Setting up a local resolver on macOS
Jan 3, 2020
For a good number of years I was using Basecamp’s Pow for local web development
and one of my favourite features was the in built local DNS resolver that meant
that *.dev
would resolve to 127.0.0.1
. This mean that I had a unique
hostname for every site I was building and running locally which I have found
incredibly useful.
Unfortunately Pow no longer sees active development (the GitHub repo has been archived) so I wanted to see if I could set up the same kind of local resolver on my Mac without using it.
It turned out to be pretty straightforward!
Note: We’re using .localhost
instead of .dev
because Google own the .dev
TLD and in 2017 they added an HSTS rule to Chromium that forces any .dev
domain to use HTTPS. As you can imagine, this is not ideal for local development
so web developers everywhere had to adjust their setups.
First of all we need to install Dnsmasq. This will handle the local name resolution. If you’re using Homebrew this is dead simple:
$ brew install dnsmasq
Then we need to configure it to resolve any domain name that ends in
.localhost
to resolve to 127.0.0.1
.
Uncomment the following line:
# /usr/local/etc/dnsmasq.conf
conf-dir=/usr/local/etc/dnsmasq.d
Add the following file to the Dnsmasq configuration directory:
# /usr/local/etc/dnsmasq.d/localhost
address=/.localhost/127.0.0.1
Start dnsmasq
as root (It needs to be running as root to be able to bind to
port 53):
$ sudo brew services start dnsmasq
Next we need to tell macOS about the local resolver.
Add the following file (You will need to do this as root
):
# /etc/resolver/localhost
nameserver 127.0.0.1
domain localhost
search_order 1
And voila! Any domain ending in .localhost
should now resolve to 127.0.0.1
.
We can test this with a ping:
$ ping foobar.localhost
PING foobar.localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.122 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.262 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.281 ms
So why is this useful?
That’s a very good question! Here’s some of the reasons I’ve found:
- If you’re developing an app that relies on a number of small services it can be useful to differentiate them by domain.
- It makes OAuth callback URL’s more readable.
- It’s useful for external services that require a domain name to authenticate. A good example of this is font services such as Typekit or Hoefler & Co.
- It just looks pretty up there in the URL bar!