Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Deploy Your Own DNS Server With Docker

DNS

This is a quick tutorial on how to deploy your own DNS service easily through Docker. Having a DNS server is an extremely good idea if you are a Linux enthusiast or a developer. It's much easier to remember names than IP's and having one location that maps all the IPs to hostnames is extremely useful. Because it is deployed through docker, you can use the Linux OS of your choice.

Steps

If you haven't already, install docker on the host server

Create a directory called dnsmasq.hosts in your home folder.

Create a file in that folder called hosts and fill it with all the hostnames on your network like below:

The file can actually have any name, but hosts makes the most sense

Update the hosts /etc/network/interfaces file so that dns-nameservers option points to the hosts own public IP that it wants to answer requests on. It is a good idea to put in a secondary normal DNS as well for when your new DNS service is not running.

This results in both the host and any other docker containers deployed on the host to utilize the DNS service you just deployed. However, if you want the host to ignore the DNS service, but keep the docker containers using it, then keep the dns-nameservers option set to 8.8.8.8 and just update the /etc/default/docker file with the option

DOCKER_OPTS="--dns $MY_SERVER_IP"

Copy the following lines into a script called start-dns-container.sh and execute it with BASH:

#!/bin/bash
# Set this to whatever NIC  you wish to respond to requests on. For Debian systems this will likely
# be "eth0" or "eth1", but on Ubuntu systems, it is likely to be something like "enp2s0".
NIC=""

name="dns-server"

if [ -z "$NIC" ]; then
    echo "You need to set your NIC variable"
    exit 1
fi

MY_IP=$(ip addr | grep $NIC | grep inet | cut -d/ -f1 | awk '{ print $2}')

SCRIPT=$(readlink -f "$0")
SCRIPTPATH=$(dirname "$SCRIPT")

docker kill $name
docker rm $name

/usr/bin/docker run \
  -v="$SCRIPTPATH/dnsmasq.hosts:/dnsmasq.hosts" \
  --name=$name \
  -p="$MY_IP":53:5353/udp \
  --restart=always \
  -d programster/dnsmasq

I used to use the sroegner/dnsmasq image, but that wasn't being maintained so I have built my own and configured it automatically update the repository daily.

Change NIC=eth0, eth1, or enpXsXto (this may be a private networking NIC rather than the Internet facing one)

Thats it! You now have an incredibly basic DNS "server" setup to answer requests.

You must restart the docker container whenever you make a change to the dnsmasq.hosts/hosts file for the changes to take effect. You can do this by running: sudo docker stop $CONTAINER_ID followed by: sudo docker start $CONTAINER_ID

Prevent DHCP Overriding Your Nameserver

If you're doing this on a local home network, chances are that your router is set to provide your computers with dynamic IP's and nameservers. Even if you set a static IP, your server will still grab the nameserver. This will result in your /etc/resolv.conf file having the router's specified nameserver first, which means that your server will not use the DNS system you just set up. Worse yet, this will reset every time the network restarts or you reboot the server.

To prevent this from happening, simply update the DHCP configuration on the server at /etc/dhcp/dhclient.conf, and uncomment/update the following line:

prepend domain-name-servers [YOUR DNS IP HERE];

Alternatively, you could just update your router/dhcp provider's setting for the nameserver so that the correct nameserver automatically "spreads".

References

Last updated: 1st April 2022
First published: 16th August 2018