Editor's note: After a winter hiatus, Rich Bowen is back with another column based on his conversations on the IRC channel #apache. This week Rich tackles SSL virtual hosts--if you think it's not possible to run them in Apache, think again. Rich is a coauthor of O'Reilly's Apache Cookbook.
#apache is an IRC channel that runs on the irc.freenode.net IRC
network. To join this channel, you need to install an IRC client (XChat, MIRC,
bitchx are popular clients) and enter the following commands:
/server irc.freenode.net /join #apache
In this week's article, I might seem to contradict myself, so it's important that you read the whole piece. If you stop too soon, you might not get the whole picture.
Over the last few months, I've seen a big increase in questions regarding SSL
and name-based virtual hosts (
vhosts). The official answer on this topic is that you
can't do that. Or, to quote fajita:
<DrBacchus> ssl vhosts
<fajita> When using SSL, each virtual host must have either its own IP address or its own port. Or both. or for details see http://httpd.apache.org/docs-2.0/ssl/ssl_faq.html#vhosts2
It's important to explain here that this is a limitation of SSL, not a limitation of Apache. That is, it's not that the Apache programmers were just so lazy that they never got around to this, but that SSL itself makes it impossible.
The reason that it's impossible lies in the way that SSL works. To grossly oversimplify, when a browser makes an SSL request (i.e., any URL starting with "https://"), the server sends the SSL certificate before it pays any attention to which URL you're requesting. Consequently, if you have multiple virtual hosts on that one IP address, you'll still always get the same certificate, which, in most cases, will not be the right one for the virtual host you requested. And when that happens, the browser pops up a scary warning message saying that the certificate does not match the web site you wanted to view.
Figure 1. SSL warning
There are several different possible solutions to this problem, but not all of them are acceptable to everyone.
The "right" thing to do is to run the other SSL site on another IP address. However, very few of us have access to an unlimited supply of IP addresses.
The "almost right" thing to do, failing that, is to run the other SSL site on
the same IP address, but using a different port. The problem with this method is that
users of the site will have to explicitly specify the port number in the URL, in
order to connect to the right site. For example, they might have to access
https://www.example.com:445/ in order to access a site running on port 445.
Since 443 is the default port for
https connections, it doesn't need to be
specified in the URL. This approach may be acceptable to many people,
particularly given that most SSL sites are arrived at via links (or redirects)
from other sites, rather than directly by the user typing in URLs.
<VirtualHost _default_:443> ServerName www.domain.com SSLEngine on SSLCertificateFile /path/to/www.domain.com.cert SSLCertificateKeyFile /path/to/www.domain.com.key DocumentRoot /www/vhosts/domain.com </VirtualHost> <VirtualHost _default_:444> ServerName www.domain.org SSLEngine on SSLCertificateFile /path/to/www.domain.org.cert SSLCertificateKeyFile /path/to/www.domain.org.key DocumentRoot /www/vhosts/domain.org </VirtualHost>
Notice that the two virtual hosts have different certificates specified, so that you get both authentication and encryption.
However, a great many people want to have multiple name-based virtual SSL hosts on the same port and same IP address. They're OK with the fact that the users will get a warning message every time they use the site. At this point, we let them in on a little secret. It is in fact possible to run name-based SSL virtual hosts. Sort of.
There are two aspects to SSL. The one that most people tend to think about is encryption. That is, all data to an SSL site is encrypted, and cannot be deciphered by a third party intercepting the data in the middle. The other one is authentication. That is, is the data you're receiving really coming from the host that you requested it from? When you pay for your SSL certificate, it is the authentication bit that you're paying for. You're paying for that company to verify that you are legally entitled to use that URL and the name under which the certificate will be signed. That way, when you connect to your bank, you can look at the certificate and be assured that you are indeed connecting to your bank, and not to some teenager scamming your money from his mother's basement.
When you run multiple SSL sites from a single certificate, you have the same level of encryption that you would have on any "correctly configured" SSL site. However, you completely forfeit any authentication ordinarily offered by SSL.
Stated differently, each time you connect to an SSL site, in addition to providing encryption, the browser checks to see that the certificate you are using is the "right" one. That is, that the web site name listed on the certificate is exactly the same web site to which you're connecting. If it's not, that's when you get the warning message. If you're getting the "wrong" certificate (that is, the certificate and the web site don't match) then there's a chance, although a very small one, that someone has intercepted your communication, and you're not actually talking to who you thought you were.
Assuming you followed that, we'll go on. If you didn't, read it again. It's a very important point.
The configuration examples following use the
mod_ssl module. If you're using
apache-ssl implementation of SSL, the concept is the same, but the
configuration will look somewhat different.
If you're persuaded that you want to run multiple SSL virtual hosts on the same IP address and port, this would be accomplished much like regular name-based virtual hosts, as follows:
NameVirtualHost *:443 <VirtualHost *:443> ServerName www.domain.com SSLEngine on SSLCertificateFile /path/to/www.domain.com.cert SSLCertificateKeyFile /path/to/www.domain.com.key DocumentRoot /www/vhosts/domain.com </VirtualHost> <VirtualHost *:443> ServerName www.domain.org SSLEngine on SSLCertificateFile /path/to/www.domain.com.cert SSLCertificateKeyFile /path/to/www.domain.com.key DocumentRoot /www/vhosts/domain.org </VirtualHost>
In other words, exactly the way you'd set up regular virtual hosts, except turning on SSL in each one.
You'll note in the above example that the same certificate file is specified
vhosts. This doesn't really matter, since you'll always get the same
certificate anyway. However, if you fail to set the certificate in one of the
vhosts, your server may fail to start, complaining that you didn't specify a
certificate file. Setting the same cert file in both places is the easiest way
Just so this is perfectly clear, you will get the warning message when you
access one of those
vhosts--all of them that don't match the certificate,
specifically. That is the price you pay for this functionality.
One final comment. Yes, this is annoying. And, yes, everyone is aware that it's annoying. Very smart people are actively working on a solution. The solution is called TLS upgrade. This is not the place to go into the technical details of how that works. But you should encourage your favorite browser vendor to implement this feature in future versions of their software.
See you on #apache.
Rich Bowen is a member of the Apache Software Foundation, working primarily on the documentation for the Apache Web Server. DrBacchus, Rich's handle on IRC, can be found on the web at www.drbacchus.com/journal.
Return to the Apache DevCenter.
Copyright © 2009 O'Reilly Media, Inc.