Apache2 mixed ssl/non-ssl name-based virtual hosting


Ran into some problems earlier today in trying to bring up a SSL enabled virtual site along side my existing (non-ssl) name-based virtual sites. I needed the SSL enabled vsite for a installation of phpmysqladmin. I ran into a lot of documentations describing how to get the IP based setup working, but almost no info on name based setups. This how-to is geared towards Ubuntu Linux 8.04 LTS and higher. The very first thing you need to do is get your SSL certificate generated and setup. Without this step nothing works. I’m gonna show you self-signed certificate route. Your milage may vary…..Here is how:

openssl genrsa -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 9999 -in server.csr -signkey server.key -out server.crt

I did this on a semi-secure server in /tmp directory (I cd’d to /tmp before I issued the above commands). You might want to do this in roots homedirectory (or in /etc/ssl directory). The process above will — once completed — provide you with three files (server.crt, server.csr, server.key). You need to move server.crt to /etc/ssl/certs and move server.key to /etc/ssl/private. Once that’s done you can get rid of server.csr file.

Now that you have your SSL setup and for the sake of getting a flawless installation of phpmysqladmin, you need to get the mcrypt extension for php. Use the following command to get it installed (otherwise you keep getting a annoying warning on your login screen about mcrypt extension being missing).

sudo apt-get install php5-mcrypt

Now we need to get Apache all figured out. I’m going to assume here that you understand the relationship between /etc/apache2/sites-available and /etc/apache2/sites-enabled. Basically for each virtual site you need a conf file in sites-available folder with a appropriate symlink in sites-enabled folder pointing to the config file in sites-available. In my situation I had already created 7 non-ssl’d name-based virtual sites and needed to add a ssl’d name-based virtual site to my setup specifically for phpmysqladmin. Two things to keep in mind before we go on:

  • Apache’s decision as to whether or not the connection is SSL is made by port number (80 vs. 443) early in the process. If Apache decides that the connection is SSL (ie: port 443), it presents the site certificate.
  • For a non-SSL host, Apache 2 will default to the first VirtualHost it finds in its config, if it can’t match the incoming name to a specific virtual host. For an SSL virtual host, the rules are the same, except that it only considers the VirtualHosts on the SSL port.

First we need to enable SSL module in apache. You can do this manually if you like by creating 2 symlinks in /etc/apache2/mods-enabled pointing to /etc/apache2/mods-available/ssl.conf and /etc/apache2/mods-available/ssl.load OR you can use the command below:

a2enmod ssl

You also want to check the file /etc/apache2/ports and make sure it looks like this:

Listen aaa.bbb.ccc.ddd:80
<IfModule mod_ssl.c>
    Listen aaa.bbb.ccc.ddd:443
</IfModule>

Where aaa.bbb.ccc.ddd is the IP address of your server. This makes apache listen for non-ssl connections on port 80 and ssl connections on port 443.

Phew, okay theory apart, here is a simple recipe that got me going:

  1. In your “default” virtual host file at the top you should find the “NameVirtualHost *” directive and change it to say “NameVirtualHost *:80”. Then add “NameVirtualHost *:443” on the following line.
  2. Add a “default” SSL virtual host early in your default config by using “<VirtualHost *:443>”. You can decide whether this should return a 404 or do something useful. Mine simply returns a 404.
  3. All your Non-SSL VirtualHosts config files are probably set up as “<Virtual Host *>”. Change this to “<VirtualHost *:80>”.
  4. Create a Final config file for your SSL enabled virtual host. In my case this is the virtual host that presents phpmysqladmin interface. I’m including my config file here:
    <VirtualHost *:443>
        ServerName secure.site.com
        ServerAdmin admin@secure.site.com
    
        SSLEngine on
        SSLOptions +StrictRequire
        SSLCertificateFile /etc/ssl/certs/server.crt
        SSLCertificateKeyFile /etc/ssl/private/server.key
    
        # DocumentRoot: The directory out of which you will serve your
        # documents. By default, all requests are taken from this directory, but
        # symbolic links and aliases may be used to point to other locations.
        DocumentRoot /srv/www/htdocs/phpmyadmin
    
        # if not specified, the global error log is used
        ErrorLog /var/log/apache2/error_log
        CustomLog /var/log/apache2/access_log combined
    
        # don't loose time with IP address lookups
        HostnameLookups Off
    
        # needed for named virtual hosts
        UseCanonicalName Off
    
        # configures the footer on server-generated documents
        ServerSignature On
    
    
        # Optionally, include *.conf files from /etc/apache2/conf.d/
        #
        # For example, to allow execution of PHP scripts:
        #
        # Include /etc/apache2/conf.d/mod_php4.conf
        #
        # or, to include all configuration snippets added by packages:
         Include /etc/apache2/conf.d/*.conf
    
    
        # ScriptAlias: This controls which directories contain server scripts.
        # ScriptAliases are essentially the same as Aliases, except that
        # documents in the realname directory are treated as applications and
        # run by the server when requested rather than as documents sent to the client.
        #
        # This should be changed to whatever you set DocumentRoot to.
        #
        <Directory "/srv/www/htdocs/phpmyadmin">
        
    	#
    	# Possible values for the Options directive are "None", "All",
    	# or any combination of:
    	#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    	#
    	# Note that "MultiViews" must be named *explicitly* --- "Options All"
    	# doesn't give it to you.
    	#
    	# The Options directive is both complicated and important.  Please see
    	# http://httpd.apache.org/docs-2.0/mod/core.html#options
    	# for more information.
    	#
    	Options FollowSymLinks
        
    	#
    	# AllowOverride controls what directives may be placed in .htaccess files.
    	# It can be "All", "None", or any combination of the keywords:
    	#   Options FileInfo AuthConfig Limit
    	#
    	AllowOverride None
        
    	#
    	# Controls who can get stuff from this server.
    	#
    	Order allow,deny
    	Allow from all
        
        </Directory>
    
    </VirtualHost>
    
    <VirtualHost *:80>
        ServerName secure.site.com
        ServerAdmin admin@secure.site.com
    
        # don't loose time with IP address lookups
        HostnameLookups Off
    
        # needed for named virtual hosts
        UseCanonicalName Off
    
        # configures the footer on server-generated documents
        ServerSignature On
    
        Redirect Permanent / https://secure.site.com
    </VirtualHost>

Notice that I’m putting the SSL virtual host first and then create a “fake” non-SSL virtual server under the same name on port 80 that redirects you back to the secure site. Also note the SSL engine being turned on with appropriate paths to the certificates and keys we created earlier on. Make sure you also assign the virtual server the appropriate ServerName and ServerAdmin. Note also that the non-SSL “fake” Server does NOT contain DocumentRoot or anything like that.

That should do it. Stop and Start apache and you should be off to the races.


One response to “Apache2 mixed ssl/non-ssl name-based virtual hosting”

Leave a Reply