Cloud

Move a WordPress site to a new server or domain with WP-CLI, rsync and search-replace

A step-by-step WordPress move with WP-CLI: export and import the database, sync files with rsync, run search-replace safely and switch DNS with little downtime.

Published
Reading time
7 min read

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 version and php -v on 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 localhost

3. 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 siteurl

Delete 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-run shows how many replacements would be made in each table without changing anything. Read it before running the real command.
  • --skip-columns=guid leaves the guid column 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.
  • --precise forces 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 flush

5. 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.com

Browse 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 flush

Now 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

  1. Lower the DNS TTL in advance and take a full backup of the old site.
  2. Copy files with rsync (dry run first) and the database with wp db export and wp db import.
  3. Change URLs only with wp search-replace, always after a --dry-run, and always with --skip-columns=guid.
  4. Test through your hosts file before switching DNS.
  5. Freeze the old site with maintenance mode for a short final sync, then switch DNS and issue the certificate.
  6. Keep the old server for a week before you delete it.

Sources

SKYLINE Engineering

@skyline

The engineering team at SKYLINE Industrial Solutions. We publish field-tested guides drawn from real KSA and GCC deployments.

See author profile
SKYLINE engineering services

Need this implemented for you?

Reading is free — building it right takes a team. SKYLINE engineers ship Cloud for Aramco vendors, banks, hospitals and government agencies across Saudi Arabia. Talk to us before you start.

Aramco Approved Contractor ISO 9001 · ISO 27001 SAMA CSF aligned NCA ECC ready 247+ KSA clients

Comments

0 total · 0 threads
Be the first to leave a comment.