adding local DNS resolution for a custom top level domain on macOS using macports
Recently I was testing some applications in a local kubernetes installation running in minikube, especially the access via an ingress. For this I defined the ingress endpoints using a custom otherwise not existing top level domain to produce names like application1.foobar
or application2.foobar
. (The list of officially registered TLDs can be found at https://www.iana.org/domains/root/db).
Now in order to access these applications locally with an URL like http://application1.foobar/ I need to make the DNS resolution resolve this address to the IP address of my local minikube instance. This IP address can be retrieved with
minikube ip
which in this sample case returns 192.168.99.100
.
Now I could add the following line to my /etc/hosts file (which needs to be edited with sudo):
192.168.99.100 application1.foobar appiicaton2.foobar
but this is no nice solution as every time when a new application is added, the /etc/hosts file must be updated.
So instead I set up a local DNS server (using dnsmasq) which will resolve every call to an address with the .foobar
top level domain to our IP address. Then I reconfigure the local name resolution process of macOS to use this DNS resolver for .foobar
addresses – we want to keep the normal DNS resolution working.
Setting up dnsmasq
I am using MacPorts on my machines, other people prefer homebrew, both have dnsmasq as package available. The first step is the installation:
sudo port install dnsmasq
The next step is to edit the dnsmasq configuration, so that any request for an address in the .foobar
domain ist resolved to our ip address. The macports installation has its configuration file at /opt/local/etc/dnsmasq.conf, this file must be edited with sudo vi /opt/local/etc/dnsmasq.conf
and the following line must be added:
address=/foobar/192.168.99.100
After changing the configuration the dnsmasq service is started with sudo port load dnsmasq
. it can be stopped with the corresponding command sudo port unload dnsmasq
.
Now the local running DNS server will return our IP for any host in the foobar domain:
$ dig application1.foobar @localhost +noall +answer
; <<>> DiG 9.10.6 <<>> application1.foobar @localhost +noall +answer
;; global options: +cmd
application1.foobar. 0 IN A 192.168.99.100
$ dig adifferenthost.foobar @localhost +noall +answer
; <<>> DiG 9.10.6 <<>> adifferenthost.foobar @localhost +noall +answer
;; global options: +cmd
adifferenthost.foobar. 0 IN A 192.168.99.100
$ dig even.subdomains.are.working.foobar @localhost +noall +answer
; <<>> DiG 9.10.6 <<>> even.subdomains.are.working.foobar @localhost +noall +answer
;; global options: +cmd
even.subdomains.are.working.foobar. 0 IN A 192.168.99.100
Configuring the system resolving process
The next step is to reconfigure the nameserver resolution of macOS to use our local running dnsmasq when requests for our .foobar
domain come in. For this we need to add a file named foobar to the /etc/resolver directory (which may not yet exist on your machine) and add the following line:
nameserver 127.0.0.1
This can be done with:
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee -a /etc/resolver/foobar
After this you can check that this dns resolver is configured by issuing a scutil --dns
command, the output contains an entry like this:
resolver #19
domain : foobar
nameserver[0] : 127.0.0.1
flags : Request A records, Request AAAA records
reach : 0x00030002 (Reachable,Local Address,Directly Reachable Address)
or you could do a
$ ping application2.foobar
PING application2.foobar (192.168.99.100): 56 data bytes
64 bytes from 192.168.99.100: icmp_seq=0 ttl=64 time=0.559 ms
64 bytes from 192.168.99.100: icmp_seq=1 ttl=64 time=0.472 ms
$ ping any.hostname.you.can.think.of.foobar
PING any.hostname.you.can.think.of.foobar (192.168.99.100): 56 data bytes
64 bytes from 192.168.99.100: icmp_seq=0 ttl=64 time=1.156 ms
64 bytes from 192.168.99.100: icmp_seq=1 ttl=64 time=0.456 ms