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:

  • dbname
  • dbuser
  • dbpass

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 moodledata directory
  • 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_index should 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:

  • ServerName
  • ServerAlias
  • ErrorLog
  • CustomLog

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
  • email
  • 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