Skip to main content

Getting started with DNSMasq for local development

Submitted by daniel on

Typically it is not uncommon to use yours hosts file to redirect network traffic on your local machine to point to your local environment where appropriate. That works pretty well for most circumstances however it can become a little tiresome if you are managing a large number of projects and quickly your hosts file can become quite long and unwieldy.

One alternative to using your hosts file is to use a local dns server. One such option is DNSMasq.

dnsmasq is free software providing Domain Name System (DNS) caching, a Dynamic Host Configuration Protocol (DHCP) server, router advertisement and network boot features, intended for small computer networks.[4][5]

dnsmasq has low requirements for system resources,[6][7] can run on LinuxBSDsAndroid and macOS, and is included in most Linux distributions. Consequently, it "is present in a lot of home routers and certain Internet of Things gadgets"[4] and is included in Android.[5]

https://en.wikipedia.org/wiki/Dnsmasq#cite_note-ars-5

Choosing a Domain suffix

There are a plethora of domain suffixes available. For many years I used .dev tld for local development. I have also seen the use of .com and .co.uk etc, However as .dev is now a tld owned by Google and is treated much like any other tld domain by browsers. Since 2017 Firefox and Chrome force the use of https by default on these top level domains , which will mean that you will have an additional step of setting up a self signed certificate in order to work in these browsers, a common requirement for most web development teams these days as part of the software development lifecycle and release process is to check how a new feature or bug fix will perform in these browsers and resolve any issues etc before being released.

ICANN/IANA has created some Special-Use domain names which are meant for special technical purposes. ICANN/IANA owns all of the Special-Use domain names

  1. .example - Not installed as a domain name, but usable in text as an example. example.com, example.net and example.org are also reserved for this purpose but are active sites.
  2. .invalid - Not installed as a domain name, but usable in testing as a domain which wouldn't work.
  3. .local Local network
  4. .localhost Points back to own computer
  5. .onion Connection to the Tor network
  6. .test Meant for testing DNS 

https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains#I

That said said when setting up a domain name locally why ot just use one that is reserved or owned by someone already. I use:

  1. .internal

Installing DNSMasq 

So what I plan to do is show the steps for setting up and configuring DNS masq locall on a Mac. One of the easiest ways is to install on the Mac is with Home Brew:

# Update your homebrew installation
brew up
# Install dnsmasq
brew install dnsmasq

Setting up DNSMasq 

As the instructions suggest, do the following.

$ mkdir -p /usr/local/etc/
$ cp /usr/local/opt/dnsmasq/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf

Setup Dnsmasq to auto start on reboot.

