Moving Client Sites Without Downtime: An Agency Checklist

A repeatable checklist for agencies moving client sites to a new host: inventory, rsync and mysqldump, testing before DNS, mail cut-over, SSL and rollback.

Published
Reading time
6 min

Moving a client's site is a technical job with somebody else's revenue and inbox attached, and usually twenty more sites queued behind it. The single-site sequence is in how to move a website without downtime; this is the agency version: the inventory that stops surprises, commands you can reuse per site, and the parts that go wrong when the site is not yours.

The checklist

One copy per client. Every line is explained below.

When Task Done
T-3 days Confirm who controls DNS and get a working login [ ]
T-3 days Inventory: files, databases, mailboxes, cron, PHP version, DNS records [ ]
T-2 days Lower TTL on A, AAAA and MX records to 300 [ ]
T-1 day First copy of files and databases to the new server [ ]
T-1 day Create mailboxes on the new server, first imapsync pass [ ]
T-1 day Test over hosts file or curl --resolve, fix what breaks [ ]
T-0 Freeze content, final rsync and database import [ ]
T-0 Switch DNS, issue SSL, verify from outside [ ]
T+1 day Second imapsync pass, check cron output and error logs [ ]
T+7 days Raise TTL, take a last backup of the old account, cancel it [ ]

Find out who controls DNS first

More client migrations stall here than anywhere else. The domain is registered to a former employee, the nameservers belong to the previous agency, or the zone lives at the old host and disappears when the account is cancelled. Check before you promise a date:

bash
dig +short NS clientsite.co.uk

If the nameservers belong to the old host, you are moving DNS as well as the site: recreate the full zone at the new provider before changing nameservers, not after.

Take a full inventory

Write down everything the old account does, because the client will not know. On the old server over SSH:

bash
# size of the site
du -sh ~/public_html

# PHP version and loaded extensions
php -v && php -m

# scheduled jobs
crontab -l

# databases and their sizes
mysql -u dbuser -p -e "SELECT table_schema AS db,
  ROUND(SUM(data_length + index_length) / 1024 / 1024) AS mb
  FROM information_schema.tables GROUP BY table_schema;"

And from anywhere, the DNS records that exist today:

bash
for t in A AAAA MX TXT NS CAA; do dig +noall +answer clientsite.co.uk $t; done
dig +noall +answer www.clientsite.co.uk A
dig +noall +answer _dmarc.clientsite.co.uk TXT

dig cannot list a zone, so also export or screenshot it from the old panel. The records that get lost are the ones nobody remembers adding: a verification TXT, a DKIM key for a newsletter service, a subdomain pointing at a booking system. DNS record types explained covers what each one does.

For mail, list every mailbox, forwarder and autoresponder. Ask the client which addresses are used; expect them to forget two.

Tip: note the PHP version the site runs on now and match it on the new server for the move. Upgrading PHP and changing host on the same day gives you two possible causes for every error.

Lower the TTL two days ahead

Resolvers cache your old IP for as long as the TTL says. Check it:

bash
dig +noall +answer clientsite.co.uk A
# clientsite.co.uk.  14400  IN  A  198.51.100.20

Set A, AAAA and MX records to 300 seconds, then wait at least the old TTL (here four hours) before the switch. Two days ahead covers zones with a 24-hour TTL.

Copy files and databases

Run the copy from the new server, pulling from the old one. The trailing slashes matter: they mean "the contents of", not "the directory itself".

bash
rsync -avz --delete \
  --exclude='wp-content/cache/' --exclude='*.log' \
  -e ssh olduser@old-host.example:public_html/ \
  /home/newuser/domains/clientsite.co.uk/public_html/

--delete makes the destination an exact mirror. Add -n for a dry run until you are certain the destination path is right.

Dump the database on the old server:

bash
mysqldump --single-transaction --quick --routines --no-tablespaces \
  -u dbuser -p client_db | gzip > client_db.sql.gz

--single-transaction gives a consistent snapshot of InnoDB tables without locking the live site. --no-tablespaces avoids the PROCESS privilege error that shared-hosting database users hit on recent MySQL versions. Import into a database you created in the new panel, then update the site's config file with the new credentials:

