Working with Wild Card Domain Names while Developing

Old Internet Proverb:

It’s not DNS
It can’t be DNS
It was DNS

A recent project uses hostname based routing and generates hostnames on a supplied domain.

In production this is not too tricky (assuming you know how to configure your chosen DNS server), you just set up a wild card DNS entry to point to the host running the ingress reverse proxy.

For development things are a little trickier, especially if you are a bit of a road warrior/digital nomad wandering round place to place connecting your laptop to lots of different WiFi networks.

For a single hostname you can usually just stick an entry in your OS’s /etc/hosts file that will map the name to a given IP address, but you can’t do that with a whole domain. Also the project I’m working on is container based so we also have to be careful not to use 127.0.0.1 as the address for the ingress host, because that will resolve to the container’s local IP stack, rather than the loop back interface of the host machine.

The solution is to setup a DNS server that will respond with a single IP address for any hosts in the given domain. Luckily there is a package that can do this for use called dnsmasq.

You can use the address=/domain.name/ip.add.re.s configuration option to map as many domains as you would like to single IP addresses (as well as adding individual hostnames as normal).

For the example setups listed I’m going to use the domain example.com but it will work for anything.

On Linux I’m going to use the IP address 172.17.0.1 because this is the default address bound to the docker0 bridge interface. This is one of the addresses that ports mapped to containers get forwarded from, so will work for accessing the ingress proxy.

Ubuntu

Modern versions of Ubuntu use something called systemd-resolved which manages which DNS server to use (depending on how many interfaces you have connected to how many different networks), it also runs a caching system to try and reduce the number of lookups get done.

While this is very useful it does make doing what we want to do here a little trickier, but after a lot of messing around and testing the following works on Ubuntu 22.04 and I’m pretty sure will work on 20.04 as well.

sudo apt-get install dnsmasq
sudo echo "bind-interfaces" >> /etc/dnsmasq.conf
sudo echo "no-resolv" >> /etc/dnsmasq.conf
sudo echo "conf-dir=/etc/dnsmasq.d" >> /etc/dnsmasq.conf
sudo echo "address=/example.com/172.17.0.1" > /etc/dnsmasq.d/02-flowforge.conf
sudo service dnsmasq restart
sudo echo "DNS=127.0.0.1" >> /etc/systemd/resolved.conf
sudo echo "DOMAINS=~example.com" >> /etc/systemd/resolved.conf
sudo service systemd-resolved restart

This does the following steps:

  • Installs dnsmasq
  • Configures dnsmasq to not try and use the system DNS information to forward requests
  • To look in /etc/dnsmasq.d for extra config files
  • Adds a config file with the mapping of example.com to 172.17.0.1
  • Tells systemd-resolved to send all requests for example.com to dnsmasq listening in 127.0.0.1

MacOS

MacOS can work basically the same way as I’ve just described for Ubuntu. The only differences are that dnsmasq gets installed via HomeBrew, and we need to assign a phantom IP address to the loopback adapter because Docker on MacOS doesn’t have the same docker0 bridge interface we can use.

sudo ifconfig lo0 alias 10.128.0.1
brew install dnsmasq
echo "conf-dir=/opt/homebrew/etc/dnsmasq.d" >> /opt/homebrew/etc/dnsmasq.conf
echo "address=/example.com/10.128.0.1" > /opt/homebrew/etc/dnsmasq.d/ff.conf
sudo brew services start dnsmasq
dscacheutil -flushcache
sudo mkdir -p /etc/resolver
sudo tee /etc/resolver/example.com > /dev/null <<EOF
nameserver 127.0.0.1
domain example.com
search_order 1
EOF

These commands do the following:

  • Set 10.128.0.1 as an address bound to the lo0 loopback interface
  • Install dnsmasq
  • Tell dnsmasq to look in the /opt/homebrew/etc/dnsmasq.d directory for extra config files
  • Add a mapping from example.com to IP address 10.128.0.1
  • Set dnsmasq to run as a service
  • Tell the MacOS name system to send all queries for example.com to dnsmasq running on 127.0.0.1

Other options

There is another option which is good in a pinch for testing these sort of set ups.

The domain sslip.io has been setup to reply with the IP address found in the hostname. e.g.

  • 127.0.0.1.sslip.io resolves to 127.0.0.1
  • www.127-0-0-1.sslip.io resolves to 127.0.0.1
  • www.--1.sslip.io resolves to ::1
  • fe80--9a6e-9aca-57cc-eea3.sslip.io resolves to fe80::9a6e:9aca:57cc:eea3

You can find more details about sslip.io here and it includes a link to the source code you you can build and run your own if needed.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.