⚡ 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.