When running multiple HTTPS virtual hosts on a single server, the traditional Server Name Indication (SNI) extension in TLS exposes the requested hostname in plaintext during the initial handshake. This allows network observers to determine which website a client is accessing, even when the actual content is encrypted.
Encrypted SNI works by:
- Using a public key published in the DNS (via HTTPS RR or alternative methods)
- Encrypting the SNI field with this key during the TLS handshake
- Allowing only the intended server to decrypt the hostname
For modern Nginx setups with OpenSSL 1.1.1 or later:
# Generate ESNI key pair
openssl genpkey -algorithm X25519 -out esni.key
openssl pkey -in esni.key -pubout -out esni.pub
# Add to nginx.conf
ssl_esni on;
ssl_esni_key esni.key;
Publish your ESNI public key in DNS (example for BIND):
_esni.example.com. IN HTTPS 1 . alpn="h2,h3" ipv4hint=192.0.2.1 ipv6hint=2001:db8::1 esniconfig="ABCDEF..."
Use OpenSSL to test your setup:
openssl s_client -connect example.com:443 -servername example.com -esnikey $(cat esni.pub)
Currently Firefox (via about:config) and experimental Chromium builds support ESNI. Configure Firefox with:
network.security.esni.enabled = true
network.dns.echconfig.enabled = true
For servers that don't yet support native ESNI:
- Consider using a TLS terminating proxy with ESNI support
- Implement domain fronting techniques (though limited by modern CDN policies)
- Wait for upcoming ECH (Encrypted Client Hello) standardization
ESNI adds approximately 1-2ms to the TLS handshake due to the additional cryptographic operations. This overhead is generally acceptable for privacy-sensitive applications.
Encrypted Server Name Indication (ESNI) is a TLS extension designed to prevent eavesdroppers from identifying which virtual host a client is accessing. While traditional SNI exposes the hostname in plaintext during the TLS handshake, ESNI encrypts this information using a public key published in the DNS records.
To enable ESNI on your servers, you'll need:
- A web server that supports TLS 1.3 (ESNI requires TLS 1.3)
- Access to modify DNS records for your domain
- Clients that support ESNI (e.g., Firefox with network.security.esni.enabled set to true)
Here's how to configure ESNI on different server platforms:
NGINX Configuration
# Ensure you're using OpenSSL 1.1.1 or later
ssl_protocols TLSv1.3;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Enable ESNI (requires nginx built with TLS 1.3 support)
ssl_esni on;
ssl_esni_key /path/to/esni_keys;
Apache Configuration
<VirtualHost *:443>
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/key.pem
# ESNI configuration
SSLUseESNI on
SSLESNIKeyFile /path/to/esni.key
</VirtualHost>
You'll need to generate ESNI keys and publish them in your DNS records:
openssl genpkey -algorithm X25519 -out esni_private.key
openssl pkey -in esni_private.key -pubout -out esni_public.key
# Then extract the base64 encoded public key:
cat esni_public.key | openssl base64 -A
Publish your ESNI public key in a TXT record:
_esni.yourdomain.com. IN TXT "1 1 2 3600 20200101000000 20201231235959 base64-public-key"
Where:
- First "1" is the version
- Second "1" is the checksum algorithm (1 for SHA-256)
- "2" is the key exchange algorithm (2 for X25519)
- "3600" is the TTL
- The two timestamps define the validity period
- The last part is your base64-encoded public key
Use this command to verify your ESNI setup:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -tls1_3 -esni yourdomain.com -esnirr _esni.yourdomain.com
For clients to use ESNI, they must support it. In Firefox, enable it by:
1. Navigate to about:config
2. Set network.security.esni.enabled to true
3. Set security.tls.enable_0rtt_data to false (recommended)
If ESNI isn't working:
- Verify your DNS TXT record is properly formatted and published
- Ensure your server supports TLS 1.3
- Check that your OpenSSL version supports ESNI (1.1.1 or later)
- Verify client support (Firefox is currently the most reliable)
While ESNI improves privacy, remember:
- The DNS record containing the public key is still visible
- ESNI doesn't encrypt the entire handshake, just the SNI
- Rotate your ESNI keys regularly (monthly is recommended)