This is a second post in a series of my experiences while Building a Homelab. The first post focusing on the history, hardware, and OS can be found here.
Having a number of networked devices at home presents some management overhead. You may find yourself asking, what was the IP address of that one laptop? or just getting plain old tired of looking at IP addresses. One method people often use to manage their network is to assign Domain Name System (DNS) names to their devices. Instead of constantly typing in
192.168.1.1 you could instead assign it the domain name
router.home into your browser then transparently brings you to the same webpage as
192.168.1.1. This not only works for browsing the internet, services such as SSH, FTP, and other places where an IP address would normally be used can likely use the friendlier domain name instead.
So how can this be done? It’s actually quite simple given you have an always-on computer on the same network as the rest of your devices, a router with DNS serving capabilities, or even a DNS provider such as Cloudflare. This article will focus on the DIY solution of running a DNS server on an always on computer.
Before we get to how to set this up, let’s first explain what DNS is and how it works. Feel free to skip over this section if you’re already knowledgeable.
What is DNS?
DNS is a technology used to translate human-friendly domain names to IP addresses. For example, we can ask a DNS server what is the IP address for the domain google.com? The DNS server would then respond with the IP address for
184.108.40.206. DNS is used for almost every request your computer, phone, smart lightbulbs, and more when it communicates with the internet.
Anyone who runs a website is using DNS whether they know it or not. Usually the basic premise is that each domain name (eg.
mysite.com) will have a DNS record which points to an IP address. The IP address is the actual computer on the internet which traffic for
mysite.com will be sent to.
An example of DNS being used can be for
jonsimpson.ca. This site is hosted on a server that I pay for at DigitalOcean. That server has an IP address of
220.127.116.11 (a fictitious example). I use Cloudflare as the DNS provider for
jonsimpson.ca. Anytime a user’s browser wants to go to
jonsimpson.ca, it uses DNS to figure out that
jonsimpson.ca is located at
18.104.22.168, then the user’s browser opens up a connection with the server at
22.214.171.124 to load this site.
This is quite a simplified definition of DNS as the system is distributed across the world, hierarchical, and involves hundreds of thousands, if not millions, of different entities. Cloudflare provides a more detailed explanation as to how DNS works, and Wikipedia has comprehensive coverage of multiple concerns relating to DNS. But what was explained earlier will provide enough context for this article.
Running a local DNS server
If there’s an always-on computer – whether that’s a spare computer or Raspberry Pi – a DNS server can run on it and provide DNS capabilities for the local network. Dnsmasq is a lightweight but powerful DNS server that has been around for a long time. Many hobbyists use Dnsmasq for their home environments since it’s quite simple to configure and get going. One minimal text file is all that’s needed for configuring a functional DNS service.
I chose to run Dnsmasq on my always-on server in a Docker container. When configuring Dnsmasq, for each device that I wanted to provide a domain name for, I added a line in the configuration mapping its IP address to the name I wanted to give it. For example, my router which lives at
192.168.1.1 was assigned
router.home.mysite.com, and my server which lives at
192.168.1.2 was assigned
I then configured my router’s DHCP to tell all clients to use the DNS provided by the server (contact
192.168.1.2 for DNS), and configure some manually networked devices to explicitly use the DNS provided by the server. Now on all of my devices I can type in
server.home.mysite.com anywhere I would type
192.168.1.2 – so much nicer compared to having to type in an entire IP address.
dig are both common command line tools to query the Domain Name System. They are often found already available on many Linux and Unix operating systems, or a straightforward install away. Using these tools can help with inspecting and debugging DNS setups. Here’s an example query using
nslookup to find
$ nslookup google.com
Address denote the DNS server that was used to find the IP address for
google.com. In this case, it was the Dnsmasq DNS server running on my home server.
Address at the bottom signify the actual response we’re interested in. In this case,
126.96.36.199 is the IP address I get whenever I go to
I use Docker as a way to simplify the configuration and running of different services. Specifically, I use
docker-compose to define the Dnsmasq Docker image to use, which ports should be opened, and where to find its configuration. Here’s the
docker-compose.yml file I use:
The docker-compose file defines one
dns service that uses the base image of
strm/dnsmasq, as its one of the more popular Dnsmasq images available on hub.docker.com. The
volume option specifies that we map a config file located alongside the
docker-compose.yml file at
config/dnsmasq.conf into the container’s filesystem at
/etc/dnsmasq.conf. This is done to allow the container to be recreated at any time while keeping the same configuration. Networking-wise, TCP and UDP port 53 are exposed (yes, DNS operates over TCP sometimes). The
network-mode is set to the host’s network (Dnsmasq just doesn’t work without this). And lastly, the
NET_ADMIN capability so that we can use privileged ports below 1024. The last option
restart, (one of my favourite features of docker-compose) is to keep the container running even when the host reboots or the container dies.
All of these
docker-compose.yml options can be understood in more detail in Docker’s reference docs.
More importantly, here’s the
dnsmasq.conf file I use to actually configure Dnsmasq’s DNS capabilities:
A lot of these settings were based off of the following blog post. Many of these options can be looked up online in the official documentation, therefore I will focus on the ones relevant to this article.
I have my Ubiquity router handle providing DHCP for my network, therefore the
no-dhcp-interface=eno1 is set here to not provide any DHCP services to the local network, as
eno1 is the interface my server uses to connect to the network.
When Dnsmasq needs to find the DNS record for something that it doesn’t know, it performs a request to an upstream DNS server.
server is used for this and can be specified multiple times to provide redundancy in case one of these DNS servers are down. I’ve specified both the Google and Cloudflare DNS servers. In addition to this, the
all-servers option results in all defined
server entries being queried simultaneously. This has the benefit that one DNS server may respond quicker than the others, resulting a net-faster response to the DNS query.
The most important part of this
dnsmasq.conf configuration file are the last lines defined in the file that start with
address=. This is Dnsmasq’s way to declare DNS mappings. For example, any device on my network performing a request for
server.home.mysite.com will have
The really cool thing with DNS is that subdomains for any of these records return the same IP, unless declared explicitly otherwise. An example of this is
blog.apps.home.mysite.com doesn’t exist in the configuration file, but performing a DNS request for it will return
192.168.1.2. This has the effect that “multiple services” can each have its own domain name, but all be served by the same IP address.
Hopefully this article gives a background about what DNS is, how it can be useful in a home environment, and how to setup and operate a Dnsmasq DNS server. A future post will build on top of the DNS functionality that has been setup here to provide multiple HTTP services running on separate domain names, all served by the same server, for the home network to use.