curl --resolve: Test a Site on a New Server Before DNS
When you move a site to a new server, you want to test it under its real domain before you change DNS. curl --resolve does that for a single command. It tells curl "for this hostname and port, connect to this IP", while everything else (the URL, the Host header, TLS SNI, certificate checks) still uses the real domain. Nothing on your system changes, and there's nothing to undo afterwards.
The basic command
The format is --resolve HOST:PORT:ADDRESS. The port must match the URL's port: 443 for HTTPS, 80 for HTTP.
# HTTPS
curl --resolve example.com:443:203.0.113.10 https://example.com/
# HTTP
curl --resolve example.com:80:203.0.113.10 http://example.com/
Add -I for headers only, or -v to see where curl actually connected:
curl -sv -o /dev/null --resolve example.com:443:203.0.113.10 https://example.com/ 2>&1 | grep -E "Added|Connected|HTTP/"
* Added example.com:443:203.0.113.10 to DNS cache
* Connected to example.com (203.0.113.10) port 443
< HTTP/2 200
If the "Connected to" line shows your new IP, the request went to the new server. If curl never prints "Added", the syntax is off (usually the wrong port), and it fell back to normal DNS.
Testing a new server, step by step
1. Check the response code and server
NEW=203.0.113.10
curl -sI --resolve example.com:443:$NEW https://example.com/ | head -5
Look for a 200 or the redirect you expect, and a Server header or custom header that proves it's the new box.
2. Cover www and redirects
--resolve only applies to the exact host and port you give it. If the site redirects to www, map both, or curl will follow the redirect to the old server via real DNS:
curl -sIL \
--resolve example.com:443:$NEW \
--resolve www.example.com:443:$NEW \
--resolve example.com:80:$NEW \
https://example.com/ | grep -iE "^HTTP|^location"
3. Check several pages at once
for p in / /about/ /contact/ /wp-login.php /sitemap.xml; do
curl -s -o /dev/null -w "%{http_code} %{time_total}s $p\n" \
--resolve example.com:443:$NEW "https://example.com$p"
done
4. Compare old and new
diff <(curl -s https://example.com/) \
<(curl -s --resolve example.com:443:$NEW https://example.com/)
Dynamic bits like nonces and timestamps will differ. Missing sections, error messages or a different <title> will stand out.
5. Confirm the TLS certificate
curl -sv -o /dev/null --resolve example.com:443:$NEW https://example.com/ 2>&1 \
| grep -E "subject:|expire date:|issuer:"
Because SNI is sent correctly, this shows exactly the certificate visitors will get after the switch.
--connect-to: when you need a different port or a hostname
--connect-to HOST1:PORT1:HOST2:PORT2 redirects the connection for HOST1:PORT1 to HOST2:PORT2. It's more flexible than --resolve:
# New server listens on 8443 during testing
curl --connect-to example.com:443:203.0.113.10:8443 https://example.com/
# Point at a load balancer or another hostname instead of an IP
curl --connect-to example.com:443:lb-eu1.myhost.net:443 https://example.com/
# Empty fields mean "any" (left side) or "unchanged" (right side):
# send example.com on any port to the new IP, keeping the port
curl --connect-to example.com::203.0.113.10: https://example.com/
As with --resolve, the URL, Host header and SNI all stay example.com. Use --resolve when you just have an IP, and --connect-to when the port differs or the target is a hostname.
Why not just use -H "Host:"?
curl -H "Host: example.com" https://203.0.113.10/ # don't do this for HTTPS
Over plain HTTP this works. Over HTTPS it breaks in two ways. curl sends no SNI for an IP address, so a server hosting several sites may hand back the wrong certificate. curl also checks the certificate against 203.0.113.10, not the domain, so you get a name mismatch error. Adding -k hides the error but also hides real certificate problems. --resolve avoids all of that.
Common errors and what they mean
| Error | Likely cause | Fix |
|---|---|---|
(7) Failed to connect ... Connection refused | Nothing listening on that port, or a firewall rejecting it | ss -tlnp on the server; open 80/443 in the firewall |
(28) Connection timed out | Firewall dropping packets, wrong IP | Check the cloud provider's security group and the IP |
(60) SSL: no alternative certificate subject name matches | The new server has no certificate for this domain yet (often a default or self-signed one) | Install the certificate, or add -k for a temporary check only |
(60) unable to get local issuer certificate | Incomplete chain: intermediate certificate missing | Serve the full chain (fullchain.pem), not just the leaf |
| Response comes from the old server | Port in --resolve doesn't match the URL, or a redirect went to an unmapped host | Use -v and check for "Added ... to DNS cache"; map www too |
404 or the wrong site | Web server vhost not configured for this domain | Add the domain to server_name / ServerName |
When curl isn't enough
curl is ideal for headers, status codes, certificates and scripted checks. It won't run JavaScript, render the layout, or let a client click around. For that you need a browser pointed at the new IP. You can edit the hosts file on every device involved, or open skipdns.dev, enter the new IP and domain, and get a link that loads the site from the new server under its real hostname in any browser. It's free with no account, and links last 7 days. This comparison of preview tools covers when each one fits.
Once the checks pass, the DNS switch is routine. The website migration checklist covers the order of steps, and DNS propagation time explains how long the switch takes to reach everyone.
FAQ
What does curl --resolve do?
It adds a temporary entry to curl's DNS cache for one command: --resolve example.com:443:203.0.113.10 makes curl connect to 203.0.113.10 whenever the URL uses example.com on port 443. The Host header and TLS SNI still say example.com.
What's the difference between --resolve and --connect-to?
--resolve maps a host and port to an IP address. --connect-to maps a host and port to another host and port, so it can also change the port or point at a hostname such as a load balancer. Both keep the original Host header and SNI.
Why not just set the Host header with -H?
It works for plain HTTP, but over HTTPS curl sends the IP (no SNI) in the TLS handshake and checks the certificate against the IP, so you get the wrong certificate or a name mismatch error. --resolve gets the Host header, SNI and certificate check right.
Does --resolve work with redirects?
Only for the host and port you mapped. If the site redirects from example.com to www.example.com, add a second --resolve for www.example.com, or curl will follow the redirect using real DNS.
How do I use --resolve with IPv6?
Put the address in square brackets: --resolve example.com:443:[2001:db8::10].