Easy Catch-all DNS and VirtualHost on macOS

Written on 2013-08-21 • conversation (4) • Read in: 2′43″

I have two rules. Rule number one: do not repeat yourself. Second rule: use what you already have. Initializing web projects served via localhost did not comply to either of those rules. MAMP Pro or Anvil required extra software. Manipulation of hosts and httpd-vhosts.conf files required repeat work. So I tried to find a solution.

People running macOS Mavericks or later will need to install BIND via homebrew first.

I thought it would be much cooler if you could just make a project-name folder in your ~/Sites directory, surf to project-name.test and be done with it. No extra stuff required. Appears it is really simple to do that. All I did was follow these steps:

1. Generate rndc key

You need to generate an rndc key file in order for BIND to work:

$ rndc-confgen -a -c /usr/local/etc/bind/rndc.key

2. Edit BIND configuration

Edit /usr/local/etc/bind/named.conf and add the following test zone somewhere in between the similar-looking zone blocks:

zone "test" IN {
	type master;
	file "test.zone";
	allow-update { none; };
};

3. Make the test.zone file

Next step is to make and edit a test.zone file, as specified in the previous step.

$ cd /usr/local/var/named
$ touch test.zone

Now open up the empty /usr/local/var/named/test.zone file in your favourite text editor and add the following block:

$TTL  60
$ORIGIN test.
@      1D IN SOA  localhost. root.localhost. (
          45    ; serial (d. adams)
          3H    ; refresh
          15M    ; retry
          1W    ; expiry
          1D )    ; minimum
      1D IN NS  localhost.
      1D IN A  127.0.0.1
*.test. 60 IN A 127.0.0.1

What this basically does is say: resolve all domains in the .test zone to localhost.

4. Check your config files for errors

$ named-checkconf /usr/local/etc/bind/named.conf
$ named-checkzone test /usr/local/var/named/test.zone

If everything is right, the first command should output nothing. The second command should print OK on the last line.

5. Start BIND

Execute the following command to start BIND. This also makes sure BIND is always running, even after a reboot.

$ brew services restart bind

6. Add local host to your DNS servers.

Open System Preferences -> Network. Go to your current network Details… -> DNS and add 127.0.0.1 and :: to your list of DNS servers via the + sign.

7. Enable Apache Virtual Hosts

Open /etc/apache2/httpd.conf in your editor and search for Virtual Hosts or httpd-vhost. Uncomment (or add) the following line:

Include /private/etc/apache2/extra/httpd-vhosts.conf

8. Edit your Virtual Hosts configuration

Open /etc/apache2/extra/httpd-vhosts.conf in your text editor and add the following block beneath any present blocks:

<VirtualHost *:80>
  ServerAlias localhost *.test
  VirtualDocumentRoot /Users/yourusername/Sites/%1/public
  UseCanonicalName Off
  <Directory "/Users/yourusername/Sites/">
    Options FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>

Make sure to change yourusername to your actual username. If you have no clue what your username is, just run whoami from the command line.

I put the public part of my websites in a public/ folder (or symlink) inside the project folder. So: http://myproject.test/index.html will point to /Users/myusername/Sites/myproject/public/index.html.

9. Reload your BIND, DNS and Apache stuff

$ sudo rndc -p 54 reload
$ dscacheutil -flushcache
$ sudo apachectl graceful

10. Profit!

Oh and a tip if your web browser is giving you trouble when you surf to project-name.test: try appending a slash at the end. That way the browser recognises it as a domain and not as a Google search or something.

Extra Tip for xip.io

Got an extra tip via Matthias Mullie:

Now, similarly, add ServerAliases for *.xip.io and/or *.nip.io and you’ll have your projects available on all devices in that same network, via project.your-ip.xip.io

Conversation is closed

Conversations close automatically after six weeks. Feel free to contact me directly if you have feedback on this article.

Hey Xavier,

great that you’ve found a solution for this!
I haven’t tested this yet, but what about php or ruby projects?
There’s stuff like POW to do this stuff for you, but it can’t manage php projects.
I know there are some tools to serve static html files easily as well, but then it can’t manage php or ruby files.
Any ideas?

Thomas Deceuninck · Wed 21 Aug 2013 · #

@Thomas works great with PHP projects and I suspect ruby as well. The only real dependency here is Apache. But I suppose you could find a similar setup for nginx!

Xavier · Wed 21 Aug 2013 · #

Thomas/Xavier

If you want to combine this for both Ruby and PHP projects you could use this apache setup, but make sure you have passenger installed for apache. That way you won’t need to use pow (for rails) anymore.

See:
mod_passenger for apache
www.google.be/search…

Bauffman · Wed 28 Aug 2013 · #

@Bauffman thanks! Will have to try that on some future project.

Xavier · Sun 1 Sept 2013 · #