Moving a WordPress site comes down to three things: the files (above all wp-content), the database, and every place where the old address is stored. WP-CLI, the official command-line tool for WordPress, handles the database parts reliably, including the serialized data that breaks naive find-and-replace. This guide moves a site between two Linux servers, optionally to a new domain, with a test before the DNS switch and a short final sync.
Before you start
- WP-CLI on both servers. The WP-CLI handbook installs it as a single PHAR file and also describes how to verify that file against its published GPG signature:
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar php wp-cli.phar --info chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp - Matching software. Run
wp core versionandphp -von the old server and make sure the new one runs the same or a newer, supported PHP version and a database that WordPress supports (WordPress recommends MariaDB 10.11 or later, or MySQL 8.0 or later). - A lower DNS TTL. Resolvers may cache a DNS record for its TTL. A day or more before the move, lower the TTL of the site's A and AAAA records (for example to 300 seconds), waiting at least as long as the old TTL before the cutover.
- A full backup of the old site that you could restore without the new server.
Run WP-CLI commands as the user that owns the site files, from the WordPress directory.
1. Copy the files
On the new server, pull the site with rsync over SSH. Do a dry run first. A trailing slash on the source copies the contents of the directory rather than the directory itself:
rsync -az --dry-run --exclude=.maintenance \
deploy@old-server:/var/www/example/ /var/www/example/
rsync -az --exclude=.maintenance \
deploy@old-server:/var/www/example/ /var/www/example/-a (archive mode) preserves permissions and timestamps. Avoid --delete on the first copy so a wrong path cannot remove anything on the destination.
2. Point wp-config.php at the new database
Create an empty database and user on the new server, then update the copied wp-config.php with WP-CLI rather than by hand:
wp config set DB_NAME example_db
wp config set DB_USER example_user
wp config set DB_PASSWORD 'a-long-random-password'
wp config set DB_HOST localhost3. Move the database
On the old server, export; on the new server, import:
# old server
wp db export /tmp/example.sql --add-drop-table
# new server, after copying the file across
wp db import /tmp/example.sql
wp option get home
wp option get siteurlDelete the SQL files once you are done; they contain every user's password hash and all site content.
4. Change the address, only if the domain changes
If the site keeps the same domain, skip this step. If it moves to a new domain or from HTTP to HTTPS, replace the old URL everywhere in the database. The WordPress migration guide warns that a plain search-and-replace can break serialized data, because some themes and widgets store values together with their length; WP-CLI's search-replace handles serialized data and is one of the tools the guide recommends:
wp search-replace 'https://old.example.com' 'https://example.com' --skip-columns=guid --dry-run
wp search-replace 'https://old.example.com' 'https://example.com' --skip-columns=guid--dry-runshows how many replacements would be made in each table without changing anything. Read it before running the real command.--skip-columns=guidleaves theguidcolumn of posts alone. The WordPress documentation is firm that GUIDs must never change, because feed readers use them to recognise items they have already shown.- By default the command only touches tables registered with WordPress. Plugins that keep their own tables under the same prefix may need
--all-tables-with-prefix. --preciseforces PHP processing for every column; use it if you suspect complex serialized data that the default mode misses. It is slower.
Then clear caches and regenerate rewrite rules:
wp cache flush
wp rewrite flush5. Test before anyone else sees it
Point your own computer at the new server by adding a line to its hosts file (/etc/hosts on Linux and macOS, C:\Windows\System32\drivers\etc\hosts on Windows):
203.0.113.10 example.com www.example.comBrowse the site, log in to the dashboard, open a few posts with images, submit a form, and check the server's error log. Remove the line when you are finished. Expect a certificate warning at this stage if the new server does not yet have a certificate for the domain.
6. Final sync and cutover
Anything created on the old site since the first copy, such as orders, comments or uploads, must come across at the end. Keep this window short:
# old server: stop changes
wp maintenance-mode activate
wp db export /tmp/example-final.sql --add-drop-table
# new server: fetch the final copy
rsync -az --exclude=.maintenance deploy@old-server:/var/www/example/wp-content/uploads/ /var/www/example/wp-content/uploads/
wp db import /tmp/example-final.sql
# repeat the search-replace from step 4 if the domain changed
wp cache flushNow change the DNS records to the new server. With the short TTL most visitors arrive within minutes. Issue the TLS certificate on the new server as soon as DNS points to it: Let's Encrypt's HTTP-01 challenge fetches a file from http://<your domain>/.well-known/acme-challenge/, so it only succeeds once the domain resolves to the new server (the DNS-01 challenge works earlier, if your DNS provider supports it). If the new home is a managed hosting plan, check what it does for you; on Skyline's hosting plans, for example, free SSL certificates are issued and renewed automatically and websites and databases are backed up nightly.
After the move
- Leave the old server in maintenance mode, untouched, for a week, and watch its access log for stragglers using cached DNS.
- Check scheduled tasks: if WP-Cron was replaced by a system cron job on the old server, recreate it on the new one.
- Raise the DNS TTL back to its usual value.
- Take a fresh backup on the new server and confirm the restore works.
What you should do
- Lower the DNS TTL in advance and take a full backup of the old site.
- Copy files with
rsync(dry run first) and the database withwp db exportandwp db import. - Change URLs only with
wp search-replace, always after a--dry-run, and always with--skip-columns=guid. - Test through your hosts file before switching DNS.
- Freeze the old site with maintenance mode for a short final sync, then switch DNS and issue the certificate.
- Keep the old server for a week before you delete it.
Sources
- make.wordpress.org/cli/handbook/guides/installing
- developer.wordpress.org/cli/commands/db/export
- developer.wordpress.org/cli/commands/db/import
- developer.wordpress.org/cli/commands/search-replace
- developer.wordpress.org/cli/commands/config/set
- developer.wordpress.org/cli/commands/maintenance-mode/activate
- developer.wordpress.org/cli/commands/cache/flush
- developer.wordpress.org/cli/commands/rewrite/flush
- developer.wordpress.org/advanced-administration/upgrade/migrating
- wordpress.org/about/requirements
- manpages.debian.org/trixie/rsync/rsync.1.en.html
- datatracker.ietf.org/doc/html/rfc1035
- letsencrypt.org/docs/challenge-types
- cloud.alskyline.com/hosting
Comments
0 total · 0 threads