Problem: You want to host all of your web development sites in ~/Sites, and you don’t want to fuck around with DNS and Apache configuration every time you start something new.
Solution: DNS wildcards and Apache Virtual Hosting!
The hard part: start by enabling BIND.
BIND is a domain name resolving system. It’s included in Mac OS X, but it isn’t turned on or configured by default. Odd.
$ sudo -s $ rndc-confgen > /etc/rndc.conf $ head -n 6 /etc/rndc.conf > /etc/rndc.key $ emacs /var/named/dev.zone
/var/named/dev.zone should be:
; BIND data file for dev sites
;
$TTL 604800
@ IN SOA dev. root.dev. (
2008101920 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS dev.
@ IN A 127.0.0.1
*.dev. 14400 IN A 127.0.0.1
$ emacs /etc/named.conf
Add this bit of content to /etc/named.conf after the line directory "/var/named";
forwarders {
208.67.222.222;
208.67.220.220;
};
Those are the OpenDNS servers. Substitute your own, add as many as your like, and use Google’s DNS if you want, but make sure you’re careful with the semicolons. I wasn’t, and it bit me in the ass.
While you’ve got named.conf open, add these lines above the zone "localhost" line:
zone "dev" IN {
type master;
file "dev.zone";
};
Again, be careful with the semicolons. BIND isn’t forgiving at all. If you mess it up, the syslog will contain lines like
2013-05-14 2:49:33.858 PM named[15397]: /private/etc/named.conf:39: missing ';' before '}'
2013-05-14 2:49:33.858 PM named[15397]: /private/etc/named.conf:53: missing ';' before 'zone'
Edit /System/Library/LaunchDaemons/org.isc.named.plist to enable the BIND daemon, by switching ‘true’ to ‘false’.
Launch the daemon:
sudo launchctl load /System/Library/LaunchDaemons/org.isc.named.plist
This should, in theory, be enough to get all the *.dev addresses pointed at the local machine, but it isn’t quite. Open up System Preferences.app and add 127.0.0.1 as a DNS entry for your internet connection. None of the documentation I saw mentioned this. It looks like the system won’t start actually using the local BIND system automatically.
The easy bit: configure Apache
Next up, configure Apache to respond to any request that matches *.dev/foo/bar.
Edit apache’s httpd.conf file and enable the virtual host include by uncommenting the include line:
# Virtual hosts Include /private/etc/apache2/extra/httpd-vhosts.conf
And then edit the httpd-vhosts.conf file. Comment out all the stuff that’s there (it’s useful as an example) and add the following:
NameVirtualHost 127.0.0.1
VirtualDocumentRoot /Path/to/Sites/%-2+
"%-2+" is magic: it means the part of the domain name before the last part. For foo.bar.dev it would be foo.bar.
Note that if you have Apache's mod_unique_id enabled you might be getting errors in Apache's log file that look something like this:
[Tue May 14 15:00:02 2013] [alert] (EAI 8)nodename nor servname provided, or not known: mod_unique_id: unable to find IPv4 address of "bernard"
Configuration Failed
Bernard is the local name of my computer. I added an entry in /etc/hosts for bernard, and everything worked out. Magic.
127.0.0.1 bernard
References:
- PPM's writeup - I had to add a couple of steps
- An old Mac OS X Hints article - still a bit relevant.