– Apache VirtualHost: Separating network and application data with mod_define for clean deployment –

Ever had the pleasure of supporting a development team in their efforts to reach deadlines and therewith smoothing out the deployment process? It can be a complex task when the deployment covers multiple servers at once. From a sysadmin point of view you are concerned with network and naming conventions of your web-, database- and possibly other servers.

The context

Nevertheless, you need to communicate with the developers about this without overloading them with network details. Practically a set of server names should be enough for their deployment configuration. Of course I’m primarily talking about framework based application deployment running on Django, Rails and so on.

When handling SSL only websites there’s the IP address per website restriction (not taking SNI into account). Then there’s the gray area; The configuration parts that are both server and application related. Doing an article on Apache 2.x trickery I’m talking about the VirtualHost setup, but there are others to consider like logrotation, cron vs. application framework jobs, etc.

Having peeked, this article indeed describes a setup that involves Apache and how to ease the work of the development team. Before taking of I’d like to add one more detail into the mix. For design reasons I consider it good practice to have a seperate IP to address a server besides the ones you use for your services as web, database, file uploads or any other. This separates traffic to your server for e.g. monitoring, backups, abuse filtering, security, etc. next to your regular service traffic.

Having such a clean setup, but also for security reasons, setting up Apache with 0.0.0.0:443 or *:443 doesn’t fit in my opinion (better explicit then implicit).

Having set the context I’ll get into the technical details.

The setup

As was written we need a ‘VirtualHost’ setup that is transparent to the developers but should contain all information for Apache to operate properly.  Besides necessary modules and what not the snippet below displays the minimal required configuration directives.

NameVirtualhost 1.2.3.4:443
Listen 1.2.3.4:443

<Virtualhost 1.2.3.4:443>

    # Your vhost config

</Virtualhost>

Note: I’m putting the listen statement in the virtualhost config file and not in Apache’s ports.conf to keep things contained with the application’s configuration. Here’s the first conflict because this would mean different configs in de developers codebase for every server they deploy on. We’ll resolve that in a minute.

 

Apache symlink intermezzo

More on keeping things contained along side your application, mainly for upscale portability, we put the file with Apache’s vhost config in an etc directory under the application codebase. E.g: [app basedir]/etc/apache.conf

Usually, with Apache, site configurations are stored in /etc/apache2/sites-available and they are enabled when symlinked to from /etc/apache2/sites-enabled.

When putting the vhost configuration under your app codebase you simply link from ‘sites-enabled’ to that location.

$ cd /etc/apache2/sites-enabled
$ ls -l
total 0
lrwxrwxrwx 1 root root   74 2011-05-04 19:47 www.example.com -> /home/appuser1/sites/www.example.com/config/etc/apache.conf
lrwxrwxrwx 1 root root   79 2011-05-04 19:48 www.other.com -> /home/appuser2/sites/www.other.com/config/etc/apache.conf
lrwxrwxrwx 1 root root   71 2011-06-10 15:22 another.other.com -> /home/appuser2/sites/another.other.com/config/etc/apache.conf

The thing to lookout for when running multiple apps: the symlink sourcename must be set different from the name ‘apache.conf’ otherwise you get a name conflict in the /etc/apache2/sites-enabled directory. This is done with the ‘ln’ command in de following manor:

$ cd /etc/apache2/sites-enabled
$ ln -s /home/appuser1/sites/www.example.com/config/etc/apache.conf www.example.com

Now that we know what goes where we can work on the relation between the IP adresses and the different applications or vhosts.

Installing the glue

We need mod_define for this, found here: mod_define. With this module we have the ability to set $variables within the Apache configuration files.

Installation is rather simple. Download it and run (as root):

$ apxs2 -i -a -c mod_define.c

Good chance the module is automatically enabled using the apxs2 command but that might depend on your distro. Otherwise you can either use a2enmod or simply symlink between /etc/apache2/mods-available and /etc/apache2/mods-enabled. The file your looking (linking) for contains the following:

$ cat /etc/apache2/mods-enabled/define.load
LoadModule define_module      /usr/lib/apache2/modules/mod_define.so

Enable the module linking it like so:

$ cd /etc/apache2/mods-enabled
$ ln -s ../mods-available/define.load

Note that your installed module, as configured in ‘define.load’, might end up elsewhere under ‘/usr/…. ‘ depending on your distro.

The glue in effect

Besides the seemingly complicated context it simply comes down to a list of variable names containing IP adress/port number combinations. The below example should explain this.

<IfModule define_module>
    # IP's are example public addresses
    Define bind_address_www_example_com 1.2.3.4:443
    Define bind_address_www_other_com 2.3.4.5:443
</IfModule>

After making sure the module is enabled we place the ‘vhost_bind_adresses.conf’ file in ‘/etc/apache2/conf.d’. After this file has been set up we can use the defined variables in our VirtualHost configuration. These are about the only thing that the development team should stick to (assuming the vhost file is included in their codebase). Considering the file wherein we defined the variables a vhost file looks like this:

Listen $bind_address_www_example_com
NameVirtualHost $bind_address_www_example_com

<VirtualHost $bind_address_www_example_com>

    ServerName www.example.com
    ServerAdmin webmaster@example.com

    LogLevel warn
    CustomLog /home/appuser1/sites/www.example.com/log/apache.access.log combined
    ErrorLog /home/appuser1/sites/www.example.com/log/apache.error.log

    DocumentRoot /home/appuser1/sites/www.example.com/

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/www.example.com.cert
    SSLCertificateKeyFile /etc/ssl/certs/www.example.com.key

    # <-- SNIP -->

</VirtualHost>

Note: As said, the Listen and NameVirtualHost directives are in de vhost file instead of the ports.conf.

The beauty of this setup is that we can shuffle our server configuration without any changes to the developers code base. Creating/deploying new apps simply means adding a variable to ‘vhost_bind_adresses.conf’ and updating the development team about the name.

Gotcha’s

Not much I can think of. If you agree on a variable name with the development team that is unambiguous, for instance: $bind_addr_www_domain_com there’s not much that can go wrong.

One more tip: Learn yourself to use apache2ctl -t after changing stuff because restarting Apache while having syntax errors results in only stopping Apache. Which in it’s turn causes already running websites being unavailable for your audience.

Any comments or questions are welcome.

GrtzG