CNAMEs and vhosts

Have you ever…

  • felt like just one web server isn’t quite cutting it?
  • wanted to alias servers on your home network so you can tell your friends a simple, memorable hostname, but keep the real name within your naming scheme?
  • gotten a steaming pile of code dumped on you that relies on requested hostname for important session information?

I actually ran into all three of these problems this week (the last was particularly nasty - PHP’s $_SERVER['host'] has no business being used the way I saw it).

In any event, there’s a relatively simple way around these issues with an Apache webserver and custom DNS resolver (this post uses dnsmasq, but BIND and the other major DNS daemons should have equivalents).

First, solving the hostname problem: tell your DNS resolver to provide a CNAME record for the aliased hostname that points to the target hostname. In dnsmasq, this is as simple as adding

cname=alias,target

to your config file. A couple caveats, though, especially if you’re in a mixed environment: some DNS clients on some systems will automatically append the local domain name (if your DNS server provides one) or, even stranger, the suffix .local to a hostname when resolving. So in a setup with a domain name, you should have three cname lines:

cname=alias,target
cname=alias.local,target
cname=alias.your.domain,target

When resolving this (using dig or similar), the CNAME record will provide a sort of DNS “redirect” to the real DNS A record with an IP.

Now for the server part. Apache comes with good vhost support in the form of a standard module; make sure that module (mod_vhost_alias) is installed and enabled in your config file, then define a vhost. In the simplest scenario, the vhosts will all listen on whatever addresses the server listens on, and will share port 80. All that remains is to provide a per-host document root and some basic contact info. Add the following to your httpd.conf:

<VirtualHost *:80>
    ServerAdmin you@example.com
    DocumentRoot "/htdocs/vhosts/target"
    ServerName target.your.domain
    ServerName target
    ServerName localhost
    ErrorLog "logs/vhosts/target/error.log"
    CustomLog "logs/vhosts/target/access.log" common
</VirtualHost>
<VirtualHost *:80>
    ServerAdmin you@example.com
    DocumentRoot "/htdocs/vhosts/alias"
    ServerName alias.your.domain
    ServerName alias
    ErrorLog "logs/vhosts/alias/error.log"
    CustomLog "logs/vhosts/alias/access.log" common
</VirtualHost>

Note that we have two separate document roots and log files, and that the vhost for “target” - the machine’s original hostname - retains the “localhost” alias in its vhost, so anyone on that machine querying http://localhost will get the right documents.