--resolve. It tells curl, for this one command only, "when you look up this hostname on this port, use this IP address." Everything else about the request stays normal. That makes it one of the most useful pre-cutover checks in hosting support, and it takes a few seconds per URL.
What --resolve changes, and what it leaves alone
--resolve host:port:address. With --resolve example.com:443:203.0.113.10, curl skips the DNS lookup for example.com on port 443 and connects straight to 203.0.113.10. The URL you request still says https://example.com/, so the request looks the same as one from a real visitor:
- The
Hostheader isexample.com, so the web server picks the right virtual host. On shared IPs this matters, because hitting the raw IP usually lands you on a default page instead of your site. - For HTTPS, curl sends
example.comas the SNI name (Server Name Indication, the field that tells the server which certificate to present) and checks the certificate againstexample.com. - Cookies, redirects, and response headers all behave as they would for a visitor.
http:// requests on port 80, and an entry for example.com does nothing for www.example.com. You can repeat --resolve as many times as you need in a single command, and most of the surprises below come from forgetting one of those combinations.
This checks the web side only. Whether your DNS zone on the new nameservers is complete, with MX, TXT, and subdomain records, is a separate job. That's covered in Pre-populating DNS Records on New Nameservers Before Registrar Cutover.
First request: confirm you are on the new server
203.0.113.10 is the new server and 198.51.100.20 is the old one. Replace them and the domain with your own.
BASH
# Verbose request to the new server; headers only, body discarded
curl -sv -o /dev/null --resolve example.com:443:203.0.113.10 https://example.com/
# Compact summary: status, final IP, redirect target, total time
curl -s -o /dev/null --resolve example.com:443:203.0.113.10 \
-w '%{http_code} %{remote_ip} %{redirect_url} %{time_total}
' https://example.com/
# Same summary against the old server, for comparison
curl -s -o /dev/null --resolve example.com:443:198.51.100.20 \
-w '%{http_code} %{remote_ip} %{redirect_url} %{time_total}
' https://example.com/
# Plain HTTP on port 80 needs its own override
curl -sI --resolve example.com:80:203.0.113.10 http://example.com/TEXT
Illustrative output format (varies by curl version):
* Added example.com:443:203.0.113.10 to DNS cache
* Hostname example.com was found in DNS cache
* Trying 203.0.113.10:443...
* Connected to example.com (203.0.113.10) port 443
* Server certificate:
* subject: CN=example.com
* issuer: ...
> GET / HTTP/2
> Host: example.com
< HTTP/2 200
< server: LiteSpeed
< content-type: text/html; charset=UTF-8www while the override doesn't. The remote_ip field in the compact version gives you the same check in one line.
Reading status codes, headers, and redirects
500 on the new server with a 200 on the old one usually means PHP itself is failing: a missing extension, a different PHP version, or a database connection error because the new wp-config.php or .env still has old credentials. A 403 often means file ownership or permissions changed during the copy. A 404 on inner pages while the homepage works is the classic sign that rewrite rules didn't come along, for example an .htaccess that wasn't copied, or an Nginx server block without the try_files line the application expects.
Headers tell you more than the status code. Compare server, x-powered-by (if present), content-type, cache-control, and any cache headers your stack adds. If the old server returns a PHP version header and the new one returns a different version, you've found a possible compatibility issue before any visitor hits it. Which headers appear depends on the server and its config, so treat missing ones as neutral, not as an error.
Redirects need the most care. Without -L, curl shows you the Location header and stops, which is usually what you want here. Check that http:// redirects to https://, that www and the bare domain redirect the way they did before, and that the target is your real domain and not a temporary URL or IP left over from staging. That last one happens often after WordPress migrations where the siteurl and home values still point at a test address.
If you do add -L to follow the chain, remember that each new hostname in the chain needs its own --resolve. Say example.com redirects to www.example.com and you only overrode the first. curl will resolve www through public DNS and quietly follow the redirect to the old server. The final result looks fine, and it tells you nothing about the new one. %{url_effective} and %{remote_ip} in the -w output show you where the chain ended.
SSL errors before cutover are often expected
- If the new server presents the hostname certificate of the server itself, or a self-signed one, no certificate for your domain has been issued yet. Plan for issuance right after cutover, or use DNS-based validation, or install a copy of your existing certificate on the new server if you are allowed to.
- If it presents a certificate for a different customer domain, the vhost or SNI mapping is wrong. Fix that before cutover.
- If it presents your certificate but
wwwormailis missing from it, the coverage gap will follow you to the new host. AutoSSL Skips the www or mail Subdomain? Check Where Its DNS Actually Points explains how to read that.
-k (--insecure) so curl skips certificate verification. Only use it for that. It hides exactly the problem you would otherwise be checking, so drop it once the real certificate is in place and run the request again.
Testing a list of URLs in one pass
/, /wp-login.php, /contact/, a product page, an old URL that should redirect), and run them against both hostnames:
BASH
#!/usr/bin/env bash
# Read-only check: prints status, host, path and redirect target for each URL
NEW_IP='203.0.113.10'
while read -r path; do
for host in example.com www.example.com; do
result=$(curl -s -o /dev/null --max-time 15 \
--resolve "host:443:NEW_IP" \
-w '%{http_code} %{redirect_url}' \
"https://hostpath")
printf '%s %s%s
' "result" "host" "$path"
done
done < paths.txtdiff works well). Any line that differs is worth a closer look with curl -sv. --max-time keeps a stuck PHP request from hanging the whole loop, and a 000 status means curl couldn't complete the request at all. That usually means a firewall, a missing listener on that port, or the timeout.
There's one blind spot. --resolve only affects your curl command. If the application on the new server calls its own domain, as WordPress does for loopback and scheduled tasks, that request goes through the new server's resolver, which still sees the old IP. Page loads can look perfect while background jobs quietly hit the old server. Whether that matters depends on the application, but keep it in mind if something works in your tests and fails after cutover.
The practical habit: before changing nameservers, check that every important URL returns from the new IP with the status, headers, and redirect targets you expect, for both example.com and www, over both HTTP and HTTPS. Know whether any certificate error is expected or a real mapping problem. It takes a few minutes, needs nothing but curl, and means the only thing left to wait for after the nameserver change is DNS caching itself.