How to Verify a Migration Without Touching the Live Site

How to Verify a Migration Without Touching the Live Site

To verify a website migration without downtime, you point your own machine at the new server while everybody else keeps hitting the old one, then compare the two responses until they match. The trick is that this comparison happens entirely through DNS resolution and the Host header, so nothing about the public site changes until you decide it should.

This is the difference between hoping the migration worked and knowing it did. A cutover is a one way door: once the authoritative nameservers hand out the new address, every visitor is a test subject. Verification moves the test to a private door first.

Why the Host Header Is the Whole Mechanism

HTTP/1.1 and later carry a Host header on every request. On a shared or virtual host setup, the web server reads that header and decides which document root, which PHP pool, which TLS certificate and which rewrite rules apply. The server does not particularly care what IP address the connection arrived on, only what name the client asked for.

That decoupling is what makes pre cutover testing possible. You can open a TCP connection to the new server's IP, send a request for example.com, and receive the migrated site as if the DNS record already pointed there. The old server never knows, and your visitors never notice.

There are two ways to exploit this. The first is to override name resolution locally and keep the URL intact. The second is to hit the IP directly and supply the name by hand. Both are worth having in your toolkit because they fail in different ways.

Using curl to Verify a Website Migration Without Downtime

The --resolve flag on curl is the cleanest tool for this job. It tells curl to use a specific IP for a specific host and port, bypassing the system resolver entirely, while leaving the request URL and the Host header untouched. Cookies, redirects and TLS SNI all behave normally because from the client's point of view the hostname never changed.

curl -sS --resolve example.com:443:203.0.113.10 \
  -o /tmp/new.html -D /tmp/new.headers \
  https://example.com/

Run the same command without --resolve to capture the current live response, then diff the two. The headers file is often more informative than the body, because it exposes caching layers, redirect chains and compression settings that a visual check will miss.

curl -sS -o /tmp/old.html -D /tmp/old.headers https://example.com/
diff -u /tmp/old.headers /tmp/new.headers

Expect differences. A new host will almost certainly emit a different Server header, and possibly a different set of Cache-Control or Set-Cookie directives. What you are looking for is not byte equality but the absence of surprises: no unexpected 301 to a staging domain, no X-Robots-Tag: noindex left over from the build, no missing Strict-Transport-Security that the old host was sending.

Checking TLS and SNI Separately

Certificate problems are the most common cause of a migration going sideways at the last moment, and they are easy to test in isolation. The certificate the new server presents must be valid for the hostname, and it must be the certificate the server returns when that hostname is sent in the TLS handshake, not the one it returns for its default vhost.

openssl s_client -connect 203.0.113.10:443 -servername example.com \
  < /dev/null 2>/dev/null | openssl x509 -noout -subject -dates

If that prints a certificate for the wrong name, or one that expires sooner than you expect, you have found a problem that would have taken the site offline for every visitor at once. The -servername flag is doing the same job as --resolve: it tells the server which name you believe you are connecting to.

Pointing Your Browser at the New Server

For anything involving JavaScript, cookies, sessions or a login flow, you want a real browser rather than a command line client. The traditional approach is a hosts file entry. On a Unix like system you would add a line to /etc/hosts mapping the hostname to the new IP, and on Windows the file lives at C:\Windows\System32\drivers\etc\hosts.

This works, but it is blunt. The entry affects every application on the machine, it requires elevated privileges to edit, and it is easy to forget to remove. A cleaner alternative, if your browser supports it, is a command line flag that overrides resolution for that browser process only. Chromium based browsers accept --host-resolver-rules, which takes a comma separated list of mappings.

chromium --host-resolver-rules="MAP example.com 203.0.113.10" \
  --user-data-dir=/tmp/migration-test

The separate user data directory matters. It gives you a clean cookie jar, so you are not testing with a session that was established against the old server under a different secret key. If the new host generated new application keys, an old session cookie will fail in a way that looks like a bug but is really just stale state.

What to Actually Test Once You Are In

Work through the paths that touch state. Log in and confirm the session survives a page load. Submit a form and confirm the write lands in the new database. Upload a file and confirm it is readable from the URL the application hands back. Check that a URL with a trailing slash and one without both resolve the way they did before, because rewrite rules are frequently the thing that gets lost in a migration.

Then look at the things that only break under load or over time. Scheduled tasks, outgoing mail, and any integration that authenticates by source IP are all common casualties. A cron job that ran on the old host may simply not have been recreated, and you will not discover that until a report fails to arrive a week later.

Make the Check Repeatable Before You Cut Over

Ad hoc testing is fine for a small site, but if the migration matters, script it. A short shell script that fetches a fixed list of URLs from both the old and new server, normalises the volatile parts of the response, and reports differences turns a nervous afternoon into a single command you can run as often as you like. The volatile parts are usually dates, CSRF tokens, session identifiers and cache busting query strings, and stripping them is a few lines of sed.

The value of a script is that it runs the same checks every time, including the checks you would have forgotten at the end of a long day. It also gives you a written record of what you verified, which is worth having when someone asks why the cutover happened when it did.

When the diffs come back clean and the browser tests pass, the remaining step is lowering the TTL on your DNS records well in advance, then changing the record and watching your monitoring for the first hour. Keep the old server running and serving for a while after the switch, so that a rollback is a DNS change rather than a restore from backup. If you have not yet set a short TTL, do that first, because it is the one part of this process you cannot rush.

Related articles

Subscribe to our newsletter

Get the latest hosting tips, performance insights, and industry news.