Hey there! If you’ve ever managed two CyberPanel servers running OpenLiteSpeed, you know how challenging it can be to keep them in sync manually. I was in the same boat until I decided to automate the process using a Bash script. In this guide, I’ll walk you through how I automated the synchronization between my servers using SSH, MySQL, rsync, and Pushover notifications. Let’s dive right in!

Table of Contents

Why Automate CyberPanel Server Sync?

Managing multiple servers manually isn’t just time-consuming; it’s also prone to errors. By automating the sync process, you can:

  • Save time by eliminating repetitive tasks.
  • Reduce errors caused by manual operations.
  • Ensure consistency across all your servers.
  • Focus on more important aspects of server management.

Essential Tools for CyberPanel Automation

Before we get started, make sure you have:

  • SSH access to both servers.
  • MySQL credentials for database operations.
  • A Pushover account for notifications.
  • Basic knowledge of Bash scripting.
💡
Remember to back up your data before running any scripts that modify your servers.

Step-by-Step Guide to Automate CyberPanel Server Sync

developer working code
A developer is working with Bash scripts | Source: freepik.com

Step 1: Define Essential Variables

First, we’ll define all the essential variables in our script. This includes SSH details, Pushover tokens, MySQL credentials, and the log file location.

# Define variables
REMOTE_USER=root
REMOTE_SERVER=<your-server-ip>
SSH_PORT=<your-ssh-port>
PUSHOVER_USER=<your-pushover-user-key>
PUSHOVER_TOKEN=<your-pushover-token>
LOG_FILE="/var/log/sync.log"
DB_USER="<your-db-user>"
DB_PASSWORD="<your-db-password>"
MYSQL_ROOT_PASSWORD="<your-mysql-root-password>"
DUMP_FILE="/tmp/alldbs.sql"
💪
Replace placeholders like <your-server-ip> with your actual server details.

Step 2: Set Up Pushover Notifications

I use Pushover to get real-time notifications on my phone whenever the script runs into an issue.

# Function to send notification using Pushover
send_notification() {
	local message=$1
	curl -s \
		--form-string "token=$PUSHOVER_TOKEN" \
		--form-string "user=$PUSHOVER_USER" \
		--form-string "message=$message" \
		https://api.pushover.net/1/messages.json
}

Why Use Pushover?

Pushover provides instant notifications, so you can quickly address any issues that arise during synchronization.

Step 3: Write Logs to a File

Logging is essential to track what happens during script execution, especially when it’s running as a cron job.

# Function to write to log
log() {
	local message=$1
	echo "$(date +'%Y-%m-%d %H:%M:%S') - $message" >> $LOG_FILE
}

Step 4: Check SSH Connection

Before initiating the sync process, the script checks the SSH connection to the remote server.

# Check SSH connection
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "exit" || {
	send_notification "SSH connection failed"
	log "SSH connection failed"
	exit 1
}

# Send notification that syncing has started
send_notification "Syncing started."
log "Syncing started."
If the SSH connection fails, the script exits to prevent any further actions.

Step 5: Transfer User and Group Information

This ensures that user IDs and group IDs are consistent across both servers.

# Dump user and group information on the source server
getent passwd > /tmp/passwd_dump
getent group > /tmp/group_dump

# Transfer user and group information to the destination server
scp -P $SSH_PORT /tmp/passwd_dump /tmp/group_dump $REMOTE_USER@$REMOTE_SERVER:/tmp/ || {
	send_notification "Transfer of user/group information failed"
	log "Transfer of user/group information failed"
	exit 1
}

Synchronizing CyberPanel Databases and Directories

Step 6: Sync Users, Groups, MySQL User, and Install WP-CLI

On the remote server, the script creates any missing users and groups, sets up MySQL user permissions, and installs WP-CLI if it’s not already installed.

# Create missing users and groups on the destination server, check and setup MySQL user, and check and install wp-cli
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "
	while IFS=: read -r username x uid gid x x x; do
		id -u \$username &>/dev/null || (groupadd -g \$gid \$username; useradd -u \$uid -g \$gid \$username)
	done < /tmp/passwd_dump
	while IFS=: read -r groupname x gid x; do
		getent group \$groupname &>/dev/null || groupadd -g \$gid \$groupname
	done < /tmp/group_dump
	rm /tmp/passwd_dump /tmp/group_dump
	
	# Check and setup MySQL user
	mysql -uroot -p$MYSQL_ROOT_PASSWORD -e \"SELECT 1 FROM mysql.user WHERE user = '$DB_USER'\" | grep -q 1 || {
		mysql -uroot -p$MYSQL_ROOT_PASSWORD -e \"
			CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
			GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost';
			FLUSH PRIVILEGES;
		\"
	}
	
	# Check and install wp-cli
	command -v wp &>/dev/null || {
		curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
		chmod +x wp-cli.phar
		mv wp-cli.phar /usr/local/bin/wp
	}
