The web developer’s holy vhost trinity

When you’re developing web stuff, working with projects in path names (i.e. not at the top level of a domain) can be difficult (gets in the way of absolute links, rewrite rules etc), so you often need to set up a local apache virtual host, stick an entry in DNS and create an SSL certificate before you can get on with the serious business of doing some real work. This can get to be a drag when you do it a lot, but there is an extremely elegant solution that means you’ll never have to do it again…
Those three things that you need to do share a common feature that’s often missed: they all support wildcards. So here’s the trick.
First we need to create a DNS entry that points a whole subdomain at your local web server. This just needs a simple CNAME record like this (assuming that you already have an A record pointing at your machine):

dev.example.com. 10800 IN A 192.168.0.2
* 10800 IN CNAME dev.example.com.

Now the DNS will point <anyname>.dev.example.com at your machine without you having to define any other DNS entries. Note that if you do define other entries, they will take precedence over the wildcard.
Next you need to get apache to set up virtual hosts that conform to a pattern instead of just a fixed name. First you need to make sure you have the mod_vhost_alias module enabled in apache2 (on debian/ubuntu do a2enmod vhost_alias). Then in an apache virtual host container, you need something like this:

<VirtualHost *:80>
DocumentRoot “/Users/joeuser/Sites”
ServerName dev.example.com
ServerAlias *.dev.example.com
UseCanonicalName Off
VirtualDocumentRoot /Users/joeuser/Sites/%1
</VirtualHost>

This says that a request that matches the wildcard ServerAlias will have its first element used to define the document root for the site, so project1.dev.example.com will get mapped to /Users/joeuser/Sites/project1 and so on.
At this point you’ve already got the main feature – all you need to do to create a new project is make the folder in your sites folder, and whatever you name it is used as the vhost. You don’t need to touch apache or your DNS; it just works.
The icing on the cake is that when you need SSL, you can wildcard that too! In fact this is the only way that you can put multiple https sites on a single IP (because the SSL connection happens before it knows which site name is being requested – it can work here because we don’t care). Create a wildcard self-signed certificate, specifying *.dev.example.com as the common name, drop it into wherever you usually keep your certificates and keys, then tell the vhost about it:

SSLEngine On
SSLCertificateFile /etc/apache2/ssl/dev.example.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/dev.example.com.key

Now you can talk https to your vhosts too, and add new ones at will, again without having to touch any config at all. Now isn’t that nice?
The only thing I can think of that would make this even better is if someone would figure out the tweaks required to get bonjour to advertise the sites that are defined. Incidentally, if you develop on OS X and use VMWare Fusion or Parallels for testing in Windows, make sure you install bonjour for Windows, it works really well in that setup.
The syntax I’ve used is a bit of an odd mixture of linux and OS X config, but that’s just me. I’m sure you can figure it out.

4 Replies to “The web developer’s holy vhost trinity”

  1. Hey Marcus,

    nice post. We use one machine for all developers and currently have to handle a lot of vhosts. This is a good way to consolidate them. It would be even better if you could specify the developers username which points to the developers home directory, eg. (project1-trunk.enrico.dev.example.com).

    Any ideas?

    Kind Regards
    Enrico

  2. Other than by scripting the addition of an htpasswd username at the same time as you add a folder, I don’t see any way to do this. I guess you could use groups to assign them to multiple vhosts at once (which might allow you to give access to existing users without having to do anything), but you can’t wildcard passwords!

  3. Hey Marcus, i solved this issue.

    VirtualDocumentRoot /home/%2/web/%1

    “project1-trunk.enrico.dev.example.com” will now point to “/home/enrico/web/project1-trunk”.

Leave a Reply