Moving a Live Website to a New Server Without a Downtime Story

A step-by-step migration checklist for moving a production web app to a new VPS — DNS TTLs, database sync, the cutover window, and the rollback you prepare before you need it.

Moving a Live Website to a New Server Without a Downtime Story

At some point every project moves: the VPS is too small, the provider had an incident, or the stack finally changed. The move itself is ordinary sysadmin work. What makes migrations go wrong is ordering: people copy files, cut DNS, and discover at hour zero that the database didn't come across completely, or that the old server kept receiving mail for three days. The whole job is making the new server fully qualified before anyone points traffic at it, so the cutover is a switch, not a leap.

Before anything: inventory what "the site" actually is

Write the list before moving a single file. A web app is almost never just the code:

  • The application code and its build artifacts
  • The database, with size and charset noted
  • Uploaded files and anything on local disk that changed after deploy (this is the item most often forgotten, and the most painful)
  • Cron entries, queue workers, daemons, their users and environments
  • TLS certificates, or the renewal mechanism that will fetch them on the new box
  • DNS records beyond the A record: MX, SPF, subdomains, API callback URLs
  • Environment variables and secrets (from the server, not from memory)

Treat anything not on the list as already lost. Then check the list against reality on the old server — crontab -l for every user, running services, directories the app writes to. The inventory is also your rollback plan: it says what still needs the old machine.

Bring the new server to full readiness first

Build the new box to serve production traffic completely before it sees a single visitor: stack installed, app deployed, database restored from a backup, workers running, certificates issued, health checks passing. Use the deployment pipeline you already have rather than hand-copying files. Then test it hard against a hosts-file override, which puts the new server at the end of its own address while nobody else is looking:

95.216.162.138  example.com www.example.com

Browse the site, log in, submit a form, check the queue drain, check that emails send. Every bug you find here is one that would otherwise be a production incident during cutover.

Lower the DNS TTL a day ahead

DNS caching decides your cutover speed. A record with an 86400-second TTL means resolvers worldwide can serve the old address for up to a day after you switch — which is why "we moved the site but some customers still see the old one" is a support-ticket classic.

The day before: drop the TTL to 300 seconds. Wait out the old TTL (that day) so every resolver holds only short-lived answers. Now the switch propagates in minutes, not hours.

The old server stays up through all of this. It's not the old server until the cutover window is over, and honestly, until a TTL-period after that.

The cutover window

With everything rehearsed, the switch itself is minutes:

  1. Freeze writes on the old database — maintenance banner, read-only mode, whatever the app supports. A few minutes of a banner beat reconciling two divergent databases any day.
  2. Final database sync — dump on the old server, restore on the new (or replicate continuously ahead of time and just catch the tail).
  3. Copy the stragglers — uploads and anything else that changed since the main copy. rsync -av with --update picks up exactly the delta.
  4. Flip DNS to the new server's address.
  5. Run the checklist from your hosts-file session against the live domain. Health endpoint, one real login, one real form submission.
  6. Keep the old server running, read-only, for the TTL window plus a safety margin. It now serves nothing but stragglers hitting cached DNS — and that's exactly what it's for.

Rollback: a switch back, not a recovery

This is what makes the whole thing calm. Until DNS expires everywhere, rollback is the reverse switch: point DNS at the old server, unfreeze its database, and you're live again within the TTL. Costs you the writes made to the new database since cutover — usually minutes' worth, and usually nothing, because you'd cut over in a quiet window.

That changes completely once real writes have landed on the new database (orders, signups, messages). Then rollback means merging divergent data between two databases, and that's a project, not a procedure. This is the line, and it's why the checklist in step 5 matters more than it looks: it's not caution, it's the point of no return, and you want to cross it deliberately with the checklist green.

The week after

  • Watch error logs on the new server and access logs for anything still hitting the old one.
  • Verify the certificate renews automatically on the new box before its first expiry arrives unattended.
  • Check cron actually ran (jobs on schedule, queue workers drained overnight).
  • Confirm monitoring, backups, and alerting now point at the new machine. A backup job silently writing to a decommissioned server is the most common thing we find in post-migration reviews.
  • Only then decommission the old server, and keep its last backup anyway.

Budget a quiet morning, not a weekend. The move is 90% preparation and 10% a five-minute switch, and the projects that follow that ratio are the ones where clients never notice anything happened.