Apache, SSL and name-based virtual hosts

Apparently, the apache guys aren't too fond of this, so the documentation is rather poor.   Since it took a while to piece together from information on the web, I thought I'd preserve my effort.  The set up is that last week I needed to create a set of related servers on the net, specifically on an amazon EC2 instance.  Only 1 IP was available and so the options were:

  • Run each server on a separate port
  • Proxy each server under one main server URL (ex: http://nostacktrace.com/foo, http://nostacktrace.com/bar, etc..)
  • Proxy each server with a name-based virtual host (ex: http://foo.nostacktrace.com, http://bar.nostacktrace.com)

The name-based solution was by far the easiest to configure the individual back-end servers for.  It definitely was not clear that everything would cope will with being at "/foo" instead of "/".  Apache handles name-based virtual hosts fine.  Here's a basic example of how it could be configured so that foo.nostacktrace.com will be proxied to the server on port 8081 and bar.nostacktrace.com will be proxied to the server on port 8082. 

This is great, but I really needed all access to all sites to be SSL.  The problem is that we can't just directly switch to port 443.  Why?  Name-based virtual hosts require the host to be selected by an HTTP header, an HTTP header that won't be known until after SSL has been negotiated.  And, the server can't negotiate SSL with a client before it knows what server (and thus what SSL certificate) to use.  

The solution is to use a wildcard SSL certificate.  Ignoring the debate as to whether or not wildcards are a good or a bad thing, they are highly useful.  The idea is that instead of getting an SSL certificate for "www.nostacktrace.com", I can get one for "*.nostacktrace.com".  The web server can offer that certificate to any SSL request and then route the request to the correct name-based virtual host after the SSL connection is established.  As long as the virtual hosts all match the wildcard domain, all is well.  Since these were private servers, I created the SSL certificate myself, a task that I should also explain in a later post.

Creating the name-based virtual host configuration was then quite easy.  The common SSL configuration can be outside the virtual hosts blocks, and per-host configuration is in the virtual host blocks as before.  Note that I've added an SSLProxyEngine on in each host to make sure apache knows internally that it is SSL.  It can make a difference in some cases.

The last step was to make sure that I completely redirected port 80 HTTP traffic to HTTPS.  The port 80 virtual host configuration then becomes quite simple.

And that's all there is to name-based SSL virtual hosts.