Documentation

# SNI: Server Name Indication

TLS EXTENSION MULTIPLE HOSTS ESSENTIAL FOR HTTPS

# 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

# How SNI Works

HANDSHAKE PROCESS

# TLS Handshake with SNI

Step 1: Client Initiates Connection

plaintext
🌐 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

Step 2: Server Selects Correct Certificate

plaintext
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

plaintext
🏦 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

plaintext
🌐 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)

plaintext
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

# Security Considerations

PRIVACY CONCERNS

# SNI and Privacy

What's Exposed:

plaintext
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

How ECH Works:

plaintext
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;
}
# 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:

plaintext
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:

  1. Open Developer Tools (F12)
  2. Go to Security tab
  3. View Certificate
  4. Check Subject Alternative Names (SAN)

# Common SNI Issues

TROUBLESHOOTING

# Issue 1: Old Client Support

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

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

Comparison:

Approach Pros Cons
Wildcard Cert (*.example.com) One cert for all subdomains
Simpler management
Can't have different CAs per subdomain
All subdomains share same cert
Individual Certs (SNI) Different CAs possible
More granular control
More certificates to manage
More complex renewal

# 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