Apache - Server Name Indication (SNI)

Server Name Indication (SNI) is a feature that extends the SSL and TLS protocols to indicate what hostname the client is attempting to connect to at the start of the handshaking process. By doing so, it allows a server to present multiple certificates on the same IP address and port number (443) and hence allows multiple secure (HTTPS) websites to be served off the same IP address without requiring all those sites to use the same certificate.

This manual will cover setting up two sites with SSL: site1.examplesite.net and site2.examplesite.net. Both sites will be served by the same IP address but separate SSL certificates will be used for each one.

We will also set up an unsecured site, www.examplesite.net, for testing purposes. This site will be served from the same IP address as the two SSL enabled sites but will make use of port 80 instead of port 443.

Apache Web server 2.2.12+ with mod_ssl and OpenSSL enabled is required.

If Ubuntu 10.04+ or Fedora 10 is being used on the server, then the Apache and OpenSSL packages that come with these distributions already support SNI. If you are using Red Hat Enterprise Linux, CentOS 5.x, or Debian 5.x, Apache and OpenSSL may need to be compiled from source.

If you are compiling Apache then take note that SNI is only supported in Apache versions 2.2.12 and newer. OpenSSL 0.9.8f or newer is also needed for SNI.

Browser Compatibility

SNI compatible browsers are required on the client's side in order for SNI based servers to send the correct certificate. If a browser is not compatible, the client will be shown an untrusted certificate warning.

Take note that Internet Explorer (any version) on Windows XP does not support SNI. Recent versions of Internet Explorer on Windows Vista and Windows 7 do support SNI, along with recent versions of Firefox, Chrome, and Safari. More about SNI support.

Instructions

  1. Make sure mod_ssl is enabled in your Apache installation (either by uncommenting the necessary lines in httpd.conf or using "a2enmod" on Ubuntu or Debian). Most package installations of Apache will have mod_ssl enabled by default.
  2. You will also want to make sure that Apache is listening on port 443 (for secure connections) and use name-based virtual hosts on that port.
  3. There is an IfModule mod_ssl.c block in the main httpd.conf file, the ports.conf file, or in a mod_ssl-specific config file, depending on your Apache setup.
  4. Inside that block you will find the line:

    Listen 443

  5. In the same mod_ssl.c block also add:

    NameVirtualHost *:443

That is the only SNI-specific bit of configuration that needs to be done in order to tell Apache that it should use named virtual hosts on the secure port.

PLEASE NOTE: Since a virtual host is being set up on port 80 (www.examplesite.net), there should also be a line "NameVirtualHost *:80" elsewhere in your Apache configuration. On Ubuntu and Debian, look in ports.conf and for most other distributions look in httpd.conf.

Virtual Hosts

For this part of the manual, keep the sites in separate subdirectories of the "demo" user's home directories. Start by making directories for the domains:

    cd /home/demo

    mkdir -p public_html/www.examplesite.net/{public,private,log,cgi-bin,backup}

    mkdir -p public_html/site1.examplesite.net/{public,private,log,cgi-bin,backup}

    mkdir -p public_html/site2.examplesite.net/{public,private,log,cgi-bin,backup}

Next, proceed to the Apache configuration directory and set up the virtual host configurations.

Unsecured Site Configuration

Look at the configuration for the unsecured site:

<VirtualHost *:80>

   ServerName "www.examplesite.net"

   ServerAdmin webmaster@examplesite.net

   DocumentRoot /home/demo/public_html/www.examplesite.net/public

ErrorLog /home/demo/public_html/www.examplesite.net/log/error.log

LogLevel warn

CustomLog /home/demo/public_html/www.examplesite.net/log/access.log combined

    <Directory /home/demo/public_html/www.examplesite.net/public>

    Options Indexes FollowSymLinks MultiViews

    AllowOverride None

    Order allow,deny

    allow from all

    </Directory>

</VirtualHost>

That configuration will tell Apache that the Web site, "www.examplesite.net", will be served on port 80.

Secured Site Configuration

  • First Secured Site Configuration

