How I migrated hundreds of sites from DirectAdmin to ISPConfig
Some time ago I faced a serious challenge: migrating a large number of similar websites from DirectAdmin to ISPConfig with maximum automation. The hosting platform was changed, and doing everything manually simply wasn’t an option.
To solve this, I wrote a better CLI wrapper for ISPConfig that focuses on usability while reusing the default API functions underneath: ispconfig-cli
Below is the exact workflow I used for a fast and repeatable migration.
1. Prepare migration configuration
First, define all domains and databases you want to migrate. The idea is to create everything on the ISPConfig side first, then sync files and databases afterward.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/config.json
2. Run the bootstrap script
This script creates everything required on the ISPConfig side (domains, users, databases, etc.). It’s safe to run multiple times — it will just add missing resources if something wasn’t created before.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/bootstrap.php
3. Sync files and databases
Finally, run the Bash script to rsync site files, fix ownership and permissions, dump/restore databases, and rewrite application configs with the new environment values.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/sync-db-and-files.sh
This solution isn’t for everyone, but if you’re facing a one-time mass migration, it can save a huge amount of time — and your sanity.
To solve this, I wrote a better CLI wrapper for ISPConfig that focuses on usability while reusing the default API functions underneath: ispconfig-cli
Below is the exact workflow I used for a fast and repeatable migration.
1. Prepare migration configuration
First, define all domains and databases you want to migrate. The idea is to create everything on the ISPConfig side first, then sync files and databases afterward.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/config.json
[
{
"website_from": "test1.mydomain.com",
"website_name": "my2domain.com",
"mysql_base": "my2domaincom",
"mysql_user": "my2domaincomUSER",
"mysql_pass": "my2domaincomPASS"
}
]
2. Run the bootstrap script
This script creates everything required on the ISPConfig side (domains, users, databases, etc.). It’s safe to run multiple times — it will just add missing resources if something wasn’t created before.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/bootstrap.php
$result = json_decode(addWebDomain(array(
'domain' => $website_name,
'client_id' => $client_id,
'directive_snippets_id' => 1,
)), true);
...
$result = json_decode(addDatabaseUser(array(
'database_user' => $db_user,
'database_password' => $item['mysql_pass'],
'client_id' => $client_id,
'server_id' => $server_id,
)), true);
...
$result = json_decode(addDatabase(array(
'database_name' => $db_name,
'database_user_id' => $item['database_user_id'],
'parent_domain_id' => $item['website_id'],
'client_id' => $client_id,
'server_id' => $server_id,
)), true);
3. Sync files and databases
Finally, run the Bash script to rsync site files, fix ownership and permissions, dump/restore databases, and rewrite application configs with the new environment values.
https://github.com/alan-lt/ispconfig-cli/blob/main/migration/sync-db-and-files.sh
time rsync -avh --no-perms --delete --partial --info=progress2 --info=name0 \
"$SSH_USER@$SSH_HOST:/home/*/domains/$SITE_DOMAIN_WEBROOT_FROM/public_html/" \
"$SITE_DOMAIN_WEBROOT/web/"
...
chown -R "$SITE_DOMAIN_USER:$SITE_DOMAIN_GROUP" "$SITE_DOMAIN_WEBROOT/web"
...
time mysqldump -h"$MYSQL_HOST" -u"$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_SRC_BASE" \
| pv \
| mysql -h"$MYSQL_DST_HOST" -u"$MYSQL_DST_USER" -p"$MYSQL_DST_PASS" "$MYSQL_DST_BASE"
...
time sed -i "
s|\(define('DOMAIN_NAME',[[:space:]]*'\)[^']*\(');\)|\1https://$DOMAIN/\2|
s|\(define('DIR_ROOT',[[:space:]]*'\)[^']*\(');\)|\1/var/www/$DOMAIN/web/\2|
s|\(define('DIR_SYS_ROOT',[[:space:]]*'\)[^']*\(');\)|\1/usr/share/php/tvs/v5/\2|
s|\(define('DB_HOSTNAME',[[:space:]]*'\)[^']*\(');\)|\1$MYSQL_DST_HOST\2|
s|\(define('DB_USERNAME',[[:space:]]*'\)[^']*\(');\)|\1$MYSQL_DST_USER\2|
s|\(define('DB_PASSWORD',[[:space:]]*'\)[^']*\(');\)|\1$MYSQL_DST_PASS\2|
s|\(define('DB_DATABASE',[[:space:]]*'\)[^']*\(');\)|\1$MYSQL_DST_BASE\2|
" "$SITE_DOMAIN_WEBROOT/web/config.php" "$SITE_DOMAIN_WEBROOT/web/admin/config.php"
This solution isn’t for everyone, but if you’re facing a one-time mass migration, it can save a huge amount of time — and your sanity.
Comments
Post a Comment