Apache 2.2 SNI-Based HTTPS Redirection: Conditional SSL for Browser Compatibility


2 views

Running multiple HTTPS sites on a single IP with Apache 2.2 presents a unique challenge when dealing with legacy browsers. Server Name Indication (SNI) support becomes critical for proper virtual host routing, but forcing HTTPS for non-SNI clients would break their access completely.

While user-agent sniffing isn't perfect, it's the most practical solution for Apache 2.2 environments. Here's a comprehensive list of SNI-supporting browsers that should be redirected:

# Modern browsers with SNI support
BrowserMatch "MSIE [6-8]" !SNISupport
BrowserMatch "Opera/9.*" !SNISupport
BrowserMatch "Firefox/[1-2]" !SNISupport
BrowserMatch "Chrome/[1-9]" !SNISupport
BrowserMatch "Safari/[1-4]" !SNISupport
BrowserMatch "Android [1-2]" !SNISupport

Here's the complete virtual host configuration that implements conditional redirection:

<VirtualHost *:80>
    ServerName www.dummysite.com
    
    # Check for SNI-capable browsers
    BrowserMatch "MSIE [6-8]" !SNISupport
    BrowserMatch "Opera/9.*" !SNISupport
    
    # Redirect only SNI-capable browsers
    <If "!(env('SNISupport') =~ /^!/)">
        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    </If>
    
    # Standard HTTP configuration for non-SNI clients
    DocumentRoot /var/www/html
    # ... other HTTP configurations ...
</VirtualHost>

<VirtualHost *:443>
    ServerName www.dummysite.com
    SSLEngine on
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem
    
    # Enable HSTS only for SNI clients
    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains" env=SNISupport
    
    # HTTPS configuration
    DocumentRoot /var/www/html
    # ... other HTTPS configurations ...
</VirtualHost>

When implementing this solution:

  • Test thoroughly with various browser versions
  • Monitor your access logs for any unexpected behavior
  • Consider implementing a gradual rollout
  • Document this special configuration for future administrators

For more robust solutions consider:

1. Upgrading to Apache 2.4+ with better SNI handling
2. Using separate IPs for critical sites
3. Implementing a frontend proxy like Nginx

When running multiple SSL-enabled virtual hosts on a single IP address with Apache 2.2, Server Name Indication (SNI) becomes a critical requirement. The challenge arises when you need to implement HTTPS redirection while maintaining backward compatibility with older browsers that don't support SNI.

Instead of maintaining an exhaustive list of SNI-capable user agents, we can implement a more maintainable solution using Apache's mod_setenvif and mod_rewrite:


# Enable necessary modules
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule rewrite_module modules/mod_rewrite.so

# Define SNI-capable browsers using regex patterns
BrowserMatch "MSIE [6-8]" no_sni
BrowserMatch "Opera/[0-8]\." no_sni
BrowserMatch "Safari/[0-4]\." no_sni
BrowserMatch "Firefox/[0-2]\." no_sni
BrowserMatch "Chrome/[0-9]\." no_sni
BrowserMatch "Android [0-3]" no_sni

Here's a complete virtual host configuration that implements the conditional redirection:


<VirtualHost *:80>
    ServerName www.dummysite.com
    DocumentRoot /var/www/html
    
    # Set environment variable for non-SNI browsers
    SetEnvIf User-Agent ".*" have_sni
    SetEnvIf User-Agent "^$" !have_sni
    
    # Apply our browser matching rules
    SetEnvIfExpr "!reqenv('no_sni') && reqenv('have_sni')" should_redirect
    
    # Conditional rewrite rule
    RewriteEngine On
    RewriteCond %{ENV:should_redirect} 1
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
    
    # Standard HTTP configuration
    # ...
</VirtualHost>

<VirtualHost *:443>
    ServerName www.dummysite.com
    DocumentRoot /var/www/html
    
    SSLEngine on
    SSLCertificateFile /path/to/cert.pem
    SSLCertificateKeyFile /path/to/key.pem
    SSLCertificateChainFile /path/to/chain.pem
    
    # HSTS Header (only for SNI-capable browsers)
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" env=should_redirect
</VirtualHost>

For newer Apache versions (2.2.12+), you can use:


SSLStrictSNIVHostCheck on

This will cause Apache to refuse connections from non-SNI clients rather than serving them the default SSL virtual host.

Remember to:

  • Regularly update your browser matching patterns
  • Monitor your access logs for new non-SNI clients
  • Consider implementing a gradual phase-out plan as non-SNI browser usage declines

Use cURL to verify both scenarios:


# Test SNI-capable client
curl -v -H "User-Agent: Mozilla/5.0" http://www.dummysite.com

# Test non-SNI client
curl -v -H "User-Agent: Mozilla/4.0" http://www.dummysite.com