Error message
x509: certificate is valid for example.com, not api.example.com
The two names are filled in per failure: first the names the certificate covers, then the name your client asked for.
Go crypto/x509 — HostnameError from VerifyHostname / TLS dials
What it means
The TLS connection succeeded far enough to read the certificate, but none of its Subject Alternative Names (SANs) match the hostname the client dialed. The error lists both sides, so the gap is visible immediately: the certificate covers X, you asked for Y. Note that modern verification uses SANs only — the legacy Common Name field is ignored.
Why it happens
The SAN list is missing the name in use
commonA certificate issued for example.com does not cover api.example.com (and a wildcard *.example.com covers one level only — not example.com itself, not a.b.example.com). New subdomains need reissued certificates.
Dialing by IP or internal alias
commonConnecting to https://10.0.0.5 or a docker-compose service name presents the certificate of whatever the server thinks it is — the SANs carry public DNS names, not your IP or alias, so the match fails.
Wrong or default certificate served (SNI)
occasionalMulti-tenant ingresses select certificates by SNI. A client that omits ServerName, or an ingress with no rule for the host, gets the default certificate — often a placeholder like "Kubernetes Ingress Controller Fake Certificate".
How to fix it
- 1.
Reissue with every name you actually use
Add all hostnames as SANs at issuance; inspect the current SAN list to see what is covered today.
bash echo | openssl s_client -connect host:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName # request with SANs: openssl req -new -key key.pem -out req.csr \ -subj "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:api.example.com" - 2.
Dial the name, or set ServerName explicitly
When the network address must differ from the certificate name (VIP, port-forward, sidecar), keep verification honest by telling TLS which identity you expect.
go conn, err := tls.Dial("tcp", "10.0.0.5:443", &tls.Config{ ServerName: "api.example.com", // matched against SANs, sent as SNI })