| Server IP : 172.67.149.12 / Your IP : 162.159.114.31 Web Server : Apache System : Linux vm3310.eosdns.net 4.18.0-553.132.1.el8_10.x86_64 #1 SMP Thu Jun 11 14:27:43 UTC 2026 x86_64 User : carnalmedia ( 1000) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /mojo/ |
Upload File : |
#!/bin/bash
#
# Script: migration_tool
#
# Usage: migration_tool -a <action> -o <old host> [ -f <path> ]
#
# Description: Migration tool for MojoHost servers
#
# Author: Oliver Mikitiuk
#
# Changelog:
# * 12.06.2026: Oliver Mikitiuk
# - Initial write
confirmOrExit() {
while true; do
echo -n "Ready to continue? [y/n]: "
read answer
answer="${answer,,}"
case "$answer" in
y|yes)
return 0
;;
n|no)
echo "Exiting..."
exit
;;
*)
echo "Please enter 'y' or 'n'."
;;
esac
done
}
confirmOrSkip() {
while true; do
echo -n "Ready to continue? [y/n]: "
read answer
answer="${answer,,}"
case "$answer" in
y|yes)
return 0
;;
n|no)
echo "Skipping..."
return 1
;;
*)
echo "Please enter 'y' or 'n'."
;;
esac
done
}
sshExec () {
ssh \
-o BatchMode=yes \
-o PreferredAuthentications=publickey \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 \
-o LogLevel=ERROR \
"$@"
}
rsyncExec() {
rsync \
-e "ssh \
-o BatchMode=yes \
-o PreferredAuthentications=publickey \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ConnectTimeout=3 \
-o LogLevel=ERROR" \
"$@"
}
checkSSHConnection() {
if sshExec "$OLDHOSTNAME" true 2>/dev/null; then
return 0
else
echo
echo "Cannot connect to $OLDHOSTNAME via SSH."
echo
echo "To fix SSH access, try to run these commands:"
local pub_key
pub_key=$(cat /root/.ssh/id_rsa.pub)
echo "1) On $OLDHOSTNAME, add SSH public key:"
echo " echo '$pub_key' >> /root/.ssh/authorized_keys"
echo
echo "2) On $OLDHOSTNAME, whitelist IP:"
echo " For CentOS 7:"
echo " mjact_fw -a add -t migration -i $WAN_IP -p 22 -z"
echo
echo " For CentOS 8:"
echo " mjact_fw -a add -i $WAN_IP"
echo
fi
confirmOrExit
if sshExec "$OLDHOSTNAME" true 2>/dev/null; then
return 0
else
echo "[Error] Cannot connect to $OLDHOSTNAME via SSH. Please manually add the SSH access."
exit 1
fi
echo
}
createMigrationDir() {
local hostname="$1"
sshExec "$hostname" "mkdir -p '$MIGRATION_DIR'"
sshExec "$hostname" "mkdir -p '$DATABASES_DIR'"
}
prepareEnv() {
validateHostnames
checkSSHConnection
createMigrationDir "$NEWHOSTNAME"
createMigrationDir "$OLDHOSTNAME"
cd "$MIGRATION_DIR"
}
validateHostnames() {
if [[ -z "$OLDHOSTNAME" ]]; then
echo "[ERROR] Old Hostname must be provided"
exit 1
fi
if checkHostPointsHere $(hostname); then
NEWHOSTNAME=$(hostname)
else
NEWHOSTNAME="$WAN_IP"
fi
if checkHostPointsHere "$OLDHOSTNAME"; then
echo "[ERROR] Old Hostname should not pointing locally"
exit 1
fi
}
checkHostPointsHere() {
local hostname="$1"
local resolved_ip=$(getent ahostsv4 "$hostname" | head -n1 | awk '{print $1}')
local local_ips=$(ip addr show | awk '/inet / {print $2}' | cut -d/ -f1)
if [[ -z "$resolved_ip" ]]; then
echo "[ERROR] Cannot resolve IPv4 for $hostname"
exit 1
fi
if echo "$local_ips" | grep -qw "$resolved_ip"; then
return 0
else
return 1
fi
}
checkServiceActive() {
local name="$1"
local service="$2"
local hostname="$3"
if sshExec "$hostname" "systemctl is-active --quiet $service >/dev/null 2>&1 || pgrep -x $service >/dev/null 2>&1"; then
echo "${name}: Yes"
return 0
else
echo "${name}: No"
return 1
fi
}
checkActiveServices() {
local hostname="$1"
checkServiceActive "Apache" "httpd" "$hostname"
checkServiceActive "Nginx" "nginx" "$hostname"
checkServiceActive "Redis" "redis" "$hostname"
checkServiceActive "Docker" "docker" "$hostname"
}
checkApacheModules() {
local hostname="$1"
local apache_modules_list
local apache_modules=(
prxp_module
psso_module
)
if checkServiceActive "Apache" "httpd" "$hostname" >/dev/null 2>&1; then
apache_modules_list=$(sshExec "$hostname" "httpd -M 2>/dev/null || apachectl -M 2>/dev/null")
echo "Apache modules:"
for module in "${apache_modules[@]}"; do
if echo "$apache_modules_list" | grep -qw "$module"; then
echo " $module: Yes"
else
echo " $module: No"
fi
done
fi
}
checkNginxModules() {
local hostname="$1"
local nginx_modules_list
local nginx_modules=(
realip
geoip2
)
if checkServiceActive "Nginx" "nginx" "$hostname" >/dev/null 2>&1; then
nginx_modules_list=$(sshExec "$hostname" "nginx -V 2>&1")
echo "Nginx modules:"
for module in "${nginx_modules[@]}"; do
if echo "$nginx_modules_list" | grep -q "$module"; then
echo " $module: Yes"
else
echo " $module: No"
fi
done
fi
}
checkFileExist() {
local name="$1"
local file="$2"
local hostname="$3"
if [[ "$locate_exist" == "true" ]]; then
if sshExec "$hostname" "locate -b \\${file} | grep -q '.'"; then
echo "${name}: Yes"
return 0
else
echo "${name}: No"
return 1
fi
else
if sshExec "$hostname" "find /home/httpd/html /home -maxdepth 6 -type f -name $file 2>/dev/null | grep -q '.'"; then
echo "${name}: Yes"
return 0
else
echo "${name}: No"
return 1
fi
fi
}
checkInstalledApplications() {
local hostname="$1"
if sshExec "$hostname" "command -v locate >/dev/null 2>&1"; then
local locate_exist="true"
sshExec "$hostname" "updatedb"
else
local locate_exist="false"
fi
echo "Applications:"
checkFileExist " WordPress" "wp-config.php" "$hostname"
checkFileExist " Nats" "nats.txt" "$hostname"
checkFileExist " ElevatedX" "cmsinclude.ini.php" "$hostname"
checkFileExist " KVS" "setup_db.php" "$hostname"
checkFileExist " Mechbunny" "functions.mb.php" "$hostname"
}
checkPHPVersions() {
local hostname="$1"
sshExec "$hostname" 'bash -s' <<'EOF'
versions_list=()
while IFS= read -r bin; do
if [[ -x "$bin" ]]; then
version=$("$bin" -v 2>/dev/null | head -1 | grep -oE "[0-9]+\.[0-9]+")
[[ -n "$version" ]] && versions_list+=("$version")
fi
done < <(find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /usr/local/php* /opt -type f \( -name "php" -o -name "php[0-9]*" \) 2>/dev/null)
if [ ${#versions_list[@]} -gt 0 ]; then
printf "%s\n" "${versions_list[@]}" | sort -uV | xargs echo "PHP versions:"
else
echo "PHP versions: Unknown"
fi
EOF
}
checkPHPModulesAndSettings() {
local hostname="$1"
sshExec "$hostname" 'bash -s' <<'EOF'
php_modules=(
mbstring
"ChartDirector PHP API"
)
php_settings=(
memory_limit
post_max_size
upload_max_filesize
short_open_tag
)
declare -A seen_versions
while IFS= read -r bin; do
if [[ ! -x "$bin" ]] ; then
continue
fi
version=$("$bin" -v 2>/dev/null | head -1 | grep -oE "[0-9]+\.[0-9]+")
if [[ -z "$version" ]] ; then
continue
fi
if [[ -n "${seen_versions[$version]}" ]] ; then
continue
fi
seen_versions["$version"]=1
echo "PHP $version:"
echo " Modules:"
for module in "${php_modules[@]}"; do
if "$bin" -m 2>/dev/null | grep -iq "^$module$"; then
echo " $module: Yes"
else
echo " $module: No"
fi
done
echo " Settings:"
for setting in "${php_settings[@]}"; do
value=$("$bin" -i 2>/dev/null | grep "^$setting" | awk '{print $3}')
if [[ -z "$value" ]]; then
echo " $setting: Unknown"
else
echo " $setting: $value"
fi
done
echo
done < <(find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin /usr/local/php* /opt -type f \( -name "php" -o -name "php[0-9]*" \) 2>/dev/null)
EOF
}
checkMySQLVersion() {
local hostname="$1"
local version_output
local version
if checkServiceActive "MariaDB" "mariadb" "$hostname" >/dev/null 2>&1 || checkServiceActive "MySQL" "mysqld" "$hostname" >/dev/null 2>&1 || checkServiceActive "MySQL" "mysql" "$hostname" >/dev/null 2>&1 ; then
version_output=$(sshExec "$hostname" 'mysql -e "SELECT VERSION();" 2>/dev/null' | grep -v VERSION)
version=$(echo "$version_output" | grep -oE "[0-9]+\.[0-9]+(\.[0-9]+)?")
if echo "$version_output" | grep -qi "mariadb"; then
echo "MariaDB version: $version"
return 0
else
echo "MySQL version: $version"
return 0
fi
else
echo "MySQL: No"
return 1
fi
}
checkMySQLSettings() {
local hostname="$1"
local mysql_settings=(
read_only
innodb_strict_mode
sql_mode
)
if checkMySQLVersion "$hostname" >/dev/null 2>&1; then
echo "MySQL Settings:"
for setting in "${mysql_settings[@]}"; do
value=$(sshExec "$hostname" "mysql -NBe \"SHOW GLOBAL VARIABLES LIKE '$setting';\" 2>/dev/null" | awk '{print $2}')
if [[ -z "$value" ]]; then
value="Unknown"
fi
if [[ "$setting" == "sql_mode" ]]; then
value=$( echo "$value" | sed 's|,|\n |g')
echo " $setting: $value"
else
echo " $setting: $value"
fi
done
fi
}
checkControlPanelActive() {
local hostname="$1"
if checkServiceActive "cPanel" "cpanel" "$hostname" >/dev/null 2>&1; then
echo "Control panel (cPanel): Yes"
return 0
elif checkServiceActive "DirectAdmin" "directadmin" "$hostname" >/dev/null 2>&1; then
echo "Control panel (DirectAdmin): Yes"
return 0
elif checkServiceActive "Webmin" "webmin" "$hostname" >/dev/null 2>&1; then
echo "Control panel (Webmin): Yes"
return 0
else
echo "Control panel: No"
return 1
fi
}
checkOSName() {
local hostname="$1"
local os_name
os_name=$(sshExec "$hostname" '
if [[ -f /etc/os-release ]]; then
grep "^PRETTY_NAME=" /etc/os-release | cut -d= -f2- | tr -d "\""
elif [[ -f /etc/centos-release ]]; then
cat /etc/centos-release
elif [[ -f /etc/system-release ]]; then
cat /etc/system-release
else
uname -sr
fi
')
if [[ -z $os_name ]] ; then
echo "OS: Unknown"
else
echo "OS: $os_name"
fi
}
compareBlocks(){
pr -m -t -w 140 "$@"
}
compareServers() {
echo
compareBlocks <(echo "====== $NEWHOSTNAME Installation Info ======") <(echo "====== $OLDHOSTNAME Installation Info ======")
compareBlocks <(checkOSName "$NEWHOSTNAME") <(checkOSName "$OLDHOSTNAME")
compareBlocks <(checkControlPanelActive "$NEWHOSTNAME") <(checkControlPanelActive "$OLDHOSTNAME")
echo
compareBlocks <(checkActiveServices "$NEWHOSTNAME") <(checkActiveServices "$OLDHOSTNAME")
compareBlocks <(checkMySQLVersion "$NEWHOSTNAME") <(checkMySQLVersion "$OLDHOSTNAME")
compareBlocks <(checkPHPVersions "$NEWHOSTNAME") <(checkPHPVersions "$OLDHOSTNAME")
echo
compareBlocks <(checkApacheModules "$NEWHOSTNAME") <(checkApacheModules "$OLDHOSTNAME")
echo
compareBlocks <(checkMySQLSettings "$NEWHOSTNAME") <(checkMySQLSettings "$OLDHOSTNAME")
echo
compareBlocks <(checkPHPModulesAndSettings "$NEWHOSTNAME") <(checkPHPModulesAndSettings "$OLDHOSTNAME")
compareBlocks <(checkInstalledApplications "$NEWHOSTNAME") <(checkInstalledApplications "$OLDHOSTNAME")
compareBlocks <(echo "==================================================") <(echo "==================================================")
echo
}
migrateWebData() {
echo
echo "Web data migration func is currently under development"
echo
}
isDomainEnabled() {
local domain="$1"
local file="$2"
grep -Ev '^#|^$' "$file" | grep -Fxq "$domain"
}
migrateSSLCert() {
local cert_name="$1"
local le_account="$2"
rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/live/$cert_name/" "/etc/letsencrypt/live/$cert_name/" >/dev/null 2>&1 || {
echo "[WARN] Failed to copy live cert directory: $cert_name"
return 1
}
rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/archive/$cert_name/" "/etc/letsencrypt/archive/$cert_name/" >/dev/null 2>&1 || {
echo "[WARN] Failed to copy archive cert directory: $cert_name"
return 1
}
rsyncExec -a "$OLDHOSTNAME:/etc/letsencrypt/renewal/$cert_name.conf" "/etc/letsencrypt/renewal/$cert_name.conf" >/dev/null 2>&1 || {
echo "[WARN] Failed to copy renewal config: $cert_name"
return 1
}
if [[ -n "$le_account" ]]; then
sed -i "s|^account *=.*|account = $le_account|" "/etc/letsencrypt/renewal/$cert_name.conf"
fi
}
recreateApacheConfigs() {
local apache_vhost_files
local file
local block
local servername
local cert_name
local le_account
local apache_vhosts_list_file="$MIGRATION_DIR/apache_vhosts_list.txt"
declare -A vhost_map
if ! checkServiceActive "Apache" "httpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
echo "[INFO] Apache is not active on $OLDHOSTNAME, skipping"
return 0
fi
if ! checkServiceActive "Apache" "httpd" "$NEWHOSTNAME" >/dev/null 2>&1; then
echo "[INFO] Apache is not active on $NEWHOSTNAME, skipping"
return 0
fi
apache_vhost_files=$(sshExec "$OLDHOSTNAME" "httpd -S 2>/dev/null" | awk '/\(/ {print $NF}' | tr -d '(' | cut -d: -f1 | sort -u)
le_account=$(awk -F' *= *' '$1=="account" {print $2; exit}' "/etc/letsencrypt/renewal/${NEWHOSTNAME}.conf")
for file in $apache_vhost_files; do
while IFS= read -r line; do
if [[ "$line" =~ \<VirtualHost ]]; then
block=""
servername=""
fi
block+="$line"$'\n'
if [[ "$line" =~ ServerName ]]; then
servername=$(echo "$line" | awk '{print $2}' | tr -d '"')
servername="${servername#www.}"
fi
if [[ "$line" =~ \<\/VirtualHost\> ]]; then
if [[ -z "$servername" ]]; then
servername="unknown"
fi
vhost_map["$servername"]+="$block"$'\n'
block=""
servername=""
fi
done < <(sshExec "$OLDHOSTNAME" "cat $file 2>/dev/null")
done
if [[ ! -f "$apache_vhosts_list_file" ]]; then
echo "# List of Apache vhosts to migrate. Edit it to exclude vhosts if needed." > "$apache_vhosts_list_file"
for servername in "${!vhost_map[@]}"; do
if [[ "$servername" == "$OLDHOSTNAME" ]]; then
continue
fi
echo "$servername"
done | sort -u >> "$apache_vhosts_list_file"
fi
echo "[INFO] Apache vhosts list saved to $apache_vhosts_list_file . Edit it to exclude vhosts if needed."
confirmOrExit
for servername in "${!vhost_map[@]}"; do
if ! isDomainEnabled "$servername" "$apache_vhosts_list_file"; then
continue
fi
local target_file="/etc/httpd/sites-available/${servername}.conf"
if [[ -f "$target_file" ]]; then
echo "[INFO] Config already exists, skipping: $servername"
continue
fi
echo "${vhost_map[$servername]}" | \
sed "s|/home/httpd/logs/|/var/log/httpd/domlog/|g" | \
sed "s|<VirtualHost .*:80>|<VirtualHost $WAN_IP:80>|g" | \
sed "s|<VirtualHost .*:443>|<VirtualHost $WAN_IP:443>|g" \
> "$target_file"
ln -sf "$target_file" "/etc/httpd/sites-enabled/${servername}.conf"
echo "[OK] Config created: $servername"
cert_name=$(echo "${vhost_map[$servername]}" | grep -v "#" | awk '/SSLCertificateFile/ {print $2}' | awk -F'/' '{print $(NF-1)}' | head -n1 )
if [[ -n "$cert_name" ]]; then
migrateSSLCert "$cert_name" "$le_account"
fi
done
}
recreateNginxConfigs() {
local nginx_config
local nginx_vhosts_list_file="$MIGRATION_DIR/nginx_vhosts_list.txt"
local line
local block
local servername
local cert_name
local le_account
local in_server=0
local depth=0
declare -A vhost_map
if ! checkServiceActive "Nginx" "nginx" "$OLDHOSTNAME" >/dev/null 2>&1; then
echo "[INFO] Nginx is not active on $OLDHOSTNAME, skipping"
return 0
fi
if ! checkServiceActive "Nginx" "nginx" "$NEWHOSTNAME" >/dev/null 2>&1; then
echo "[INFO] Nginx is not active on $NEWHOSTNAME, skipping"
return 0
fi
le_account=$(awk -F' *= *' '$1=="account" {print $2; exit}' "/etc/letsencrypt/renewal/${NEWHOSTNAME}.conf")
nginx_config=$(sshExec "$OLDHOSTNAME" "nginx -T 2>/dev/null")
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*# ]]; then
continue
fi
if [[ $in_server -eq 0 && "$line" =~ ^[[:space:]]*server[[:space:]]*\{ ]]; then
in_server=1
depth=1
block="$line"$'\n'
servername=""
continue
fi
if [[ $in_server -eq 0 ]]; then
continue
fi
block+="$line"$'\n'
if [[ "$line" =~ ^[[:space:]]*server_name[[:space:]] ]]; then
servername=$(echo "$line" | awk '{print $2}' | sed 's/;$//')
servername="${servername#www.}"
fi
opens=$(grep -o '{' <<< "$line" | wc -l)
closes=$(grep -o '}' <<< "$line" | wc -l)
((depth += opens))
((depth -= closes))
if [[ $depth -eq 0 ]]; then
if [[ -n "$servername" ]]; then
vhost_map["$servername"]+="$block"$'\n'
fi
in_server=0
block=""
servername=""
fi
done <<< "$nginx_config"
if [[ ! -f "$nginx_vhosts_list_file" ]]; then
echo "# List of Nginx vhosts to migrate. Edit it to exclude vhosts if needed." > "$nginx_vhosts_list_file"
for servername in "${!vhost_map[@]}"; do
if [[ -z "$servername" || "$servername" == "_" || "$servername" == "localhost" || "$servername" == "$OLDHOSTNAME" ]]; then
continue
fi
echo "$servername"
done | sort -u >> "$nginx_vhosts_list_file"
fi
echo "[INFO] Nginx vhosts list saved to $nginx_vhosts_list_file . Edit it to exclude vhosts if needed."
confirmOrExit
for servername in "${!vhost_map[@]}"; do
if ! isDomainEnabled "$servername" "$nginx_vhosts_list_file"; then
continue
fi
local target_file="/etc/nginx/sites-available/${servername}.conf"
if [[ -f "$target_file" ]]; then
echo "[INFO] Config already exists, skipping: $servername"
continue
fi
echo "${vhost_map[$servername]}" | \
sed "s|listen .*:80|listen $WAN_IP:80|g" | \
sed "s|listen .*:443|listen $WAN_IP:443|g" \
> "$target_file"
ln -sf "$target_file" "/etc/nginx/sites-enabled/${servername}.conf"
echo "[OK] Config created: $servername"
cert_name=$(echo "${vhost_map[$servername]}" | grep -v "#" | awk '/ssl_certificate/ {print $2}' | awk -F'/' '{print $(NF-1)}' | head -n1 )
if [[ -n "$cert_name" ]]; then
migrateSSLCert "$cert_name" "$le_account"
fi
done
}
recreateWebConfigs() {
recreateApacheConfigs
recreateNginxConfigs
}
migrateDatabases() {
if ! checkMySQLVersion "$OLDHOSTNAME" >/dev/null 2>&1 ; then
echo "[WARN] MySQL is not active on the $OLDHOSTNAME"
return 1
elif ! checkMySQLVersion "$NEWHOSTNAME" >/dev/null 2>&1 ; then
echo "[WARN] MySQL is not active on the $NEWHOSTNAME"
return 1
fi
local databases_file="$DATABASES_DIR/databases.txt"
local db_migration_log="$DATABASES_DIR/database_migration.log"
local local_dump_file="$DATABASES_DIR/$(hostname)_dump.sql"
local failed_db_move
if [[ ! -f "$local_dump_file" ]]; then
echo "[INFO] Creating full local dump file: $local_dump_file"
mysqldump --all-databases > "$local_dump_file" 2>/dev/null
fi
if [[ ! -f "$databases_file" ]]; then
echo "# List of databases to migrate. Edit this file to exclude any databases." > "$databases_file"
sshExec "$OLDHOSTNAME" 'mysql -N -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "^(mysql|information_schema|performance_schema|postfix|roundcube|sys$|mojotest)"' >> "$databases_file"
fi
echo "[INFO] Please review the databases that will be migrated:"
echo "======= Databases ======="
cat "$databases_file" | grep -Ev "#"
echo "========================="
echo "[INFO] Database list saved to $databases_file . Edit it to exclude databases if needed."
confirmOrExit
echo
echo "[INFO] Migrating databases..."
while IFS= read -r database; do
if [[ -z "$database" || "$database" =~ ^# ]]; then
continue
fi
if sshExec -n "$OLDHOSTNAME" "mysqldump --databases '$database' > '$DATABASES_DIR/${database}_dump.sql'" >/dev/null 2> >(grep -v "Deprecated" >> "$db_migration_log") &&
rsyncExec -a "$OLDHOSTNAME":"$DATABASES_DIR"/${database}_dump.sql "$DATABASES_DIR"/${database}_dump.sql >/dev/null 2>>"$db_migration_log" &&
mysql < "$DATABASES_DIR"/${database}_dump.sql >/dev/null 2> >(grep -v "Deprecated" >> "$db_migration_log") ; then
echo "[OK] $database"
else
echo "[ERROR] $database"
failed_db_move="true"
fi
done < "$databases_file"
echo
if [[ "$failed_db_move" == "true" ]]; then
echo "[ERROR] Some databases failed to migrate, please check the log file: $db_migration_log"
else
echo "[OK] Databases have been migrated"
fi
echo
}
recreateMySQLUsers() {
if ! checkMySQLVersion "$OLDHOSTNAME" >/dev/null 2>&1 ; then
echo "[WARN] MySQL is not active on the $OLDHOSTNAME"
return 1
elif ! checkMySQLVersion "$NEWHOSTNAME" >/dev/null 2>&1 ; then
echo "[WARN] MySQL is not active on the $NEWHOSTNAME"
return 1
fi
local users_file="$DATABASES_DIR/mysql_users.txt"
local grants_file="$DATABASES_DIR/mysql_grants.sql"
local bad_hash_users_file="$DATABASES_DIR/mysql_bad_hash_users.txt"
local backup_file="$DATABASES_DIR/mysql_system_db_backup.sql"
local mysql_password_column
local bad_hash_count
local has_password_column=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e \"SHOW COLUMNS FROM mysql.user LIKE 'Password';\" 2>/dev/null")
local mysql_users_exclude="(
'PUBLIC',
'debian-sys-maint',
'root',
'mysql',
'mysql.sys',
'mysql.session',
'mariadb',
'mariadb.sys',
'postfix',
'roundcube',
'netdata',
'mojotest',
'repl',
''
)"
if [[ -n "$has_password_column" ]]; then
mysql_password_column="password"
else
mysql_password_column="authentication_string"
fi
if [[ ! -f "$bad_hash_users_file" ]]; then
sshExec "$OLDHOSTNAME" "
mysql -B -N -e \"
SELECT CONCAT('\'', user,'\'@\'', host, '\'')
FROM mysql.user
WHERE user NOT IN $mysql_users_exclude
AND LENGTH($mysql_password_column) != 41
\" 2>/dev/null
" >> "$bad_hash_users_file"
fi
if [[ ! -f "$backup_file" ]]; then
echo "[INFO] Creating local mysql database backup: $backup_file"
mysqldump mysql > "$backup_file" 2>/dev/null
fi
if [[ ! -f "$users_file" ]]; then
#echo "[INFO] MySQL users file not found, creating: $users_file"
echo "# List of MySQL users to recreate. Edit this file to exclude any MySQL users." > "$users_file"
sshExec "$OLDHOSTNAME" "
mysql -B -N -e \"
SELECT CONCAT('\'', user,'\'@\'', host, '\'')
FROM mysql.user
WHERE user NOT IN $mysql_users_exclude
AND LENGTH($mysql_password_column) = 41
\" 2>/dev/null
" >> "$users_file"
fi
echo "[INFO] Please review the MySQL users that will be recreated:"
echo
echo "======= MySQL users ======="
cat "$users_file" | grep -Ev "#"
echo "==========================="
echo
echo "[INFO] MySQL users list saved to $users_file . Edit it to exclude users if needed."
if [[ -s "$bad_hash_users_file" ]]; then
echo "[WARN] Some MySQL users have invalid password hashes and will NOT be migrated. List saved to $bad_hash_users_file"
fi
confirmOrExit
if [[ ! -f "$grants_file" ]]; then
if [[ -z "$has_password_column" ]]; then
sshExec "$OLDHOSTNAME" "
mysql -B -N -e \"
SELECT user,host,authentication_string
FROM mysql.user
WHERE user NOT IN $mysql_users_exclude
AND length(authentication_string) = 41
\" 2>/dev/null" | awk '{print "GRANT USAGE ON *.* TO '\`'" $1 "'\`'@'\`'" $2 "'\`' IDENTIFIED BY PASSWORD '\''" $3 "'\''"}' >> "$grants_file"
fi
while IFS= read -r line; do
if [[ -z "$line" || "$line" =~ ^# ]]; then
continue
fi
sshExec -n "$OLDHOSTNAME" "mysql -B -N -uroot -e 'SHOW GRANTS FOR $line;'"
done < "$users_file" >> "$grants_file" 2>/dev/null
sed -i 's/$/;/' "$grants_file"
fi
echo
echo "[INFO] MySQL users grants saved to $grants_file . It will be imported on the next step. Edit it if needed."
confirmOrExit
echo
if mysql < "$grants_file" >/dev/null 2>&1 ; then
echo "[OK] MySQL users have been recreated"
else
echo "[ERROR] Failed to recreate MySQL users"
fi
}
createMailUsersFile() {
local users_file="$1"
echo "[INFO] Mail users file not found, creating template: $users_file"
cat > "$users_file" <<EOF
# Format: [email protected] olduser oldpassword [newpassword]
# If newpassword is not provided, oldpassword will be used
#
# Example: [email protected] olduser_domcom password
# Example: [email protected] olduser_domcom old_password new_password
#
EOF
}
migrateMails() {
local users_file="$MIGRATION_DIR/mail_users.txt"
local failed_mails_move
if ! command -v imapsync >/dev/null 2>&1; then
echo "[INFO] Installing imapsync..."
if yum install -y imapsync >/dev/null 2>&1; then
echo "[OK] imapsync installed"
else
echo "[ERROR] Failed to install imapsync"
return 1
fi
fi
if [[ ! -f "$users_file" ]]; then
createMailUsersFile "$users_file"
return 0
fi
while read -r newuser olduser oldpass newpass; do
if [[ -z "$newuser" || "$newuser" =~ ^# ]]; then
continue
elif [[ -z "$olduser" || -z "$oldpass" ]]; then
echo "[WARN] Skipping invalid line: NewUser: $newuser OldUser: $olduser Password:$oldpass"
continue
fi
if [[ -z "$newpass" ]]; then
newpass="$oldpass"
fi
if imapsync --host1 "$OLDHOSTNAME" --user1 "$olduser" --password1 "$oldpass" --host2 "$NEWHOSTNAME" --user2 "$newuser" --password2 "$newpass" --automap --skipcrossduplicates --maxsleep 0 >/dev/null 2>&1; then
echo "[OK] $olduser -> $newuser"
else
echo "[ERROR] $olduser -> $newuser"
failed_mails_move="true"
fi
done < "$users_file"
echo
if [[ "$failed_mails_move" == "true" ]]; then
echo "[ERROR] Some mails failed to migrate, please check the log files: $MIGRATION_DIR/LOG_imapsync/"
else
echo "[OK] Mails have been migrated"
fi
echo
}
recreateMailboxes() {
local domains
local aliases
local newserver_postfixadmin_cli
local oldserver_postfixadmin_cli
local oldserver_mjact_mail
local users_file="$MIGRATION_DIR/mail_users.txt"
local mailboxes_list_file="$MIGRATION_DIR/mailboxes_list.txt"
if ! checkServiceActive "Postfix" "postfix" "$NEWHOSTNAME" >/dev/null 2>&1; then
echo "[ERROR] Postfix is NOT active on $NEWHOSTNAME, please recreate mailboxes manually"
return 1
fi
if [[ ! -f "$users_file" ]]; then
createMailUsersFile "$users_file"
fi
if ! grep -qxF "# Automatically generated by Recreate Mailboxes" "$users_file"; then
echo >> "$users_file"
echo "# Automatically generated by Recreate Mailboxes" >> "$users_file"
fi
if test -x /usr/share/postfixadmin/scripts/postfixadmin-cli >/dev/null 2>&1; then
newserver_postfixadmin_cli="/usr/share/postfixadmin/scripts/postfixadmin-cli"
elif command -v postfixadmin-cli >/dev/null 2>&1; then
newserver_postfixadmin_cli="postfixadmin-cli"
else
echo "[ERROR] postfixadmin-cli not found on $NEWHOSTNAME, please install it or recreate mailboxes manually"
return 1
fi
if checkServiceActive "Postfix" "postfix" "$OLDHOSTNAME" >/dev/null 2>&1; then
echo "[INFO] Recreating Domains for Postfix..."
domains=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT domain FROM postfix.domain WHERE active=1 AND domain != \"ALL\" ;'" 2>/dev/null)
if [[ -z "$domains" ]]; then
echo "[WARN] No Domains found in PostfixAdmin database on $OLDHOSTNAME"
return 1
fi
echo "$domains" | while IFS= read -r domain; do
if [[ -z "$domain" ]] ;then
continue
elif "$newserver_postfixadmin_cli" domain view "$domain" >/dev/null 2>&1; then
echo "[INFO] Domain already exists: $domain"
continue
fi
if "$newserver_postfixadmin_cli" domain add "$domain" --aliases 30 --mailboxes 30 >/dev/null 2>&1; then
echo "[OK] Domain created: $domain"
continue
else
echo "[ERROR] Failed to recreate domain: $domain"
fi
done
echo
echo "[INFO] Recreating Mail Aliases..."
aliases=$(sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT address, goto FROM postfix.alias WHERE active=1 AND address != goto;'" 2>/dev/null)
echo "$aliases" | while IFS=$'\t' read -r address goto; do
if [[ -z "$address" || -z "$goto" ]]; then
continue
elif "$newserver_postfixadmin_cli" alias view "$address" >/dev/null 2>&1; then
echo "[INFO] Alias already exists: $address -> $goto"
continue
fi
if "$newserver_postfixadmin_cli" alias add "$address" --goto "$goto" >/dev/null 2>&1; then
echo "[OK] Alias recreated: $address -> $goto"
continue
else
echo "[ERROR] Failed to recreate alias: $address -> $goto"
fi
done
echo
if sshExec "$OLDHOSTNAME" "test -x /usr/share/postfixadmin/scripts/postfixadmin-cli" >/dev/null 2>&1; then
oldserver_postfixadmin_cli="/usr/share/postfixadmin/scripts/postfixadmin-cli"
elif sshExec "$OLDHOSTNAME" "command -v postfixadmin-cli" >/dev/null 2>&1; then
oldserver_postfixadmin_cli="postfixadmin-cli"
else
echo "[ERROR] postfixadmin-cli not found on $OLDHOSTNAME, please install it or recreate mailboxes manually"
return 1
fi
if [[ ! -f "$mailboxes_list_file" ]]; then
echo "# List of mailboxes to recreate. Edit this file to exclude any mailboxes." > "$mailboxes_list_file"
sshExec "$OLDHOSTNAME" "mysql -N -B -e 'SELECT username FROM postfix.mailbox WHERE active=1;'" 2>/dev/null >> "$mailboxes_list_file"
fi
echo "[INFO] Please review the Mailboxes that will be recreated:"
echo
echo "======== Mailboxes ========"
cat "$mailboxes_list_file" | grep -Ev "#"
echo "==========================="
echo
echo "[INFO] Mailboxes list saved to $mailboxes_list_file . Edit it to exclude mailboxes if needed."
echo "[WARN] If a mailbox is missing on $NEWHOSTNAME, its password on $OLDHOSTNAME will be changed during recreation."
echo
confirmOrExit
echo
echo "[INFO] Recreating Mailboxes for Postfix..."
while IFS= read -r mailbox; do
if [[ -z "$mailbox" || "$mailbox" =~ ^# ]] ;then
continue
elif $oldserver_postfixadmin_cli mailbox view "$mailbox" >/dev/null 2>&1; then
echo "[INFO] Mailbox already exists: $mailbox"
continue
fi
while true; do
password=$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16)
if [[ $(echo "$password" | grep -o '[0-9]' | wc -l) -ge 2 ]]; then
break
fi
done
if ! sshExec -n "$OLDHOSTNAME" "$oldserver_postfixadmin_cli mailbox update '$mailbox' --password '$password' --password2 '$password' " >/dev/null 2>&1; then
echo "[ERROR] Failed to reset password on $OLDHOSTNAME: $mailbox"
continue
fi
if "$newserver_postfixadmin_cli" mailbox add "$mailbox" --password "$password" --password2 "$password" >/dev/null 2>&1; then
echo "$mailbox $mailbox $password" >> "$users_file"
echo "[OK] Mailbox recreated: $mailbox"
else
echo "[ERROR] Failed to recreate mailbox: $mailbox"
fi
done < "$mailboxes_list_file"
echo "[INFO] Mailboxes and passwords saved to $users_file for future mails migration."
return 0
elif checkServiceActive "Sendmail" "sendmail" "$OLDHOSTNAME" >/dev/null 2>&1; then
if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_mail" >/dev/null 2>&1; then
oldserver_mjact_mail="/usr/local/mojo/sbin/mjact_mail"
elif sshExec "$OLDHOSTNAME" "command -v mjact_mail" >/dev/null 2>&1; then
oldserver_mjact_mail="mjact_mail"
else
echo "[ERROR] mjact_mail not found on $OLDHOSTNAME, please recreate mailboxes manually"
return 1
fi
echo "[INFO] Recreating Domains for Postfix..."
domains=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null" | awk '!/^#/ && /@/ && !/Forward\/Alias/ && !/Account/ {print $1}' | awk -F@ '{print $2}' | sort -u)
if [[ -z "$domains" ]]; then
echo "[WARN] No Domains found in Sendmail configuration on $OLDHOSTNAME"
return 1
fi
echo "$domains" | while IFS= read -r domain; do
if [[ -z "$domain" ]] ;then
continue
elif "$newserver_postfixadmin_cli" domain view "$domain" >/dev/null 2>&1; then
echo "[INFO] Domain already exists: $domain"
continue
fi
if "$newserver_postfixadmin_cli" domain add "$domain" --aliases 30 --mailboxes 30 >/dev/null 2>&1; then
echo "[OK] Domain created: $domain"
continue
else
echo "[ERROR] Failed to recreate domain: $domain"
fi
done
echo
echo "[INFO] Recreating Mail Aliases..."
aliases=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null" | awk '!/^#/ && /@/ && $2 ~ /@/ {print $1, $2}')
echo "$aliases" | while read -r address goto; do
if [[ -z "$address" || -z "$goto" ]]; then
continue
elif "$newserver_postfixadmin_cli" alias view "$address" >/dev/null 2>&1; then
echo "[INFO] Alias already exists: $address -> $goto"
continue
fi
if "$newserver_postfixadmin_cli" alias add "$address" --goto "$goto" >/dev/null 2>&1; then
echo "[OK] Alias recreated: $address -> $goto"
else
echo "[ERROR] Failed to recreate alias: $address -> $goto"
fi
done
echo
if [[ ! -f "$mailboxes_list_file" ]]; then
echo "# List of mailboxes to recreate. Edit this file to exclude any mailboxes." > "$mailboxes_list_file"
sshExec "$OLDHOSTNAME" "$oldserver_mjact_mail -a list 2>/dev/null " | awk '/Email Addy[[:space:]]+Account/ {found=1; next} found && $1 ~ /@/ && $1 !~ /^#/ {print $1,$2}' | column -t >> "$mailboxes_list_file"
fi
echo "[INFO] Please review the Mailboxes that will be recreated:"
echo
echo "======== Mailboxes ========"
cat "$mailboxes_list_file" | grep -Ev "#" | awk '{print $1}'
echo "==========================="
echo
echo "[INFO] Mailboxes list saved to $mailboxes_list_file . Edit it to exclude mailboxes if needed."
echo "[WARN] If a mailbox is missing on $NEWHOSTNAME, its password on $OLDHOSTNAME will be changed during recreation."
echo
confirmOrExit
while IFS= read -r line; do
if [[ -z "$line" || "$line" =~ ^# ]] ; then
continue
fi
mailbox=$(echo "$line" | awk '{print $1}')
account=$(echo "$line" | awk '{print $2}')
if [[ -z "$mailbox" || -z "$account" ]] ; then
continue
fi
if "$newserver_postfixadmin_cli" mailbox view "$mailbox" >/dev/null 2>&1; then
echo "[INFO] Mailbox already exists: $mailbox"
continue
fi
while true; do
password=$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 16)
if [[ $(echo "$password" | grep -o '[0-9]' | wc -l) -ge 2 ]]; then
break
fi
done
if ! sshExec "$OLDHOSTNAME" "export PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mojo/sbin; export TERM=xterm; $oldserver_mjact_mail -a changepassword -t 000000 -n $account -e $mailbox -p" <<< $password >/dev/null 2>&1; then
echo "[ERROR] Failed to reset password on $OLDHOSTNAME: $mailbox"
continue
fi
if "$newserver_postfixadmin_cli" mailbox add "$mailbox" --password "$password" --password2 "$password" >/dev/null 2>&1; then
echo "$mailbox $account $password" >> "$users_file"
echo "[OK] Mailbox recreated: $mailbox"
else
echo "[ERROR] Failed to recreate mailbox: $mailbox"
fi
done < "$mailboxes_list_file"
echo "[INFO] Mailboxes and passwords saved to $users_file for future mails migration."
return 0
else
echo "[WARN] Unsupported mail service on $OLDHOSTNAME. Mailbox recreation is only supported for Postfix and Sendmail servers."
return 1
fi
}
recreateFTPUsers() {
local newserver_mjact_ftp
local oldserver_mjact_ftp
local ftp_users_list_file="$MIGRATION_DIR/ftp_users_list.txt"
local ftp_users_file="$MIGRATION_DIR/ftp_users.txt"
local add_output
if test -x /usr/local/mojo/bin/mjact_ftp >/dev/null 2>&1; then
newserver_mjact_ftp="/usr/local/mojo/bin/mjact_ftp"
elif command -v mjact_ftp >/dev/null 2>&1; then
newserver_mjact_ftp="mjact_ftp"
else
echo "[WARN] mjact_ftp not found on $NEWHOSTNAME, skipping FTP users recreation"
return 1
fi
if checkServiceActive "vsftpd" "vsftpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/bin/mjact_ftp" >/dev/null 2>&1; then
oldserver_mjact_ftp="/usr/local/mojo/bin/mjact_ftp"
elif sshExec "$OLDHOSTNAME" "command -v mjact_ftp" >/dev/null 2>&1; then
oldserver_mjact_ftp="mjact_ftp"
else
echo "[WARN] mjact_ftp not found on $OLDHOSTNAME, skipping FTP users recreation"
return 1
fi
if [[ ! -f "$ftp_users_list_file" ]]; then
echo "# List of FTP users to recreate. Edit this file to exclude any FTP users." > "$ftp_users_list_file"
sshExec "$OLDHOSTNAME" "$oldserver_mjact_ftp -a list 2>/dev/null" | grep -v "Local path" | awk 'NF>1 && $2 !~ /^#/ && $1 !~ /(_wp|_wp_autoftp)$/ {print $1,$3}' | column -t >> "$ftp_users_list_file"
fi
elif checkServiceActive "proftpd" "proftpd" "$OLDHOSTNAME" >/dev/null 2>&1; then
if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_ftp" >/dev/null 2>&1; then
oldserver_mjact_ftp="/usr/local/mojo/sbin/mjact_ftp"
elif sshExec "$OLDHOSTNAME" "command -v mjact_ftp" >/dev/null 2>&1; then
oldserver_mjact_ftp="mjact_ftp"
else
echo "[WARN] mjact_ftp not found on $OLDHOSTNAME, skipping FTP users recreation"
return 1
fi
if [[ ! -f "$ftp_users_list_file" ]]; then
echo "# List of FTP users to recreate. Edit this file to exclude any FTP users." > "$ftp_users_list_file"
sshExec "$OLDHOSTNAME" "$oldserver_mjact_ftp -a list 2>/dev/null" | grep -Ev "FTP Accounts|Any accounts" | awk 'NF>1 && $2 !~ /^#/ && $2 !~ /(_wp_autoftp|_wp)$/ {print $2,$3}' | column -t >> "$ftp_users_list_file"
fi
else
echo "[WARN] FTP users recreation is only supported for ProFTPD and vsftpd servers."
return 1
fi
echo "[INFO] Please review the FTP users that will be recreated:"
echo
echo "=============== FTP Users ==============="
cat "$ftp_users_list_file" | grep -Ev "^#"
echo "========================================="
echo
echo "[INFO] FTP users list saved to $ftp_users_list_file . Edit it to exclude FTP users if needed."
echo
confirmOrExit
echo
echo "[INFO] Recreating FTP Users..."
while IFS= read -r line; do
if [[ -z "$line" || "$line" =~ ^# ]] ; then
continue
fi
ftp_user=$(echo "$line" | awk '{print $1}')
ftp_path=$(echo "$line" | awk '{print $2}')
if "$newserver_mjact_ftp" -a list 2>/dev/null | awk '{print $1}' | grep -qx "$ftp_user"; then
echo "[INFO] FTP user already exists: $ftp_user"
continue
fi
if [[ ! -d "$ftp_path" ]]; then
echo "[WARN] FTP path does not exist, skipping user: $ftp_user ($ftp_path)"
continue
fi
if add_output=$($newserver_mjact_ftp -a add -n "$ftp_user" -f "$ftp_path" 2>/dev/null); then
{
echo "$add_output"
echo
} >> "$ftp_users_file"
echo "[OK] FTP user recreated: $ftp_user"
else
echo "[ERROR] Failed to recreate FTP user: $ftp_user"
fi
done < "$ftp_users_list_file"
echo
echo "[INFO] FTP users and passwords saved to $ftp_users_file"
}
recreateSSHUsers() {
local newserver_mjact_ssh
local oldserver_mjact_ssh
local ssh_users_list_file="$MIGRATION_DIR/ssh_users_list.txt"
local ssh_users_file="$MIGRATION_DIR/ssh_users.txt"
local mjact_ssh_list_output
local add_output
if test -x /usr/local/mojo/bin/mjact_ssh >/dev/null 2>&1; then
newserver_mjact_ssh="/usr/local/mojo/bin/mjact_ssh"
elif command -v mjact_ssh >/dev/null 2>&1; then
newserver_mjact_ssh="mjact_ssh"
else
echo "[WARN] mjact_ssh not found on $NEWHOSTNAME, skipping SSH users recreation"
return 1
fi
if sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/bin/mjact_ssh" >/dev/null 2>&1; then
oldserver_mjact_ssh="/usr/local/mojo/bin/mjact_ssh"
elif sshExec "$OLDHOSTNAME" "test -x /usr/local/mojo/sbin/mjact_ssh" >/dev/null 2>&1; then
oldserver_mjact_ssh="/usr/local/mojo/sbin/mjact_ssh"
elif sshExec "$OLDHOSTNAME" "command -v mjact_ssh" >/dev/null 2>&1; then
oldserver_mjact_ssh="mjact_ssh"
else
echo "[WARN] mjact_ssh not found on $OLDHOSTNAME, skipping SSH users recreation"
return 1
fi
mjact_ssh_list_output=$(sshExec "$OLDHOSTNAME" "$oldserver_mjact_ssh -a list 2>/dev/null")
if [[ ! -f "$ssh_users_list_file" ]]; then
echo "# List of SSH users to recreate. Edit this file to exclude any SSH users." > "$ssh_users_list_file"
if echo "$mjact_ssh_list_output" | grep -q "Client SSH Users"; then
echo "$mjact_ssh_list_output" | awk '/Client SSH Users/ {p=1; next}/Mojo SSH Users/ && p {exit}p && $1 !~ /^(USRNAME|-+|backuppc)/ && NF {print $1}' >> "$ssh_users_list_file"
elif echo "$mjact_ssh_list_output" | grep -q "(uid="; then
echo "$mjact_ssh_list_output" | sed 's/^ *//g' | awk -F '(' '$1 !~ /^(rocky|backuppc)$/ {print $1}' >> "$ssh_users_list_file"
else
echo "[WARN] Unknown mjact_ssh format"
return 1
fi
fi
echo "[INFO] Please review the SSH users that will be recreated:"
echo
echo "======= SSH Users ======="
cat "$ssh_users_list_file" | grep -Ev "^#"
echo "========================="
echo
echo "[INFO] SSH users list saved to $ssh_users_list_file . Edit it to exclude SSH users if needed."
echo
confirmOrExit
echo
echo "[INFO] Recreating SSH Users..."
while IFS= read -r ssh_user; do
if [[ -z "$ssh_user" || "$ssh_user" =~ ^# ]] ; then
continue
fi
if "$newserver_mjact_ssh" -a list 2>/dev/null | sed 's/^ *//g' | awk -F '(' '{print $1}' | grep -qx "$ssh_user"; then
echo "[INFO] SSH user already exists: $ssh_user"
continue
fi
if add_output=$($newserver_mjact_ssh -a add -n "$ssh_user" 2>/dev/null); then
{
echo "$add_output"
echo
} >> "$ssh_users_file"
echo "[OK] SSH user recreated: $ssh_user"
else
echo "[ERROR] Failed to recreate SSH user: $ssh_user"
fi
done < "$ssh_users_list_file"
echo
echo "[INFO] SSH users and passwords saved to $ssh_users_file"
}
createHostsFile() {
local livedomains_cmd
local output_file="$MIGRATION_DIR/hosts.txt"
if [[ ! -f "$output_file" ]]; then
if sshExec "$OLDHOSTNAME" "test -x /mojo/livedomains" >/dev/null 2>&1; then
livedomains_cmd="/mojo/livedomains"
elif sshExec "$OLDHOSTNAME" "command -v livedomains >/dev/null 2>&1" >/dev/null 2>&1; then
livedomains_cmd="livedomains"
else
echo "[ERROR] livedomains command not found, cannot create file $output_file"
return 1
fi
echo "#Live Domains:" > "$output_file"
sshExec "$OLDHOSTNAME" "$livedomains_cmd 2>&1 | grep -E 'is live here' | sed -r 's/\x1b\[[0-9;]*m//g'" | awk -v ip="$WAN_IP" '{print ip, $1, "www."$1}' | grep -v "$OLDHOSTNAME" >> "$output_file"
echo >> "$output_file"
echo "#CloudFlare Domains:" >> "$output_file"
sshExec "$OLDHOSTNAME" "$livedomains_cmd 2>&1 | grep -E 'is using CloudFlare' | sed -r 's/\x1b\[[0-9;]*m//g'" | awk -v ip="$WAN_IP" '{print ip, $1, "www."$1}' | grep -v "$OLDHOSTNAME" >> "$output_file"
echo "[OK] File $output_file has been created"
return 0
else
echo "[INFO] File $output_file already exists"
return 0
fi
echo
}
checkDomainsNameservers(){
local hosts_file="$MIGRATION_DIR/hosts.txt"
local nameservers_output_file="$MIGRATION_DIR/domains_nameservers.txt"
local domains_list
local domain
local root_domain
local nameservers
local nameservers_output
if [[ ! -f "$nameservers_output_file" ]]; then
if ! createHostsFile >/dev/null 2>&1 ; then
echo "[ERROR] Failed to create hosts file $hosts_file . Please create it manually - it is required for nameservers checks."
return 1
fi
domains_list=$(awk '!/^#/ && NF {print $2}' "$hosts_file")
nameservers_output=$(
echo "$domains_list" | while IFS= read -r domain; do
if [[ -z "$domain" || "$domain" =~ ^# ]]; then
continue
fi
root_domain=$(echo "$domain" | awk -F. '{if(NF>=2) print $(NF-1)"."$NF}')
nameservers=$(dig +short NS "$root_domain" 2>/dev/null | sort -u | sed 's|\.$||' | tr '\n' ' | ')
echo -e "$domain\t( zone: $root_domain )\t- $nameservers"
done | sort -k4,4 | column -t -s $'\t' -o ' '
)
echo "#File Format: domain ( DNS zone ) - nameservers" > "$nameservers_output_file"
echo >> "$nameservers_output_file"
echo "MojoHost Nameservers:" >> "$nameservers_output_file"
echo "$nameservers_output" | grep -E "mojohost.com|mojohost.eu|mjhst.com|eosdns.net" >> "$nameservers_output_file"
echo >> "$nameservers_output_file"
echo "CloudFlare Nameservers:" >> "$nameservers_output_file"
echo "$nameservers_output" | grep "cloudflare.com" >> "$nameservers_output_file"
echo >> "$nameservers_output_file"
echo "Others Nameservers:" >> "$nameservers_output_file"
echo "$nameservers_output" | grep -Ev "mojohost.com|mojohost.eu|mjhst.com|eosdns.net|cloudflare.com" >> "$nameservers_output_file"
echo "[OK] Nameservers list saved to $nameservers_output_file"
return 0
else
echo "[INFO] File $nameservers_output_file already exists"
return 0
fi
}
HELP() {
echo "===================================================================================================="
echo "Migration Tool"
echo
echo "Usage:"
echo " $0 -a <action> -o <old host> [ -f <path> ]"
echo "===================================================================================================="
echo "Options:"
echo " -a ACTION Action to perform"
echo " -o HOST Old Hostname"
echo " -f DIR Working directory for migration files (default: /root/migration)"
echo " -h Show help"
echo
echo "Actions:"
echo " webdata Migrate web data (In development)"
echo " db Migrate databases"
echo " mail Migrate mails"
echo " vhosts Recreate Apache and Nginx vhosts"
echo " mysqlusers Recreate MySQL users"
echo " mailboxes Recreate Mailboxes and Aliases (WARNING: Passwords will be reset on the old server)"
echo " ftpusers Recreate FTP users"
echo " sshusers Recreate SSH users"
echo " hosts Generate hosts file"
echo " checkns Generate nameservers list file"
echo " compare Compare servers"
echo "===================================================================================================="
}
if [ "$(whoami)" != 'root' ]; then
echo "[ERROR] You must execute this script as the root user!"
exit 1
fi
if [[ -z "$1" || "$1" == "-h" || "$1" == "--help" || "$1" == "help" ]]; then
HELP
exit 0
fi
while getopts ":a:o:f:" OPTION; do
case "${OPTION}" in
a) ACTION="${OPTARG}" ;;
o) OLDHOSTNAME="${OPTARG}" ;;
f) MIGRATION_DIR="${OPTARG}" ;;
\?) echo "[ERROR] Unknown option: -$OPTARG"; exit 1 ;;
:) echo "[ERROR] Option -$OPTARG requires argument"; exit 1 ;;
esac
done
if [ -z "$MIGRATION_DIR" ]; then
MIGRATION_DIR="/root/migration"
fi
DATABASES_DIR="$MIGRATION_DIR"/dbs
WAN_IP=$(curl -s https://api.ipify.org)
ACTION_LOWER="${ACTION,,}"
case "$ACTION_LOWER" in
webdata) prepareEnv; migrateWebData ;;
vhosts) prepareEnv; recreateWebConfigs ;;
db) prepareEnv; migrateDatabases ;;
mail) prepareEnv; migrateMails ;;
mysqlusers) prepareEnv; recreateMySQLUsers ;;
mailboxes) prepareEnv; recreateMailboxes ;;
ftpusers) prepareEnv; recreateFTPUsers ;;
sshusers) prepareEnv; recreateSSHUsers ;;
hosts) prepareEnv; createHostsFile ;;
checkns) prepareEnv; checkDomainsNameservers ;;
compare) prepareEnv; compareServers ;;
*) echo "[ERROR] Unknown Option: $ACTION"; exit 1 ;;
esac