Next, make a config for the first of the secure sites, site1.examplesite.net. The config looks similar to the "regular" virtual host, but site1.examplesite.net will be served on port 443 and include SSL configuration lines at the end:

    <VirtualHost *:443>
        ServerName "site1.examplesite.net" 
        ServerAdmin webmaster@examplesite.net 
        DocumentRoot /home/demo/public_html/site1.examplesite.net/public 
        ErrorLog /home/demo/public_html/site1.examplesite.net/log/error.log 
        LogLevel warn 
        CustomLog /home/demo/public_html/site1.examplesite.net/log/access.log combined 
        <Directory /home/demo/public_html/site1.examplesite.net/public>
            Options Indexes FollowSymLinks MultiViews 
            AllowOverride None 
            Order allow,deny 
            allow from all 
        </Directory> 
        SSLEngine On 
        SSLCertificateFile /var/www/certs/site1.pem 
        SSLCertificateKeyFile /var/www/keys/site1.key 
    </VirtualHost> 

 

Note that the certificate file is site1.pem and the key file is site1.key.

  • Second Secured Site Configuration

Similarly, the VirtualHost file for site2.examplesite.net would be:

<VirtualHost *:443>
        ServerName "site2.examplesite.net" 
        ServerAdmin webmaster@examplesite.net 
        DocumentRoot /home/demo/public_html/site1.examplesite.net/public 
        ErrorLog /home/demo/public_html/site2.examplesite.net/log/error.log 
        LogLevel warn 
        CustomLog /home/demo/public_html/site2.examplesite.net/log/access.log combined 
        <Directory /home/demo/public_html/site2.examplesite.net/public>
            Options Indexes FollowSymLinks MultiViews 
            AllowOverride None 
            Order allow,deny 
            allow from all 
        </Directory> 
        SSLEngine On 
        SSLCertificateFile /var/www/certs/site2.pem 
        SSLCertificateKeyFile /var/www/keys/site2.key 
    </VirtualHost> 

 

Use different certificates and key files for site2.examplesite.net, site2.pem, and site2.key.

With this setup, site2.examplesite.net is being served on port 443, just like site1.examplesite.net. If there is a single public IP address on the server it means the secure sites are sharing the same IP address and port. On a non SNI-based setup, this configuration would not work.

Test Pages

To finish the setup, make some index pages for each site in order to test them.

Create the index page for the unsecured site at:

/home/demo/public_html/www.examplesite.net/public/index.html

Add the following to the file:

    <html>
        <head><title>WWW Test</title></head> 
        <body>
                www.examplesite.net is working. 
        </body> 
    </html> 

 

The page for site1.examplesite.net should be located at:

/home/demo/public_html/site1.examplesite.net/public/index.html

The index page should be:

    <html>
        <head><title>Site1 Test</title></head> 
        <body>
                site1.examplesite.net is working. 
        </body> 
    </html> 

 

For site2.examplesite.net, the index page location should be:

/home/demo/public_html/site2.examplesite.net/public/index.html

The file should contain:

    <html>
        <head><title>Site2 Test</title></head> 
        <body>
                site2.examplesite.net is working. 
        </body> 
    </html> 

 

Now both sites need to be set up with their own document roots and certificates.

Enable the Web sites

Enable the Web sites by making sure the virtual host configurations are in the right place and enabling them if needed.

  • Restart the Apache Web Server
  • Restart Apache to apply the configuration changes.
  • Once it has restarted, make sure Apache is listening for both secure and normal connections with the "netstat" command. The "grep" at the end of the command looks for the process name:

sudo netstat -tnlp | grep apache

tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN  :9965/apache2

tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN  :9965/apache2

If the web server is listening only on port 80 and not on port 443, double check the config to make sure mod_ssl is installed and enabled.

The unsecure site should be available:

http://www.examplesite.net

If "www.examplesite.net is working." is visible, then Apache is running correctly.

Now visit both secure sites in an SNI-enabled browser to check the secure connections:

https://site1.examplesite.net

https://site2.examplesite.net

Check that the client indicates a secure connection (usually a "lock" symbol) and that the test index page is displayed. You can also check the certificate properties in your browser to make sure the two sites are using their respective SSL certificates.

This set-up was done with with the intention of sharing a single IP address for all sites. To keep things cleaner it is possible to use two IP addresses; one for all regular Web sites over http, and the other for all SSL-enabled Web sites.

SSLCheck

Our SSLCheck will examine your website's root and intermediate certificates for correctness and report any potential issues