How to Migrate Moodle to a New Server and Domain
Migrate Moodle to a new server and domain without losing data, breaking URLs, or missing the config, cron, and DNS dependencies that matter in cutover.
Summary: This guide walks through migrating Moodle to a new server or domain, including preserving the file layout, transferring the database and moodledata, updating Apache, cron, wwwroot, and validating the cutover.
This is the full infrastructure-side migration workflow for self-hosted Moodle or Totara. It assumes you have access to both the source and destination servers and that you are moving the application stack itself, not just changing DNS.
Step 1: Recreate the user and folder structure on the destination
Start by inspecting the source user account and, where possible, preserve the same UID on the destination. This reduces permission problems during transfer.
grep username /etc/passwd
useradd -u 1025 username
Then create the home directory structure and fix ownership before copying anything.
If the UID is already taken on the destination, create the user with a different UID and be prepared to normalize ownership after the transfer.
Step 2: Identify the active database from config.php
Before dumping anything, confirm which database Moodle is actually using. Do not guess from panel labels.
grep db /home/username/public_html/config.php
You need at least:
dbnamedbuserdbpass
Step 3: Dump the database on the source server
Create a database dump before transferring the filesystem.
mysqldump --single-transaction -u root -p database_name > backup-website.sql
Use --single-transaction so the dump is consistent without locking large InnoDB tables unnecessarily.
Step 4: Transfer the home directory, including the code and moodledata
The SOP uses rsync with archive mode so owner, group, permissions, and timestamps are preserved:
rsync -ar --progress --partial /home/username/* root@destination:/home/username/
This is practical because the transferred home directory typically contains:
- the Moodle webroot
- the
moodledatadirectory - the SQL dump
For very large sites, expect this step to dominate the migration window.
Step 5: Fix ownership if the destination UID differs
If you could not preserve the same UID, normalize ownership on the destination after the copy. The SOP’s pattern is to make the webroot readable to the web server and moodledata owned appropriately for application writes.
sudo chown -R root /home/website/public_html
sudo chmod -R 0755 /home/website/public_html
sudo chown -R www-data:www-data /home/website/moodledata
sudo chmod -R 0750 /home/website/moodledata
Adjust to your local ownership model, but do it deliberately rather than by trial and error.
Step 6: Recreate the database and user on the destination
Log in to MySQL on the destination and recreate the database and application user with the same credentials the site expects.
CREATE DATABASE dbname;
CREATE USER dbuser@'localhost' IDENTIFIED BY 'dbpassword';
GRANT ALL PRIVILEGES ON dbname.* TO dbuser@'localhost';
FLUSH PRIVILEGES;
If this is Totara, review whether the user also needs permissions to create tables and indexes for caching-related features.
Step 7: Import the database
Import the SQL dump into the recreated database. If the site is large, run this in screen or tmux.
mysql -u dbuser -p dbname < /path/to/backup-website.sql
Step 8: Check MySQL or MariaDB settings before you blame Moodle
The SOP calls out two concrete issues worth checking:
innodb_adaptive_hash_indexshould be on for workloads where it materially helps complex read-heavy query patterns.- the default collation should match Moodle expectations, typically
utf8mb4_unicode_ci.
Also note the operational warning from the SOP: some large Moodle workloads performed significantly worse on MariaDB than on the equivalent MySQL setup. If performance is unexpectedly bad after migration, treat the database platform choice as a real suspect.
Step 9: Copy and adapt the Apache vhost
Copy the source virtual host configuration into the destination and then review:
ServerNameServerAliasErrorLogCustomLog
If the domain changes, these values need to change too.
Watch for Apache 2.2 to 2.4 syntax differences
This is one of the more dangerous migration details in the SOP because it can break the whole Apache reload. If the source config uses old syntax like:
allow from all
and the destination is Apache 2.4+, replace it with:
Require all granted
If you miss this, Apache can fail to load the site config and take down unrelated sites on the same server.
Step 10: Create the Moodle cron job on the destination
Add the Moodle cron task on the destination immediately:
*/1 * * * * /usr/bin/php /home/website/public_html/admin/cli/cron.php >/dev/null
If you are using multiple PHP versions through PHP-FPM, use the exact PHP binary the site needs:
*/1 * * * * /usr/bin/php7.2 /home/website/public_html/admin/cli/cron.php >/dev/null
Step 11: Update the domain references if the hostname changed
If the new site uses a different domain, run Moodle’s replace tool to update stored references:
php /home/website/public_html/admin/tool/replace/cli/replace.php \
--search="old.example.com" \
--replace="new.example.com"
Then update $CFG->wwwroot in config.php and purge caches. The SOP notes that Totara in particular can cache domain-linked navigation elements aggressively.
Step 12: Validate before reopening the site
Before the cutover, test:
- homepage and login
- file delivery
- upload limits
- cron
- SSO or other integrations
If embedded video, uploads, or mail stop working after migration, treat them as explicit post-migration checks rather than “we’ll see if users complain.”
Step 13: Re-establish backups on the new host
The migration is not complete until the destination server has a working backup routine for code, database, and moodledata. Do not assume the old server’s backup arrangement carries over automatically.
Solin specializes in Moodle migrations, host moves, and controlled production cutovers. Need help? Contact us.
Solin handles Moodle migrations, cutovers, DNS changes, and post-migration validation for self-hosted and managed platforms. Need help? Contact us.
Contact us