β‘ cURL --resolve vs -H "Host:" β Practical DNS Tricks for DevOps¶
In DevOps, we often need to test services before DNS propagation, behind ingress controllers, or on custom ports.
This is where curl --resolve becomes your secret weapon β it simulates DNS entries without modifying /etc/hosts.
π Table of Contents
1. [π§© The Problem](#-the-problem) 2. [βοΈ The Solution β `--resolve`](#οΈ-the-solution---resolve) 3. [βοΈ Comparison β `--resolve` vs `-H "Host:"`](#οΈ-comparison---resolve-vs--h-host) 4. [π DNS Resolution Flow](#-dns-resolution-flow) 5. [βΈοΈ Real-World Kubernetes Example](#οΈ-realworld-kubernetes-example) 6. [π HTTPS & SNI Behavior](#-https--sni-behavior) 7. [π§° DevOps Advantages](#-devops-advantages) 8. [π§© Summary Cheat Sheet](#-summary-cheat-sheet) 9. [β‘ Quick Recap](#-quick-recap) 10. [π¨βπ» Author Meta](#-author-meta)π§© The Problem¶
You have a service available internally:
192.168.102.154:31568
but it only serves requests for the hostname:
sam.com
````
If you try:
```bash
curl https://sam.com:31568/
````
π₯ It fails because **DNS doesnβt know how to resolve `sam.com`** to that IP.
---
## βοΈ The Solution β `--resolve`
`curl --resolve` lets you manually tell curl *which IP* a hostname should resolve to, temporarily.
```bash
curl -k --resolve sam.com:31568:192.168.102.154 https://sam.com:31568/
| Flag | Description |
|---|---|
-k | Ignore SSL certificate validation (useful for self-signed certs). |
--resolve sam.com:31568:192.168.102.154 | Maps sam.com on port 31568 to IP 192.168.102.154. |
https://sam.com:31568/ | Uses hostname in the URL so the correct Host header and SNI are sent. |
π§ Deep Dive: What Happens Internally¶
curlskips DNS lookup forsam.com.- It directly connects to
192.168.102.154:31568. - It sends
Host: sam.comin the request. - The web server (NGINX, Ingress, Apache, etc.) routes it correctly.
-kensures SSL issues donβt block testing.
β Result: The app responds as if DNS already existed.
βοΈ Comparison β --resolve vs -H "Host:"¶
The -H "Host:" flag only changes the HTTP header, not DNS lookup.
β Example 1 β Fails (no DNS entry)¶
curl -k -H "Host: sam.com" https://sam.com:31568/
If sam.com isnβt in DNS, curl canβt reach the server at all.
β Example 2 β Works (using IP)¶
curl -k -H "Host: sam.com" https://192.168.102.154:31568/
Here:
- Curl connects to IP directly
- Sends
Host: sam.com - The server routes correctly
β Works β but SNI (for HTTPS) still uses the IP, not the hostname.
| Feature | --resolve | -H "Host:" |
|---|---|---|
| Changes DNS resolution | β Yes | β No |
| Sends custom Host header | β Yes | β Yes |
| Works without DNS | β | β οΈ Only with IP |
| Affects HTTPS SNI | β | β |
| Ideal for | DNS override & testing | Quick vhost testing on IP |
π DNS Resolution Flow¶
π§ Normal DNS Flow¶
curl https://sam.com
β
βΌ
[System Resolver]
β
βΌ
[DNS Server] β Returns IP
β
βΌ
Connects to IP β Sends Host: sam.com
β Works only if DNS exists.
βοΈ /etc/hosts Override¶
192.168.102.154 sam.com
curl β System Resolver β /etc/hosts β
β Connects β Host: sam.com
β
Works system-wide β οΈ Needs sudo, permanent until removed.
π‘ --resolve Override (Best for Testing)¶
curl -k --resolve sam.com:31568:192.168.102.154 https://sam.com:31568/
curl β Internal Resolver β
β Skips DNS β Connects β Host: sam.com
β Temporary β No root access β Proper SNI for HTTPS
π§ Priority Order¶
| Source | Priority | Scope | Notes |
|---|---|---|---|
--resolve | πΊ Highest | Per curl call | Safest & temporary |
/etc/hosts | Medium | System-wide | Requires sudo |
| DNS | Lowest | Default | Needs propagation |
βΈοΈ Real-World Kubernetes Example¶
When testing Kubernetes Ingress before DNS is live, --resolve is a lifesaver.
Example Ingress¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: production
spec:
rules:
- host: sam.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
If you try to curl using IP directly:
curl http://192.168.102.154
β Youβll get 404 Not Found β missing Host: sam.com.
β
Use --resolve¶
curl --resolve sam.com:80:192.168.102.154 http://sam.com
For HTTPS:
curl -k --resolve sam.com:443:192.168.102.154 https://sam.com
β Pretends DNS exists β Routes correctly through Ingress
πΌοΈ Visual Flow¶
Client (curl)
βββ Manual map: sam.com β 192.168.102.154
βββ Connects to IP
β
βΌ
NGINX Ingress
β
Matches Host: sam.com
βΌ
Routes to myapp-service
π‘ Pro Tip for Automation¶
INGRESS_IP=$(kubectl get ingress myapp-ingress -n production -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -k --resolve sam.com:443:$INGRESS_IP https://sam.com
β Perfect for CI/CD validation before DNS changes.
π HTTPS & SNI Behavior¶
| Scenario | Host Header | SNI Sent | HTTPS Works? |
|---|---|---|---|
curl -H "Host:" https://IP | sam.com | IP | β |
curl --resolve sam.com:443:IP https://sam.com | sam.com | sam.com | β |
π‘ SNI (Server Name Indication) ensures the correct SSL certificate is presented.
π§° DevOps Advantages¶
| Use Case | Why --resolve Helps |
|---|---|
| π§ͺ Test Ingress before DNS | No need to edit /etc/hosts |
| π§± Multiple vhosts on one IP | Perfect for multi-domain ingress |
| π SSL/TLS validation | Sends correct SNI |
| π§ Troubleshoot routing | Verify host-based routing |
| βοΈ CI/CD testing | Automatable and non-invasive |
π§© Summary Cheat Sheet¶
| Scenario | Recommended Command |
|---|---|
| DNS not ready | curl --resolve host:port:IP https://host:port/ |
| Multi-domain test | Multiple --resolve flags |
| Quick vhost test | curl -H "Host: host.com" https://IP:port/ |
| System-wide mapping | /etc/hosts |
| Ignore SSL mismatch | Add -k |
β‘ Quick Recap¶
Think of
--resolveas a temporary DNS record, and-H "Host:"as a fake name tag. Both tell the server βIβm calling sam.com,β but only--resolvetells curl where to find it.
π¬ Quote:
π§ β
--resolvelets you see tomorrowβs DNS today.β Before DNS goes live, you can already test, verify, and automate routing checks like a pro.