" || {
	send_notification "User/group creation or MySQL user setup or wp-cli installation failed"
	log "User/group creation or MySQL user setup or wp-cli installation failed"
	exit 1
}

Step 7: Database Backup and Transfer

Back up all databases on the source server and import them on the remote server.

# Dump all local databases
mysqldump -u$DB_USER -p$DB_PASSWORD --all-databases > $DUMP_FILE || {
	send_notification "MySQL dump failed"
	log "MySQL dump failed"
	exit 1
}

# Transfer the dump file to the remote server
scp -P $SSH_PORT $DUMP_FILE $REMOTE_USER@$REMOTE_SERVER:$DUMP_FILE || {
	send_notification "Transfer of dump file failed"
	log "Transfer of dump file failed"
	exit 1
}

# Import the dump file on the remote server
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "mysql -u$DB_USER -p$DB_PASSWORD < $DUMP_FILE" || {
	send_notification "MySQL import failed"
	log "MySQL import failed"
	exit 1
}
✔️
Database synchronization completed successfully!

Step 8: Directory Synchronization Using rsync

Use rsync to mirror specific directories from the source to the destination server.

# Sync specified directories using rsync
for dir in /usr/local/lsws/ /home/ /etc/cyberpanel/ /etc/letsencrypt/ /etc/pure-ftpd/ /etc/firewalld/ /usr/local/lscp/ /usr/local/CyberCP/ /usr/local/CyberPanel/; do
	rsync -avP --delete -e "ssh -p $SSH_PORT" $dir $REMOTE_USER@$REMOTE_SERVER:$dir || {
		send_notification "Rsync failed for directory $dir"
		log "Rsync failed for directory $dir"
		exit 1
	}
done
💪
This step ensures that both servers have identical configurations.

Finalizing the CyberPanel Sync Process

Step 9: Flush LiteSpeed Cache on the Remote Server

Clear the LiteSpeed cache for each WordPress installation on the destination server.

# Flush LiteSpeed Cache on the remote server for all WordPress installations
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "
	find /home/ -type f -name wp-config.php | while read wp_config; do
		wp_path=\$(dirname \"\$wp_config\")
		wp --allow-root --path=\"\$wp_path\" litespeed-purge all || {
			echo \"Error: Unable to purge LiteSpeed Cache for \$wp_path\"
		}
	done
" || {
	send_notification "LiteSpeed Cache flush failed"
	log "LiteSpeed Cache flush failed"
	exit 1
}

Step 10: Clean Up and Reboot

Finally, remove the database dump from both servers and reboot the remote server.

# Remove the dump file from both local and remote servers
rm $DUMP_FILE
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "rm $DUMP_FILE"

# Reboot the remote server
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "reboot" || true

# Send notification that syncing has completed successfully
send_notification "Synchronization completed successfully. Remote server is rebooting."
log "Synchronization completed successfully. Remote server is rebooting."
💡
The remote server is rebooted to apply all changes effectively.

Full Script for Easy Setup

Here's the complete script for you to set up your automated synchronization. Remember to replace all placeholders with your actual server details.

#!/bin/bash
# Define variables
REMOTE_USER=root
REMOTE_SERVER=<your-server-ip>
SSH_PORT=<your-ssh-port>
PUSHOVER_USER=<your-pushover-user-key>
PUSHOVER_TOKEN=<your-pushover-token>
LOG_FILE="/var/log/sync.log"
DB_USER="<your-db-user>"
DB_PASSWORD="<your-db-password>"
MYSQL_ROOT_PASSWORD="<your-mysql-root-password>"
DUMP_FILE="/tmp/alldbs.sql"

# Function to send notification using Pushover
send_notification() {
	local message=$1
	curl -s \
		--form-string "token=$PUSHOVER_TOKEN" \
		--form-string "user=$PUSHOVER_USER" \
		--form-string "message=$message" \
		https://api.pushover.net/1/messages.json
}

# Function to write to log
log() {
	local message=$1
	echo "$(date +'%Y-%m-%d %H:%M:%S') - $message" >> $LOG_FILE
}