bash
gunzip < client_db.sql.gz | mysql -u newuser_db -p newuser_db

Tip: if the old host has no SSH, do not fall back to FTP for thousands of small files. Download a full account backup archive and unpack that.

Test on the new server before DNS

Point only your own machine at the new server with a hosts-file line:

203.0.113.55  clientsite.co.uk www.clientsite.co.uk

For a scripted check across many sites, curl --resolve does the same per request:

bash
curl -skI --resolve clientsite.co.uk:443:203.0.113.55 https://clientsite.co.uk/ | head -n 1

-k skips certificate verification, because the real certificate is not on the new server yet. A 200 means PHP, the database and the rewrite rules work. Then test by hand what a script cannot: admin login, a contact form, an upload, checkout. Remove the hosts line afterwards.

SSL timing

Let's Encrypt's HTTP validation only succeeds once the domain resolves to the new server. Three ways to avoid a browser warning:

  1. Copy the existing certificate and private key from the old host and install them on the new one; replace them with a fresh certificate later.
  2. Use DNS validation, if your DNS provider and panel support it, to issue in advance.
  3. Issue immediately after the switch. The gap is a few minutes; acceptable for a brochure site, not for a shop.

On DirectAdmin the issuing step is in free Let's Encrypt SSL in DirectAdmin.

Final sync and the switch

Pick a quiet hour. Ask the client to stop editing, or put the shop into maintenance mode: any order written to the old database after the final dump is lost. Repeat the two copy commands (rsync transfers only what changed), re-import the database, and change the A and AAAA records. Watch it land:

bash
watch -n 15 'dig +short clientsite.co.uk A @1.1.1.1; dig +short clientsite.co.uk A @8.8.8.8'

Mail cut-over

Create every mailbox on the new server first, with the same addresses. Then copy messages over IMAP with imapsync, once before the switch and once a day after:

bash
imapsync \
  --host1 mail.old-host.example --user1 anna@clientsite.co.uk --passfile1 old.pass --ssl1 \
  --host2 203.0.113.55 --user2 anna@clientsite.co.uk --passfile2 new.pass --ssl2

The second run picks up mail delivered to the old server by senders with a cached MX. imapsync skips messages already copied, so repeating it is safe.

Update SPF to include the new server and publish the new DKIM key before the switch; SPF, DKIM and DMARC explained has the formats. Send the client the new mail server names in advance.

Tip: if the client's mail is on Microsoft 365 or Google Workspace, leave the MX, SPF, DKIM and autodiscover records exactly as they are. The classic fault is a new zone with the host's default MX in it, and the client's email silently going to an empty mailbox.

The rollback plan

Decide it before the switch. It is short, because the old server has not been touched:

  • Old account stays active and unmodified for at least seven days.
  • TTL stays at 300 until you are sure. Rolling back is then one A-record change and five minutes.
  • If you roll back after the new site has taken orders or form entries, export those first; they exist only on the new server.
  • Define the trigger in advance: for example, checkout failing for 30 minutes with no identified cause.

After a week of clean error logs, raise the TTL again, download a last backup of the old account and cancel it.

For agencies that would rather not do this twenty times, our agency hosting comes with a free migration service, so the copying and testing above can be our job instead of yours.

#migration#agencies#dns#rsync#email

Keep reading

More from Migration

All guides

Migration

How to Move a Website to a New Host Without Downtime

The zero-downtime migration sequence we use for every site — copy files and database, test with a hosts-file trick, lower the DNS TTL, then switch.

3 min read →

Migration

How to Migrate From cPanel to Plesk

Move a cPanel account to Plesk with the Plesk Migrator — sites, databases, mail, DNS — plus the manual method, what does not transfer, and pre-switch checks.

3 min read →

Networking

What Is a Reverse DNS (PTR) Record and Why Email Needs It

How a PTR record maps an IP back to a hostname, why Gmail and Outlook reject mail from servers without one, how to check yours, and who can actually set it.

3 min read →