SNI: how one IP address serves hundreds of certificates
Before 2003 a server could present one certificate per IP address, and hosting several HTTPS sites meant buying several addresses. Server Name Indication removed that constraint, and it is the reason a single load balancer can terminate TLS for thousands of domains. It also explains a confusing class of failure where a host serves a certificate for a completely unrelated domain.
The ordering problem
Consider what a server knows at each stage of a request to https://shop.example.com.
The TCP connection carries the destination IP, nothing more. The TLS handshake begins, and the server must send its certificate almost immediately, as part of establishing the encrypted channel. Only after TLS completes does the HTTP request arrive, carrying the Host: shop.example.com header that says which site was wanted.
So the server must choose a certificate before it learns which name to choose it for. Plain HTTP has no such problem, because the Host header arrives in the clear at the start. Adding TLS underneath inverts the order.
What SNI does
SNI is an extension in the ClientHello, the first message the client sends. The client includes the hostname it intends to reach, so the server can select the matching certificate before responding.
ClientHello
server_name: shop.example.com
supported_versions: TLS 1.3, TLS 1.2
...
That single field is the whole mechanism. It is sent before encryption is established, so it travels in plaintext, which matters and we will come back to it.
Every current browser and library sends SNI. Support has been effectively universal for over a decade, and the clients that lacked it, notably very old Android and Windows XP era stacks, are no longer a practical consideration.
Why you sometimes get the wrong certificate
A server holding many certificates needs a rule for when SNI is absent or matches nothing. That rule is a default certificate, and it is the source of the confusion.
If a client sends no SNI, or sends a name the server has no certificate for, the server does not fail. It presents its default, which is typically the first configured site or whichever virtual host is marked as default. The client then sees a certificate for some other domain and reports a name mismatch.
The two situations that produce this in practice:
- Connecting by IP address. There is no hostname to send, so no SNI, so you receive the default certificate. A name mismatch here is expected behaviour, not a misconfiguration.
- The hostname is not configured on that server. DNS points the name at the load balancer, but nobody added the site to it. The default certificate answers instead, and the mismatch error is really telling you the site is missing.
The second case is easy to misread. The error mentions certificates, so it looks like a certificate problem, when the actual problem is that this host has never heard of the name you asked for.
Debugging it with openssl
The behaviour is easiest to see by controlling SNI directly.
With SNI:
openssl s_client -connect 203.0.113.10:443 -servername shop.example.com
Without SNI:
openssl s_client -connect 203.0.113.10:443
Compare the subject and SAN entries in the two responses. If the first returns the right certificate and the second returns something else, SNI is working correctly and you are simply seeing the default.
The same comparison diagnoses a suspected missing configuration: if a valid -servername still returns the default, the name is not set up on that server.
A quick way to check what a name resolves to and what certificate it actually serves, without assembling openssl flags, is the SSL checker, which connects to the host by name and reports the chain and the names on the leaf. For a list of hosts behind the same address, the bulk SSL checker makes the differences obvious in one pass.
SNI and the certificate strategies around it
SNI changes the arithmetic of how you cover multiple names.
A SAN certificate lists several names in one certificate, so a server can answer for all of them with a single file and no SNI selection is needed among them. A wildcard covers one label under a domain. With SNI you can also simply hold many separate certificates and let the server pick, which is what large platforms do because it lets each tenant's certificate be issued and renewed independently.
The tradeoff is operational rather than cryptographic: one SAN certificate means one renewal and one point of failure for every name on it, while many certificates mean many renewals and isolated failures. Wildcard versus SAN certificates covers where each fits.
The plaintext hostname, and ECH
Because SNI is sent before the connection is encrypted, anyone observing the network sees which hostname you requested, even though the request itself is protected. On a shared IP, SNI is what reveals which of the hosted sites a user visited.
An earlier attempt called Encrypted SNI (ESNI) encrypted just that field. It has been superseded by Encrypted Client Hello (ECH), which encrypts the sensitive parts of the entire ClientHello rather than one extension. ECH relies on the client obtaining a public key for the server, distributed through DNS in an HTTPS resource record, and it needs DNS itself to be protected to be meaningful, since otherwise the DNS query reveals the same name.
Deployment is partial. Cloudflare and Firefox have shipped support, other combinations have not, and clients fall back to plaintext SNI when ECH is unavailable. Treat the hostname as observable unless you have specifically verified otherwise.
What this means when you are diagnosing TLS
Three habits save time:
- Always test by hostname, not by IP. Testing by IP guarantees the default certificate and tells you nothing about the site you care about.
- Read a name mismatch as a routing question first. Ask whether this server has the name configured before assuming the certificate is wrong.
- Check the chain as well as the leaf. A correct leaf served with a missing intermediate fails in some clients and not others, which is a different problem with similar symptoms. Fixing SSL certificate chain errors covers that case, and the SSL checker reports whether the chain it received was complete.
For the handshake itself and where SNI sits inside it, see the TLS handshake explained.