# Check SSH connection
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "exit" || {
	send_notification "SSH connection failed"
	log "SSH connection failed"
	exit 1
}

# Send notification that syncing has started
send_notification "Syncing started."
log "Syncing started."

# Dump user and group information on the source server
getent passwd > /tmp/passwd_dump
getent group > /tmp/group_dump

# Transfer user and group information to the destination server
scp -P $SSH_PORT /tmp/passwd_dump /tmp/group_dump $REMOTE_USER@$REMOTE_SERVER:/tmp/ || {
	send_notification "Transfer of user/group information failed"
	log "Transfer of user/group information failed"
	exit 1
}

# Create missing users and groups on the destination server, check and setup MySQL user, and check and install wp-cli
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "
	while IFS=: read -r username x uid gid x x x; do
		id -u \$username &>/dev/null || (groupadd -g \$gid \$username; useradd -u \$uid -g \$gid \$username)
	done < /tmp/passwd_dump
	while IFS=: read -r groupname x gid x; do
		getent group \$groupname &>/dev/null || groupadd -g \$gid \$groupname
	done < /tmp/group_dump
	rm /tmp/passwd_dump /tmp/group_dump
	
	# Check and setup MySQL user
	mysql -uroot -p$MYSQL_ROOT_PASSWORD -e \"SELECT 1 FROM mysql.user WHERE user = '$DB_USER'\" | grep -q 1 || {
		mysql -uroot -p$MYSQL_ROOT_PASSWORD -e \"
			CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
			GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost';
			FLUSH PRIVILEGES;
		\"
	}
	
	# Check and install wp-cli
	command -v wp &>/dev/null || {
		curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
		chmod +x wp-cli.phar
		mv wp-cli.phar /usr/local/bin/wp
	}
" || {
	send_notification "User/group creation or MySQL user setup or wp-cli installation failed"
	log "User/group creation or MySQL user setup or wp-cli installation failed"
	exit 1
}

# Dump all local databases
mysqldump -u$DB_USER -p$DB_PASSWORD --all-databases > $DUMP_FILE || {
	send_notification "MySQL dump failed"
	log "MySQL dump failed"
	exit 1
}

# Transfer the dump file to the remote server
scp -P $SSH_PORT $DUMP_FILE $REMOTE_USER@$REMOTE_SERVER:$DUMP_FILE || {
	send_notification "Transfer of dump file failed"
	log "Transfer of dump file failed"
	exit 1
}

# Import the dump file on the remote server
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "mysql -u$DB_USER -p$DB_PASSWORD < $DUMP_FILE" || {
	send_notification "MySQL import failed"
	log "MySQL import failed"
	exit 1
}

# Sync specified directories using rsync
for dir in /usr/local/lsws/ /home/ /etc/cyberpanel/ /etc/letsencrypt/ /etc/pure-ftpd/ /etc/firewalld/ /usr/local/lscp/ /usr/local/CyberCP/ /usr/local/CyberPanel/; do
	rsync -avP --delete -e "ssh -p $SSH_PORT" $dir $REMOTE_USER@$REMOTE_SERVER:$dir || {
		send_notification "Rsync failed for directory $dir"
		log "Rsync failed for directory $dir"
		exit 1
	}
done

# Flush LiteSpeed Cache on the remote server for all WordPress installations
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "
	find /home/ -type f -name wp-config.php | while read wp_config; do
		wp_path=\$(dirname \"\$wp_config\")
		wp --allow-root --path=\"\$wp_path\" litespeed-purge all || {
			echo \"Error: Unable to purge LiteSpeed Cache for \$wp_path\"
		}
	done
" || {
	send_notification "LiteSpeed Cache flush failed"
	log "LiteSpeed Cache flush failed"
	exit 1
}

# Remove the dump file from both local and remote servers
rm $DUMP_FILE
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "rm $DUMP_FILE"

# Reboot the remote server
ssh -p $SSH_PORT $REMOTE_USER@$REMOTE_SERVER "reboot" || true

# Send notification that syncing has completed successfully
send_notification "Synchronization completed successfully. Remote server is rebooting."
log "Synchronization completed successfully. Remote server is rebooting."
✔️
You're all set! Your servers will now sync automatically.

Conclusion

Automating the synchronization between two CyberPanel servers with OpenLiteSpeed has been a game-changer for me. Not only does it save time, but it also ensures that both servers are always up-to-date without manual intervention. I hope this guide helps you streamline your server management. Happy syncing!

Categorized in:

Automation, Code, Servers, Tech, Tutorials,