Resolving SNI and HTTP Hostname Mismatch in Apache: SSL Performance Optimization Guide


1 views

When migrating WordPress sites to self-managed servers, many developers encounter this specific Apache warning:

[Error] Hostname example.com provided via SNI and hostname www.example.com provided via HTTP are different

This occurs when the Server Name Indication (SNI) in the TLS handshake doesn't match the HTTP Host header. In your case, clients are requesting example.com via SNI but the browser ultimately sends requests for www.example.com.

Your current Apache configuration likely has these characteristics:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAlias example.com
    SSLEngine on
    SSLStrictSNIVHostCheck off
    # SSL certificate paths...
</VirtualHost>

The performance degradation stems from Apache performing additional verification steps when SNI and HTTP hostnames mismatch. While SSLStrictSNIVHostCheck off prevents outright rejection, it doesn't eliminate the overhead.

Option 1: Canonical Hostname Enforcement

Force all traffic to use either www or non-www version consistently:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^example\.com [NC]
    RewriteRule ^(.*)$ https://www.example.com$1 [L,R=301]
</VirtualHost>

<VirtualHost *:443>
    ServerName www.example.com
    SSLEngine on
    # Ensure certificate covers both variants
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem
</VirtualHost>

Option 2: Dual SSL VirtualHosts

Create separate virtual hosts for each hostname variant:

<VirtualHost *:443>
    ServerName www.example.com
    SSLEngine on
    # SSL configuration for www
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    # SSL configuration for non-www
</VirtualHost>

Option 3: Wildcard Certificate Implementation

For maximum flexibility with subdomains:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias *.example.com
    SSLEngine on
    SSLCertificateFile /path/to/wildcard.crt
    SSLCertificateKeyFile /path/to/wildcard.key
</VirtualHost>

After implementing the solution, test SSL handshake times:

openssl s_time -connect example.com:443 -www / -new -servername example.com
openssl s_time -connect www.example.com:443 -www / -new -servername www.example.com

Compare results before and after the fix to quantify performance improvements.

Ensure these settings in wp-config.php match your SSL configuration:

define('WP_HOME','https://www.example.com');
define('WP_SITEURL','https://www.example.com');

And update the siteurl and home options in the WordPress database:

UPDATE wp_options SET option_value = 'https://www.example.com' WHERE option_name IN ('siteurl', 'home');

When you see the error [Error] Hostname example.com provided via SNI and hostname www.example.com provided via HTTP are different, this indicates a fundamental mismatch between how your server identifies itself during different phases of the HTTPS handshake process.

# Typical error pattern in Apache logs
[ssl:error] [pid 12345] Hostname example.com provided via SNI 
and hostname www.example.com provided via HTTP are different

The performance degradation occurs because Apache has to perform extra validation steps when it encounters this mismatch. Each TLS handshake becomes more computationally expensive as the server tries to reconcile the conflicting host information.

Your current setup likely has these characteristics:

# Port 80 VirtualHost
<VirtualHost 192.0.2.1:80>
    ServerName www.example.com
    ServerAlias example.com
    # ... other config
</VirtualHost>

# Port 443 VirtualHost
<VirtualHost 192.0.2.1:443>
    ServerName www.example.com
    ServerAlias example.com
    SSLEngine on
    SSLStrictSNIVHostCheck off
    # ... SSL certificate paths
</VirtualHost>

The issue stems from how modern browsers handle SNI (Server Name Indication) versus traditional HTTP host header processing. When a client connects:

  1. During TLS handshake: Provides example.com via SNI
  2. After encryption: Sends www.example.com in HTTP Host header

Implement one of these approaches:

Option 1: Standardize Hostnames

# Force canonical hostname in both vhosts
<VirtualHost *:80>
    ServerName www.example.com
    ServerAlias example.com
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
    RewriteRule ^(.*)$ https://www.example.com$1 [L,R=301]
</VirtualHost>

Option 2: Match SNI Exactly

# Modify your SSL vhost to prioritize the non-www version
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    SSLEngine on
    # Certificate files should cover both variants
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem
    SSLCertificateChainFile /path/to/chain.pem
</VirtualHost>

Option 3: Upgrade Configuration

For Apache 2.4+, consider using:

SSLStrictSNIVHostCheck on
ServerName example.com
ServerAlias www.example.com

After implementing the fix, test with:

ab -n 100 -c 10 https://www.example.com/
openssl s_client -connect example.com:443 -servername example.com
  • Ensure your SSL certificate covers both example.com and www.example.com
  • Check for mixed content warnings in browser developer tools
  • Verify DNS records have proper CNAME/ALIAS configurations