When testing load-balanced HTTPS services, developers often need to target specific backend servers while maintaining proper SSL certificate validation. The standard approach of using curl https://DOMAIN.TLD
doesn't let us specify which backend IP to test, while using curl https://IP_ADDRESS
breaks certificate validation since the cert is issued for the domain, not the IP.
# Problematic approach:
curl https://192.0.2.1 -H 'Host: example.com'
# Results in SSL certificate error: hostname doesn't match
Modern versions of cURL (7.21.3+) support Server Name Indication (SNI) through the --resolve
flag, which solves this elegantly:
# Correct way to test specific IP with SSL validation:
curl https://example.com --resolve example.com:443:192.0.2.1
This command does three things:
1. Forces resolution of example.com to 192.0.2.1 for port 443
2. Maintains proper Host header
3. Preserves full SSL certificate validation
For older systems or special cases, consider these approaches:
Using --connect-to (cURL 7.49+)
curl --connect-to example.com:443:192.0.2.1:443 https://example.com
Modifying /etc/hosts Temporarily
# Add to /etc/hosts
192.0.2.1 example.com
# Then run normal curl
curl https://example.com
# Remember to remove the entry after testing!
For low-level debugging, openssl can verify the SSL handshake directly:
openssl s_client -connect 192.0.2.1:443 -servername example.com -showcerts
While testing with -k/--insecure
might seem tempting, it defeats the purpose of HTTPS validation. Production testing should always maintain certificate validation to catch potential MITM attacks or misconfigurations.
For automated testing, consider setting up proper DNS records or using service discovery instead of hardcoding IPs.
When testing load-balanced HTTPS services, developers often need to target specific backend servers by IP while maintaining proper SSL validation. The fundamental issue arises because:
curl https://192.0.2.1 -H 'Host: example.com'
Triggers a certificate validation failure since the SSL certificate is issued for example.com
but we're connecting to an IP address.
Modern HTTPS implementations enforce strict hostname verification through two mechanisms:
- Server Name Indication (SNI) in the TLS handshake
- Certificate Subject Alternative Name (SAN) validation
When you specify an IP address in the URL, curl automatically uses that for both the TCP connection and certificate validation.
cURL provides two powerful options for this scenario:
curl https://example.com \
--resolve 'example.com:443:192.0.2.1' \
--connect-timeout 3
This approach:
- Maintains proper HTTPS validation by using the domain in the URL
- Forces the connection to your specified IP via DNS override
- Keeps all SSL certificate checks intact
For more complex cases, you might need:
Multiple Backend Testing
#!/bin/bash
servers=("192.0.2.1" "192.0.2.2" "192.0.2.3")
for ip in "${servers[@]}"; do
echo "Testing $ip"
curl -sS https://example.com \
--resolve "example.com:443:$ip" \
-H "X-Test: backend-check" \
-o /dev/null \
-w "HTTP %{http_code} - Size: %{size_download} bytes\n"
done
Certificate Inspection
To verify certificates while targeting specific IPs:
openssl s_client -connect 192.0.2.1:443 \
-servername example.com \
-showcerts < /dev/null 2>/dev/null | \
openssl x509 -noout -text | \
grep -A1 "Subject Alternative Name"
When working with tools that don't support cURL's advanced features:
Hosts File Override
# Temporary DNS override (Linux/macOS)
sudo sh -c "echo '192.0.2.1 example.com' >> /etc/hosts"
curl https://example.com
sudo sed -i '/192.0.2.1 example.com/d' /etc/hosts
Using HTTP/1.1 Host Header
For non-SNI compatible servers (not recommended for production):
curl https://192.0.2.1 \
--http1.1 \
-H "Host: example.com" \
--cacert /path/to/cert.pem
- Always verify the IP actually hosts the service:
nc -zv 192.0.2.1 443
- Check for protocol mismatches with
--tlsv1.2
or--tlsv1.3
- Use
--verbose
to see complete handshake details