TLS, certificates and host overrides

curl · Advanced · 12 min

Internal CAs, mutual TLS and testing a new server before DNS changes are routine in real infrastructure.

For https:// URLs curl verifies the server's certificate chain against a CA bundle and checks that the certificate matches the host name. Failures produce exit code 60 (or 35 for handshake errors).

  • --cacert internal-ca.pem trusts an extra CA, such as your company's internal CA. CURL_CA_BUNDLE sets it via environment.
  • -k / --insecure disables verification entirely. Fine for a one-off look at a dev box, but never in scripts: it makes the connection open to interception.
  • -v shows the negotiated TLS version, cipher and certificate subject, issuer and expiry, which usually explains the failure.

Mutual TLS (the server also verifies the client): --cert client.crt --key client.key, or a single PEM with both. Some services use this instead of tokens.

Testing without changing DNS:

  • --resolve api.example.com:443:203.0.113.50 makes curl connect to that IP for that host and port, while the URL, SNI and Host header stay api.example.com. Ideal for checking a new server or a single node behind a load balancer before switching DNS.
  • --connect-to api.example.com:443:staging.internal:443 similarly redirects the connection to another host name.

Do not fake the host with -H 'Host: ...' against an IP for HTTPS: SNI and certificate checks would use the IP, not the name.

Example

curl -sS https://intranet.corp/api            # curl: (60) SSL certificate problem
curl -sS --cacert corp-root-ca.pem https://intranet.corp/api   # OK
curl -sS --cert client.crt --key client.key https://mtls.example.com/v1/ping
curl -v https://example.com -o /dev/null 2>&1 | grep -E 'SSL connection|subject|expire'
# * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
# *  subject: CN=example.com
# *  expire date: Jan 15 23:59:59 2027 GMT
# test the new server before the DNS switch
curl -sS --resolve www.example.com:443:203.0.113.50 https://www.example.com/health
curl -sS --connect-to www.example.com:443:node-2.internal:443 https://www.example.com/

Remember

  • --cacert trusts an extra CA; -k disables verification (avoid)
  • --cert/--key for mutual TLS
  • --resolve and --connect-to target a specific server with the real host name

Watch out for

  • Adding -k to make an error go away in a script, leaving it permanently unverified.

Check yourself

  1. You want to hit the new server at 203.0.113.50 as https://shop.example.com, with correct SNI and certificate checks, before DNS changes. Use:

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: curl.se/docs/sslcerts.html