Networking

Configure Apache to support multiple SSL sites on a single IP address

With Apache 2.2.12 and support for the SNI (Server Name Indication) extension to the SSL protocol, you can configure name-based HTTPS sites, just as you can name-based HTTP sites. Vincent Danen introduces the new Apache feature.

As the Apache Web server grows and matures, new features are added and old bugs are fixed. Perhaps one of the most important new features added to recent Apache versions (2.2.12, to be specific) is the long-awaited support for multiple SSL sites on a single IP address.

Traditionally, it was only possible to have an SSL-enabled Web site if it was bound to one particular IP address. This has caused a lot of grief and frustration because if you had only two IP addresses, you could only have two SSL-enabled sites.

On two IP addresses you can have any number of regular HTTP sites strung out across them both or bound to a single IP, but for each of these, only one HTTPS site. What made this even more frustrating is that if www.example1.com and www.example2.com were on the same IP and example1.com had an HTTPS site as well, going to https://www.example2.com/ would, in fact, take you to the equivalent of visiting https://www.example1.com/. This meant that most people who wanted HTTPS sites had to restrict one site (both HTTP and HTTPS variants) to a single IP address to avoid this type of confusion.

With Apache 2.2.12 and support for the SNI (Server Name Indication) extension to the SSL protocol, this has changed completely. Now you can configure name-based HTTPS sites, just as you can configure name-based HTTP sites. The bottom line is that the five IPs that you needed today to run five SSL sites can be reduced to one IP tomorrow (provided, of course, you use the newer Apache).

There are some prerequisites, however:

  • The server, obviously, must use Apache 2.2.12 or higher.
  • It must also use OpenSSL 0.9.8f or later and must be built with the TLS extensions option.
  • And Apache must be built against this version of OpenSSL as it will enable SNI support if it detects the right version of OpenSSL -- the version of OpenSSL that includes TLS extension support.

Finally, as far as browsers go, not every browser yet supports SNI, but the most popular browsers do, and some have for quite a while. This includes Firefox 2.0 or later, Opera 8.0 or later, Internet Explorer 7.0 or later (unfortunately, only on Vista), Google Chrome, and Safari 3.2.1 (unfortunately only on OS X 10.5.6 or later).

In practical terms, this means that for a serious e-commerce Web site or one that needs to have broad appeal, this solution won't work -- yet. Expect in the next year or so for more people to upgrade and more browsers to support SNI.

For testing purposes or for internal sites where you can have some say over client browser installation (and also considering that such old versions of Firefox support SNI), using SNI can be quite useful.

For configuration, here is an example of what to put in your Apache configuration file:

Listen 443

NameVirtualHost *:443

SSLStrictSNIVHostCheck off

<VirtualHost *:443>

DocumentRoot /srv/www/example1.com/

ServerName www.example1.com

...

</VirtualHost>

<VirtualHost *:443>

DocumentRoot /srv/www/example2.com/

ServerName www.example2.com

...

</VirtualHost>

What the above does is enable Apache listening to port 443 and turns on listening for virtual host requests on all IPs. The new keyword SSLStrictSNIVHostCheck is disabled, meaning we will not throw a 403 error if the client does not support SNI; instead, they will be redirected to the SSL site defined first (example1.com in the example), so be sure to define your default site first.

That is pretty much all there is to it. The largest hurdle here is the client browser support, but that will come in time. The Apache requirements and configuration, by contrast, are very simple and straightforward.

About

Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.

2 comments
Lunfa
Lunfa

Hi Jack, thanx for a great article. Setting SSLStrictSNIVHostCheck off did not help me, however. The second domain over https displays the certificate of the first domain. Any help/tips would be greatly appreciated! This is my ssl-enabled/00-default: NameVirtualHost *:80 NameVirtualHost *:443 SSLStrictSNIVHostCheck off DocumentRoot /var/www ServerName www.example1.com Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all ErrorLog /var/log/apache2/ex1/error.log RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R] # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog /var/log/apache2/ex1/access.log combined Alias /doc/ "/usr/share/doc/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128 JkMount /* ajp13_worker ServerAdmin info@example1.com DocumentRoot /var/www ServerName www.example1.com #SSL START SSLEngine On SSLCertificateFile /etc/apache2/ssl/crt/chost1.crt SSLCertificateKeyFile /etc/apache2/ssl/key/vhost1.key SSLRequireSSL On SSLVerifyClient optional SSLVerifyDepth 1 SSLOptions +StdEnvVars +StrictRequire #SSL END Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all ErrorLog /var/log/apache2/ex1/error.log RewriteEngine on RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R] # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog /var/log/apache2/ex1/access.log combined Alias /doc/ "/usr/share/doc/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128 JkMount /* ajp13_worker DocumentRoot /var/www ServerName www.example2.com Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all ErrorLog /var/log/apache2/ex2/error.log RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R] # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog /var/log/apache2/ex2/access.log combined Alias /doc/ "/usr/share/doc/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128 JkMount /* ajp13_worker DocumentRoot /var/www ServerName www.example2.com #SSL START SSLEngine On SSLCertificateFile /etc/apache2/ssl/crt/iop-doc.crt SSLCertificateKeyFile /etc/apache2/ssl/key/iop-doc.key SSLRequireSSL On SSLVerifyClient optional SSLVerifyDepth 1 SSLOptions +StdEnvVars +StrictRequire #SSL END Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all ErrorLog /var/log/apache2/ex2/error.log RewriteEngine on RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R] # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog /var/log/apache2/ex2/access.log combined Alias /doc/ "/usr/share/doc/" Options Indexes MultiViews FollowSymLinks AllowOverride None Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 ::1/128 JkMount /* ajp13_worker