Name-Based Virtual Hosts with SSL using Apache2 on Ubuntu Lucid

It has now been a few years (2007) that SNI (Server Name Indication) has been introduced/supported in OpenSSL 0.9.8, but it has only been just last year that SNI was fully supported in Apache2 with version 2.2.12 released in July 2009. Now we can really having
multiple virtual hosts with different certificates on the same IP address! No need to buy any more IP addresses!

Introduction

This tutorial is mainly oriented to Ubuntu, but can also be applied to other distributions such as Debian.

The minimum requirements for SNI to work are Apache 2.2.12 (or higher) with OpenSSL 0.9.8g (or higher).

Make sure you already have your website(s) set up and running (non-SSL of course!) and listening on another port than 443 as we will use this port for SSL.

Installation of packages

We need to activate the Apache2 SSL module in order to serve websites over SSL:

sudo a2enmod ssl

Also, the ssl-cert package will allow us to create certificates in a few keystrokes:

sudo apt-get install ssl-cert

If you don’t have ssl-cert available in your distribution’s package manager, you can find it here: http://packages.debian.org/sid/ssl-cert

Creating certificates

We will now create a self-signed SSL certificate.

When using make-ssl-cert, both the certificate and the private key are generated and stored within the same file. The generated *.crt file needs to be kept somewhere safe on your disk, it is a good practice to move it to /etc/ssl/privateand use chmod 600 and chown root:root. It should be readable by root only!

sudo make-ssl-cert /usr/share/ssl-cert/ssleay.cnf \
/etc/ssl/private/mydomain.crt

It should ask you for a hostname, enter the exact domain name of the website (e.g. if you want to use https://www.myexampledomain.com then put www.myexampledomain.comas
hostname).

Enabling name-based SSL virtual hosts

Apache2 needs to know that our virtual hosts using SSL will be matched using a name-based matching rule (instead of IP-based) and also that it needs to listen for SSL connections on port 443.

Open the Apache2 ports config file, located at /etc/apache2/ports.conf and add:

NameVirtualHost *:443

It should look similar to this:

NameVirtualHost *:80
NameVirtualHost *:443

Listen 80


    Listen 443

Make surethere is Listen 443 somewhere in this file, in order to tell Apache2 to listen on this specific port for SSL connections.

Creating the virtual hosts configuration file

Important Note:
Note that not all browsers support SNI. For those without SNI support they will be redirected to the first SSL vhost defined (which is usually the first alphabetically in the /sites-enabled/ folder) in
the Apache2 configuration.
Also, it is good to know that in their browser, they will see the domain name that they typed in instead of the actual vhost’s domain name, as a consequence the certificate will not be validated as it will not match the domain shown in their browser. As an alternative you can use SSLStrictSNIVHostCheck, see note below.

The best thing to do is to copy the normal configuration file of your website (with normal http:// access) and add the SSL directives.

First, make a copy:

sudo cp /etc/apache2/sites-available/{mywebsite.conf,mywebsite_ssl.conf}

Then open the mywebsite_ssl.conf file, and add/modify the bold parts:


 ServerName www.myexampledomain.com 

 SSLEngine On
 SSLCertificateFile /etc/ssl/private/myexampledomain.crt 
 
 DocumentRoot /var/www/myexampledomain

Explanation:

*:443” along with ServerName define this configuration as a name-based virtual host.

SSLEngine On” enables SSL for this virtual host.

SSLCertificateFile”points to the certificate we created earlier.

Note:
Using SSLStrictSNIVHostCheckit will refuse non SNI capable browsers to access any website on your server using SSL.
This directive sets
whether a non SNI client is allowed to access a name based virtual host. If set to
on in the non default name based virtual host, non SNI clients are not allowed to access this particular virtual host. If set
to
on in the default name based virtual host, non SNI clients are not allowed to access any name based virtual host belonging to this IP / port combination. (http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#SSLStrictSNIVHostCheck)

Enabling the virtual host

We need to enable the virtual host, this is an important step which is often forgotten:

sudo a2ensite mywebsite_ssl.conf

Testing

Restart Apache2:

sudo service apache2 restart

This is time for a test, visit your website over SSL, make sure you prepend https:// to your domain name (for example https://www.myexampledomain.com)

Troubleshooting

If you cannot see your website using https you can dig into the Apache2 logs (located at /var/log/apache2/error.log) and search for [error] or [warn].

Also be certain to have activated/enabled all of the virtual hosts you want by typing sudo a2ensite yourdomain.conf and then reload or restart Apache2.

If you get a “ssl_error_rx_record_too_long” error, it can mean either SSL is not activated properly for this virtual host (check that there is SSLEngine On in your vhost config) or the virtual host configuration is not enabled
(“sudo a2ensite vhostconfigfile”).

Notes

If you already have your own certificates, you will want to use both SSLCertificateKeyFileand SSLCertificateFilein the virtual host configuration file because certificate issuers usually give
you two different files (one containing a private key and the other one containing the certificate).

It is important to be aware that some browsers do not support SNI and will not be able to access your virtual hosts.

Some browsers in mobile devices might not support SNI so be certain that your default SSL virtual host can provide some help or support to those users, like for example offering the option to switch back to regular non-SSL connection.

3 Replies to “Name-Based Virtual Hosts with SSL using Apache2 on Ubuntu Lucid”

  1. I have a mix of SSL and non-SSL sites setup this way on one VM. Yet when I access the sites without SSL configured I get the Untrused Connection prompt. How can I make it just not respond or give “Website not found” when someone tries to access a virtual host that does *not* have SSL setup?

Leave a Reply