Apache SSL Vhosts and Default Vhosts Behavior

Context

I like to have things well compartmentalized :)

With this said, when I bought the domain andrecardoso.eu I decided to create sub-domains as well, each for a different purpose. So, I created dev.andrecardoso.eu and blog.andrecardoso.eu.

Of course, I’ve put my modest machine, a VPS, serving all the domains with Apache. As I like compartmentalized things, I used different named virtual hosts (defined in different files) to serve each of the domains. I have only one IP so, of course, Apache is serving the requests based on the Server Name present on the http request:

# /etc/apache2/ports.conf
NameVirtualHost 192.168.0.1:80
Listen 80
##################################
# /etc/apache2/sites-available/andrecardoso.eu
<VirtualHost 192.168.0.1:80>
    ServerAdmin admin@mail.com
    ServerName andrecardoso.eu
    ServerAlias www.andrecardoso.eu
    DocumenRoot /var/www/andrecardoso.eu/
    ...
    ...
##################################
# /etc/apache2/sites-available/blog.andrecardoso.eu
<VirtualHost 192.168.0.1:80>
    ServerAdmin admin@mail.com
    ServerName blog.andrecardoso.eu
    DocumenRoot /var/www/blog.andrecardoso.eu/
    ...
    ...
##################################
# /etc/apache2/sites-available/dev.andrecardoso.eu
<VirtualHost 192.168.0.1:80>
    ServerAdmin admin@mail.com
    ServerName dev.andrecardoso.eu
    DocumenRoot /var/www/dev.andrecardoso.eu/
    ...
    ...

These files allow me to keep things well organized, and facilitate the maintenance. Each vhost has it’s own set of rules…

SSL

I wanted to protect my dev.andrecardoso.eu domain with SSL. So, I basically followed the steps described in Ubuntu documentation wiki. This was fairly easy. Of course, I used a self-signed certificate, instead of buying one to some Certificate Authority.

# enable ssl in apache2
sudo a2enmod ssl
# generate your keys
sudo openssl genrsa -des3 -out apache_server.key 1024
# generate a certificate request
sudo openssl req -new -key apache_server.key -out apache_server.csr
# create the certificate (self-signed) valid for 2 years
sudo openssl x509 -req -days 730 -in apache_server.csr -signkey apache_server.key -out apache_server.crt
# copy certificate and keys
sudo cp apache_server.key /etc/ssl/private/
sudo cp apache_server.crt /etc/ssl/certs/

With this done, I need now to change my dev.andrecardoso.eu Virtual Host, enabling SSL.  As we are now listening on 443 port (SSL) we have also to create a new Listen directive in ports.conf. The final configuration is shown below:

# /etc/apache2/ports.conf
NameVirtualHost 192.168.0.1:80
Listen 80
<IfModule mod_ssl.c>
 # SSL name based virtual hosts are not yet supported, therefore no
 # NameVirtualHost statement here
 NameVirtualHost 192.168.0.1:443
 Listen 443
</IfModule>
###########################
# /etc/apache2/sites-available/dev.andrecardoso.eu
<VirtualHost 192.168.0.1:80>
    ServerAdmin admin@mail.com
    ServerName dev.andrecardoso.eu
    DocumenRoot /var/www/dev.andrecardoso.eu/
    # SSL enabled vhost
    SSLEngine on
    SSLOptions +StrictRequire
    SSLCertificateFile    /etc/ssl/certs/apache_server.crt
    SSLCertificateKeyFile /etc/ssl/private/apache_server.key
    ...
    ...

This should work :)

Server Names, redirecting, default vhosts…

I  had a problem with the configuration above:

  • If I type http://dev.andrecardoso.eu/ I get the contents served by andrecardoso.eu vhost
  • If I type https://andrecardoso.eu/ I get the contents served by dev.andrecardoso.eu vhost, but the url remains https://andrecardoso.eu/

Ideally:

  • If I type http://dev.andrecardoso.eu/ I want to be redirected to https://dev.andrecardoso.eu/, and get the contents served by dev.andrecardoso.eu vhost
  • If I type https://andrecardoso.eu/ I want to be redirected to https://dev.andrecardoso.eu/, and get the contents served by dev.andrecardoso.eu vhost

Some background

When using named virtual hosts, Apache analyzes the Server Name in the http request. Then, he scans the virtual hosts blocks available for the port on which the request was made and the corresponding ServerName directive. If one matches, he uses that configuration to reply to the http request.

What happens when the name does not match to any vhost?

:) The first Virtual Host block found is used. Let’s call this the default Virtual Host.

The order, first or last Virtual Host found, depends, of course, on the names of the files on which they are defined. So you may create a file named 0default, for example, containing a Virtual Host definition for when everything else fails.

With this in mind, and using mod_rewrite we can cover the first of my objectives.

Problem

Ok.

I write http:dev.andrecardoso.eu, Apache scans the vhosts available on port 80, none is found. He defaults to the one defined in the file /etc/apache2/sites-available/0default and the rules defined there make a redirection to https://dev.andrecardoso.eu. Nice.

We can apply the same logic when we’re writing https://andrecardoso.eu/ and want to be redirected to https://dev.andrecardoso.eu/, if we create another default vhost listening on port 443:  no matching Server Name is found, apache defaults to the first found, and applies our rules of redirection…simple.

But it does not work, unless you have apache version 2.2.12 or later.

As it is explained here and here, when using SSL, the server gets no Server Name field in the request, so has no way of deciding which Virtual Host to use. Also, apache lets you define multiple SSL virtual hosts, raising no configuration erros, but, in my experience, you end up getting something like “SSL received a record that exceeded the maximum permissible length.” when trying to access the site.

So, the attempt to define a default SSL vhost, fails and my second objective remains unreached.

Please let me know if I’m doing something wrong :)

My final configuration is below:

# create file /etc/apache2/sites-available/0default
<VirtualHost 192.168.0.1:80>
 RewriteEngine   on
 RewriteCond     %{SERVER_NAME} ^dev.andrecardoso.eu$
 RewriteRule     ^(.*)$ https://dev.andrecardoso.eu$1 [L,R]
</VirtualHost>
#######################
# enable site
sudo a2ensite 0default
# restart apache
sudo /etc/init.d/apache2 restart

Consulted Material

Spread the word...
  • Twitter
  • Facebook
  • del.icio.us
  • Google Bookmarks
  • StumbleUpon
  • Digg

Post a Comment

Your email is never published nor shared. Required fields are marked *

-->

Page optimized by WP Minify WordPress Plugin

Miscellaneous is Digg proof thanks to caching by WP Super Cache