$ sudo cp -fv /usr/local/opt/dnsmasq/*.plist /Library/LaunchDaemons
$ sudo chown root /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist

Start Dnsmasq now and accept the warning. 

$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist

Stop/Start Dnsmasq

The following commands show how to stop and start Dnsmasq. This must be done after any configuration changes are made.

$ sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist

Configuring Dnsmasq

Now that you have Dnsmasq installed and running, it’s time to configure it! The configuration file lives at /usr/local/etc/dnsmasq.conf by default, so open this file in your favourite editor.

One the many, many things that Dnsmasq can do is compare DNS requests against a database of patterns and use these to determine the correct response. I use this functionality to match any request which ends in .internal and send 127.0.0.1 in response. The Dnsmasq configuration directive to do this is very simple:

address=/internal/127.0.0.1

Insert this into your /usr/local/etc/dnsmasq.conf file (I put it near the example address=/double-click.net/127.0.0.1 entry just to keep them all together) and save the file.

You may need to restart Dnsmasq to get it to recognise this change. Restarting Dnsmasq is the same as any other service running under launchd:

sudo launchctl stop homebrew.mxcl.dnsmasq
sudo launchctl start homebrew.mxcl.dnsmasq

You can test Dnsmasq by sending it a DNS query using the domain internet groper utility aka as dig. Pick a name ending in internal (or whatever your preference) and use dig to query your new DNS server:

dig testing.testing.one.two.three.internal @127.0.0.1

You should get back a response something like:

;; ANSWER SECTION:
testing.testing.one.two.three.internal. 0 IN	A	127.0.0.1

Configuring OS X

Now that you have a working DNS server you can configure your operating system to use it. There are two approaches to this:

  1. Send all DNS queries to Dnsmasq.

  2. Send only .internal queries to Dnsmasq.

The first approach is easy – just change your DNS settings in System Preferences. I.e. set 127.0.0.1 as a DNS server

There is Another Way

It is worth knowing that there is an alternative way to configure DNSMasq.

The second approach involves editing /etc/resolv.conf which controls the way DNS queries are performed, including the default server to use for DNS queries (this is the setting that gets set automatically when you connect to a network or change your DNS server/s in System Preferences).

#
# macOS Notice
#
# This file is not consulted for DNS hostname resolution, address
# resolution, or the DNS query routing mechanism used by most
# processes on this system.
#
# To view the DNS configuration used by this system, use:
#   scutil --dns
#
# SEE ALSO
#   dns-sd(1), scutil(8)
#
# This file is automatically generated.
#
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 10.230.56.145
nameserver 172.16.161.22

Here we can see that the /etc/resolv.conf matches the entries from the system control panel.

Mac OS 10.15 also allows you to configure additional resolvers by creating configuration files in the /etc/resolver/ directory. This directory probably won’t exist on your system, so your first step should be to create it:

sudo mkdir -p /etc/resolver

Now you should create a new file in this directory for each resolver you want to configure. Each resolver corresponds – roughly and for our purposes – to a top-level domain like our dev. There a number of details you can configure for each resolver but I generally only bother with two:

  • the name of the resolver (which corresponds to the domain name to be resolved); and
  • the DNS server to be used.
$ ls -al
total 64
drwxr-xr-x@  10 root  wheel   320 24 Oct  2019 .
drwxr-xr-x  151 root  wheel  4832 18 Nov 23:58 ..
-rw-r--r--    1 root  wheel    21 24 Oct  2019 digital
-rw-r--r--@   1 root  wheel    21 26 Apr  2018 internal
-rw-r--r--    1 root  wheel    21 24 Oct  2019 local
-rw-r--r--    1 root  wheel    21 24 Oct  2019 local2
-rw-r--r--    1 root  wheel    21 24 Oct  2019 localhost
-rw-r--r--@   1 root  wheel    21 28 Sep  2018 test
-rw-r--r--@   1 root  wheel    21 26 Apr  2018 vbox

each one of these entries looks like this

nameserver 127.0.0.1

To create a new file with the same name as your new top-level domain (I’m using dev, recall) in the /etc/resolver/ directory and add a nameserver to it by running the following commands:

sudo tee /etc/resolver/internal >/dev/null <<EOF
nameserver 127.0.0.1
EOF

Notice the use of the tee command. The tee utility copies standard input to standard output, making a copy in zero or more files. The output is unbuffered.

Here internal is the top-level domain name that I’ve configured Dnsmasq to respond to and 127.0.0.1 is the IP address of the server to use.

Once you’ve created this file, OS X will automatically read it and you’re done. My /usr/local/etc/dnsmasq.conf file looks like this

listen-address=127.0.0.1
address=/.internal/127.0.0.1
address=/.localhost/127.0.0.1
address=/.local/127.0.0.1
address=/.dev/127.0.0.1
# keep nameserver order of resolv.conf
strict-order

conf-file=/Users/danlobo/.config/valet/dnsmasq.conf

Testing

Testing you new configuration is easy; just use ping check that you can now resolve some DNS names in your new top-level domain.

ping -c 1 www.duckduckgo.com
# Check that .internal names work
ping -c 1 this.is.a.test.internal
ping -c 1 iam.the.walrus.internal

You should see results that mention the IP address in your Dnsmasq configuration like this:

PING iam.the.walrus.internal   (127.0.0.1): 56 data bytes

You can now just make up new DNS names under .internal whenever you please and they will automatically route to localhost if there is something to point to, i.e. a virtual machine

References

https://passingcuriosity.com/2013/dnsmasq-dev-osx/

https://oracle-base.com/articles/misc/dnsmasq-for-simple-dns-configurations-mac-osx

Add new comment

Filtered HTML

  • Web page addresses and email addresses turn into links automatically.
  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.