curl --resolve and SNI: Testing Virtual Hosts Without /etc/hosts
When you need to test a virtual host on a specific IP but don’t want to edit /etc/hosts — whether due to permissions, conflicts with other services, or just the habit of keeping the file clean — curl --resolve solves both problems at once: it overrides DNS resolution and sends the correct SNI in the TLS handshake.
Problem: virtual host without editing /etc/hosts
Multiple virtual hosts can live on a single IP, and the server picks the right one based on the Host header (HTTP/1.1) and SNI (TLS). Without an entry in /etc/hosts, curl first tries to resolve the name through DNS — getting the wrong IP, or no response at all.
Editing /etc/hosts works, but it requires sudo, clutters the file, and can break other services that depend on the same record.
curl –resolve: syntax and example
The --resolve flag intercepts name resolution at the curl level and substitutes it:
| Component | Meaning |
|---|---|
HOST | Virtual host name |
PORT | Port (typically 443 for HTTPS) |
ADDR | Target IP address |
Example:
curl sends the request to 203.0.113.50:443, but the HTTP Host header will still be example.com.
SNI in combination with –resolve
--resolve does not change the name curl sends in SNI. SNI is taken from the URL.
This is the key point. If the URL contains https://example.com, curl sends example.com as SNI in the TLS ClientHello — even though the IP is overridden via --resolve. The server uses SNI to select the correct certificate and virtual host.
To verify that SNI is actually being sent, use openssl:
If SNI is empty or wrong, the server returns the default certificate — and curl produces an error like SSL: certificate subject name does not match.
Practical example: checking a virtual host
Suppose several virtual hosts run on server 198.51.100.10, and you need to check app.local without touching /etc/hosts:
In the -v output you will see:
Connected to 198.51.100.10 (198.51.100.10) port 443— connection to the correct IP.> Host: app.local— correctHostheader.TLS SNI extension: "app.local"— SNI sent correctly.
For bulk-checking multiple hosts on the same IP:
--resolve applies only to the current curl process. Once the command finishes, the override disappears — /etc/hosts stays untouched.
If you need the override to work for all tools in the terminal, not just curl, then nsupdate or a local DNS resolver (dnsmasq, stubby) is a better fit. But for a one-off virtual host check, --resolve is faster and safer.