Zero-config development with Apache's VirtualDocumentRoot and xip.io

  • Written by Dave on Tuesday 9 October 2012

Running your own PHP development stack (a good guide for OSX Mountain Lion by @akrabat here) instead of running just (X|M)AMP is important for mostly one reason: You want to have complete control over everything concerning your development setup:

  • You want to be able to compile and load new extensions when necessary, which is a real pain in the ass to do on MAMP (Getting memcached loaded up is a good example).
  • You want general control; how many modules Apache loads, how many PHP versions you want to install, maybe you need an additional webserver like nginx or lighttpd, etc,...

You also want to be able to control your virtual host configuration. Many examples on the web show you how to achieve this with separate vhosts for each website, usually accompanied by an addition to your machine's /etc/hosts file.

A while back I was going through @tijsverkoyen's dotfiles, and discovered the lesser known VirtualDocumentRoot from Apache, which he applies brilliantly.

What is Apache's VirtualDocumentRoot directive?

From the official 2.2 documentation, Apache provides us with this description:

Dynamically configures the location of the document root for a given virtual host.

The keyword here is dynamically. Below you can see my entire vhost configuration:

# Use name-based virtual hosting.
NameVirtualHost *:80
UseCanonicalName Off

# ~/Sites/ vhost configuration - sends foo.bar.dev to ~/Sites/bar/foo
<VirtualHost *:80>
    VirtualDocumentRoot /Users/dave/Sites/%2/%1

    <Directory "/Users/dave/Sites">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

My config is setup so that all my projects have the following directory structure:

/Users/dave/Sites/<company>/<project>/

What that VirtualDocumentRoot does is map the above company and project to the %2 and %1 variables, respectively. So whenever I surf to http://foo.bar.dev, I end up in ~/Sites/bar/foo.

Great! That will save us a load of time generating and maintaining separate vhosts. But there is another step we need to complete before we have a true zero-config environment.

Who needs /etc/hosts when you have xip.io?

Every incoming domain should have a DNS rule set that redirects it to your localhost. This is Yet Another Configuration File we need to maintain. /etc/hosts itself does not support wildcard configurations, but there are a few options to work around this problem.

You could install a local DNS server that maps all incoming *.dev domains to 127.0.0.1. Popular choices include Bind and dnsmasq. These require some know-how in their setup however, so luckily a new option has become available recently.

A while ago, 37signals released xip.io, which provides exactly what it says; wildcard DNS for everyone. The best part is you don't even need to do anything. Following the example above, http://foo.bar.127.0.0.1.xip.io will resolve to ~/Sites/bar/foo on my local machine.

Obviously, this has a few caveats; you need a constant internet connection for your xip.io domains to be active. If this is important to you, I'd stick with Bind or dnsmasq to circumvent this.
People who have projects where the webroots differ; you can solve most issues by creating symlinks to the required webroots.

Another (unintended) positive is that your machine becomes publicly available on the network. If you're working with other devs in an office, they can surf to your projects by using your internal IP instead of localhost (example: http://foo.bar.10.1.11.165.xip.io).

Enjoy your zero-config setup!

About this b(ack)log

You can skim through the archive or subscribe to the RSS feed if you'd like to read more. Also, you can find me on GitHub.

If you have questions or remarks, or you want to say hi, you can drop me a line on Twitter.