#
SNI: Server Name Indication
TLS EXTENSION MULTIPLE HOSTS ESSENTIAL FOR HTTPS
Enables Multiple HTTPS Sites on One IP
SNI (Server Name Indication) is a TLS extension that allows a single server with one IP address to host multiple HTTPS websites with different SSL certificates. Without SNI, you'd need a separate IP address for every HTTPS website!
#
What is SNI?
TLS EXTENSION
Simple Definition: SNI (Server Name Indication) is a TLS extension that allows a client to specify which hostname it's trying to connect to at the start of the TLS handshake. This enables servers to present the correct SSL certificate for that specific domain.
The Problem SNI Solves:
Before SNI, HTTPS had a major limitation:
- One IP = One Certificate - Each HTTPS site needed its own IP address
- IPv4 exhaustion - Running out of IP addresses globally
- Expensive hosting - Virtual hosting didn't work with HTTPS
- Wasteful - Using entire IPs for simple websites
How SNI Fixed It:
- Multiple sites per IP - Host dozens of HTTPS sites on one IP
- Virtual hosting works - HTTPS now works like HTTP virtual hosts
- Cost effective - Dramatically reduced hosting costs
- IPv4 conservation - Solved the IP shortage problem for HTTPS
Real-World Analogy
Think of SNI like an apartment building address system:
Without SNI (Old Way):
- Each apartment (website) needs its own building (IP address)
- Wasteful and expensive
- Can't fit many buildings in the neighborhood (IPv4 exhaustion)
With SNI (Modern Way):
- One building (IP address) with many apartments (websites)
- Mailman (server) checks apartment number (hostname) before delivering
- Each apartment gets the right mail (correct SSL certificate)
- Efficient use of space (IP addresses)
#
How SNI Works
HANDSHAKE PROCESS
#
TLS Handshake with SNI
Step 1: Client Initiates Connection
🌐 Browser → 🏦 Server (IP: 203.0.113.10)
TLS ClientHello:
- TLS Version: 1.3
- Cipher Suites: [TLS_AES_256_GCM_SHA384, ...]
- SNI Extension: hostname = "bank.com" ← THIS IS THE KEY!
- Random bytes for key generation
The Critical SNI Field
The SNI extension in the ClientHello message tells the server which hostname the client wants to connect to. This happens BEFORE encryption, so the server knows which certificate to present.
Step 2: Server Selects Correct Certificate
Server (IP: 203.0.113.10) receives ClientHello
Checks SNI: hostname = "bank.com"
Server has multiple certificates:
├── bank.com → Certificate A ← SELECTED!
├── shop.com → Certificate B
└── blog.com → Certificate C
Selects Certificate A for bank.com
Step 3: Server Responds with Correct Certificate
🏦 Server → 🌐 Browser
TLS ServerHello:
- Selected Cipher Suite: TLS_AES_256_GCM_SHA384
- Certificate: [Certificate for bank.com]
- Server Key Exchange
- Server Hello Done
Step 4: Client Validates Certificate
🌐 Browser validates certificate:
✅ Certificate is for "bank.com" (matches SNI)
✅ Certificate is signed by trusted CA
✅ Certificate is not expired
✅ Certificate has not been revoked
🔒 Connection proceeds with encryption
#
Without SNI (Old Behavior)
Server (IP: 203.0.113.10) receives ClientHello
❌ No SNI extension provided!
Server has multiple sites:
├── bank.com → Certificate A
├── shop.com → Certificate B
└── blog.com → Certificate C
❓ Which certificate should server send?
→ Server sends DEFAULT certificate (maybe Certificate A)
Client wanted shop.com but got bank.com certificate!
❌ Certificate name mismatch error
❌ Connection fails or shows warning
Why This Was a Problem
Without SNI, the server couldn't know which hostname the client wanted BEFORE choosing a certificate. This meant:
- Only the default certificate would work
- All other sites on that IP would show certificate errors
- The only solution was using separate IP addresses for each HTTPS site
#
Security Considerations
PRIVACY CONCERNS
#
SNI and Privacy
SNI Exposes Hostnames
Critical Privacy Issue: SNI sends the hostname in plaintext during the TLS handshake, meaning eavesdroppers can see which website you're connecting to, even though the actual traffic is encrypted.
What's Exposed:
Attacker observes TLS ClientHello:
❌ Visible in plaintext:
- hostname: "secret-dating-site.com" ← EXPOSED!
- Client IP address
- TLS version
- Cipher suites
✅ Still encrypted:
- Actual page URLs (like /profile/user123)
- POST data and form submissions
- Cookies and authentication tokens
- Page content
Privacy Impact:
ISPs can see which domains you visit Government surveillance can monitor website access Corporate networks can track employee browsing Censorship - Countries can block specific domains No way to hide the initial domain in standard SNI
#
Encrypted SNI (ESNI / ECH)
SOLUTION
Encrypted Client Hello (ECH)
Encrypted Client Hello (ECH), formerly called ESNI, encrypts the SNI field to protect privacy. This is the modern solution to SNI privacy concerns.
How ECH Works:
Old SNI (Plaintext):
SNI: "bank.com" ← VISIBLE TO EAVESDROPPERS
ECH (Encrypted):
SNI: "[encrypted blob]" ← HIDDEN FROM EAVESDROPPERS
The SNI is encrypted using the server's public key,
which is published in DNS records.
ECH Status (2025):
- Cloudflare - Supports ECH
- Firefox - ECH enabled by default
- Chrome - ECH support in development
- Server support - Growing but not universal
- Deployment - Requires DNS record setup
# Nginx with ECH support (example)
ssl_ech on;
ssl_ech_keys /path/to/ech_keys;
# Apache with ECH (example)
SSLECHEnabled on
SSLECHKeyDir /path/to/ech/keys
#
SNI Configuration
SERVER SETUP
#
Web Server Configuration
# Multiple HTTPS sites on one IP with SNI
# Site 1: bank.com
server {
listen 443 ssl;
server_name bank.com www.bank.com;
ssl_certificate /etc/ssl/certs/bank.com.crt;
ssl_certificate_key /etc/ssl/private/bank.com.key;
# TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
root /var/www/bank;
index index.html;
}
# Site 2: shop.com (same IP address!)
server {
listen 443 ssl;
server_name shop.com www.shop.com;
ssl_certificate /etc/ssl/certs/shop.com.crt;
ssl_certificate_key /etc/ssl/private/shop.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
root /var/www/shop;
index index.html;
}
# Site 3: blog.com (same IP address!)
server {
listen 443 ssl;
server_name blog.com www.blog.com;
ssl_certificate /etc/ssl/certs/blog.com.crt;
ssl_certificate_key /etc/ssl/private/blog.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
root /var/www/blog;
index index.html;
}
How This Works
Nginx automatically uses SNI to determine which server block to use based on the hostname in the SNI extension. Each site gets its own SSL certificate, all served from the same IP address!
# Multiple HTTPS sites with SNI
# Site 1: bank.com
<VirtualHost *:443>
ServerName bank.com
ServerAlias www.bank.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/bank.com.crt
SSLCertificateKeyFile /etc/ssl/private/bank.com.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
DocumentRoot /var/www/bank
</VirtualHost>
# Site 2: shop.com (same IP!)
<VirtualHost *:443>
ServerName shop.com
ServerAlias www.shop.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/shop.com.crt
SSLCertificateKeyFile /etc/ssl/private/shop.com.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
DocumentRoot /var/www/shop
</VirtualHost>
# Site 3: blog.com (same IP!)
<VirtualHost *:443>
ServerName blog.com
ServerAlias www.blog.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/blog.com.crt
SSLCertificateKeyFile /etc/ssl/private/blog.com.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
DocumentRoot /var/www/blog
</VirtualHost>
#
Testing SNI
VERIFICATION
#
Testing SNI Support
Test SNI with OpenSSL:
# Test specific hostname with SNI
openssl s_client -connect example.com:443 -servername example.com
# Test different hostname on same IP
openssl s_client -connect 203.0.113.10:443 -servername bank.com
# Test without SNI (old behavior)
openssl s_client -connect example.com:443 -no_servername
Expected output with correct SNI:
CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, ...
verify return:1
---
Certificate chain
0 s:CN = example.com
i:CN = DigiCert SHA2 Secure Server CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGYzCCBUugAwIBAgIQBk...
-----END CERTIFICATE-----
subject=CN = example.com ← Matches requested hostname
Check SNI in Browser:
- Open Developer Tools (F12)
- Go to Security tab
- View Certificate
- Check Subject Alternative Names (SAN)
What to Look For
- Certificate should match the domain you're visiting
- SAN field should include the domain
- No certificate warning or error
- Green padlock in address bar
#
Common SNI Issues
TROUBLESHOOTING
#
Issue 1: Old Client Support
Legacy Clients Don't Support SNI
Problem: Clients older than 2010 don't support SNI, causing certificate errors.
Affected Clients:
- Windows XP (Internet Explorer 6)
- Android 2.x (default browser)
- Java 6 and older
- Python 2.x (without backports)
- Old mobile phones
Solutions:
WORKAROUND 1 Use dedicated IP address for critical sites
WORKAROUND 2 Display browser upgrade message for old clients
WORKAROUND 3 Use wildcard certificates for subdomains
#
Issue 2: Certificate Mismatch
Wrong Certificate Served
Problem: Server serves wrong certificate when SNI isn't working correctly.
Causes:
- Server not configured properly
- Client not sending SNI
- Default certificate configured incorrectly
- Firewall/proxy stripping SNI
Debug Steps:
# Check which certificate is served
openssl s_client -connect domain.com:443 -servername domain.com | openssl x509 -noout -text
# Check server configuration
nginx -t # Nginx
apachectl configtest # Apache
# Verify DNS points to correct IP
dig domain.com +short
#
Issue 3: Wildcard vs Multiple Certificates
When to Use Wildcards
Wildcard certificates (*.example.com) can simplify SNI configuration for subdomains.
Comparison:
#
SNI Best Practices
RECOMMENDATIONS
#
Do's
Enable SNI on all modern web servers Test thoroughly with multiple browsers and clients Monitor certificate expiration for all hosted domains Use Let's Encrypt for free automated certificates Configure default certificate as fallback for non-SNI clients Implement ECH when available for privacy Document which domains are on shared IPs
#
Don'ts
Don't assume all clients support SNI (check analytics) Don't forget intermediate certificates in the chain Don't mix wildcard and specific certs carelessly Don't ignore certificate transparency logs Don't use self-signed certificates in production
#
SNI History and Adoption
EVOLUTION
Timeline:
- 2003 - SNI standardized in RFC 3546 (TLS Extensions)
- 2006 - Apache 2.2.12 adds SNI support
- 2009 - Nginx 0.5.23+ supports SNI
- 2010 - Windows Vista+ / IE 7+ support SNI
- 2012 - SNI becomes widely adopted
- 2018 - ESNI (Encrypted SNI) proposed
- 2020 - ECH (Encrypted Client Hello) development
- 2025 - SNI universal, ECH deployment growing
Adoption Rate (2025):
- 99%+ of browsers support SNI
- 95%+ of servers configured for SNI
- <1% legacy clients without SNI
- 20%+ servers with ECH support
#
Related Topics
#
Learn More
TLS/SSL Basics - Understanding the full TLS handshake Certificate Chain - How certificates are validated HSTS - Forcing HTTPS connections Certificate Revocation - CRL and OCSP
#
Protected by Layerd AI
Layerd AI Guardian Proxy provides:
SNI Validation - Ensures correct certificates for requested hostnames Certificate Monitoring - Alerts before certificate expiration Multi-Domain Support - Automatic SNI handling for virtual hosts ECH Support - Privacy-preserving hostname encryption Legacy Client Detection - Identifies and handles non-SNI clients
Learn more about Layerd AI Protection →
Last updated: November 2025