Docker container with a simple installation of dnsmasq to provide DNS and DHCP services to your local network.
Based on Alpine Linux 'latest' (currently 3.20) and dnsmasq-2.90-r3.
💡 To build a version of docker-dnsmasq using the latest pre-release version of Alpine Linux Edge and dnsmasq-2.90-r3, use Dockerfile-edge
. The easiest way to do this is to mv Dockerfile Dockerfile-release
and then mv Dockerfile-edge Dockerfile
and then build the container. Be sure to also change the version in the image:
name in docker-compose.yml
so your image gets built with the correct version.
This project was born out of a larger project to get rid of the large, loud, hot server sitting next to my desk at home. At the time, I was running a Windows Active Directory environment inside VMware, and needed to provide DNS/DHCP to my local network before getting rid of the server. I don't like hosting it on my router for no good reason at all, and I'm in the progress of learning Docker so I figured I'd take a stab at a lightweight DNS/DHCP container. This container has been providing all DNS and DHCP services to my home network since late July 2020.
I'm not really doing anything groundbreaking here, there really isn't much to the Dockerfile at all. Most of my work has been in building the custom configuration files to make things easier for me to manage later with any text editor I'd like.
- Currently, this container only listens on IPv4.
- We're using Quad9 for our upstream DNS provider by default, but this can be changed.
- Details on changing this are in
config/dns.conf
.
- Details on changing this are in
- Container binds to DNS & DHCP ports of the host machine (i.e.,
53/udp
,67/udp
,68/udp
).- Ubuntu 18.04 and later use a stub resolver (essentially dnsmasq) to cache DNS requests from the local host, so you'll need to disable that before starting this container:
sudo systemctl stop systemd-resolved && sudo systemctl disable systemd-resloved
- Ubuntu 18.04 and later use a stub resolver (essentially dnsmasq) to cache DNS requests from the local host, so you'll need to disable that before starting this container:
- Modify the four files in
config
to suit your environment. The files are commented well enough that you can figure out what's needed. - Starting in this directory, run
docker-compose up -d docker-compose.yml
to build & start the container.
It's strongly recommended that you read the dnsmasq docs (http://www.thekelleys.org.uk/dnsmasq/doc.html) and visit the main site for more information on dnsmasq. While not entirely necessary, as the documentation below pretty well spells out the basics, it will give you a better understanding of how dnsmasq works its magic.
The four files provided in the config
folder make up the core of our configuration.
The first file is dns.conf
, which contains our dnsmasq options related to DNS and the main application itself.
The second file is dhcp.conf
, which contains our DHCP configuration. This is where we define our DHCP scopes, default gateways, and DNS servers.
The third file is hosts.local
, and is referenced in addition to /etc/hosts
(in the container). This is a standard hosts file, and is where we define static DNS entries. DHCP client hostnames are automatically added to the server, there's no need to define them here.
Finally, the fourth file is dhcp-reservations.conf
. This is where we will define our DHCP reservations.
Syntax for each file is noted in the comments & examples in each file.
docker container restart dnsmasq
). The same goes for dnsmasq installed directly on a host: you have to do a sudo systemctl restart dnsmasq
to pick up the changes.
In dns.conf
we set some options:
no-resolv
- This tells dnsmasq to ignore the /etc/resolv.conf file and only forward to the servers we define later in this file.
addn-hosts=/etc/dnsmasq.d/hosts.local
- This is the hosts file for our domain. Here, you'll define the static IP mappings, just like you would in /etc/hosts.
server=9.9.9.9
&server=149.112.112.112
- These are the primary and secondary DNS servers provided by the service Quad9. Visit https://quad9.com for details.
- You may also change these to whatever you'd like. For example, 8.8.8.8 & 8.8.4.4 for Google DNS, 1.1.1.1 or 1.0.0.1 for CloudFlare's 1.1.1.1 service.
domain-needed
- Tells dnsmasq not to forward plain names (i.e., hostnames without a FQDN) to upstream servers.
bogus-priv
- Tells dnsmasq not to forward private address space (i.e., 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) requests upstream. This prevents reverse-DNS lookups of internal ranges from being sent to external servers (i.e., the internet).
local=/xxxx/
- Tells dnsmasq that this domain is a private domain and should only be served from /etc/hosts and our hosts.local file.
- You can do as many of these as you'd like, one per line. This is helpful if you experiment with multiple internal domain names or subdomains.
domain=internal.example.com
- Set your primary internal domain name here. The example uses the subdomain internal.example.com.
expand-hosts
- Tells dnsmasq to expand queries for a just a hostname to a FQDN by appending the domain set above.
log-facility=/var/log/dnsmasq/dnsmasq.log
- Tells dnsmasq to write logs to a file. We specify the file because we bind-mount the the directory so we can access the file on our physical host.
- Dnsmasq will close and reopen it's log files when it receives the signal SIGUSR2. This is helpful if you'd like to use something like
logrotate
to rotate the logs. Just add a post-rotation command ofdocker kill --signal=SIGUSR2 dnsmasq
to your logrorate script on the host.
log-queries
- Tells dnsmasq to log all queries it handles. This can cause lots of writes to disk, so be careful when using this flag. Uncomment to enable.
In dhcp.conf
, we'll set up our DHCP scopes:
- Set up scopes
- In this section, you'll add each IP range, or scope, that you want dnsmasq to serve addresses from.
- You can do as many as you'd like, one per line.
- The syntax is:
dhcp-range=<range_name>,<start_address>,<end_address>,<subnet_mask>,<leasetime>
- Lease times can be expressed in
m
,h
,d
, or asinfinite
(i.e.,12h
).
- Set gateway servers
- In this section, you'll define the default gateway, or router, for each DHCP scope.
- Each scope should have one entry, one entry per line.
- The syntax is:
dhcp-option=<range_name>,3,<ip_address>
(the 3 tag indicates it's a router)
- Set DNS servers
- Here, we set our DNS servers for each scope. It's recommended you set at least a primary server, likely the address of the server you'll be running this container on, in fact!
- The syntax is:
dhcp-option=<range_name>,6,<ip_address>
(the 6 tag indicates it's a DNS server)
We set our static DNS entries in the hosts.local
file. This file works just like /etc/hosts
.
The syntax is:
<ip_address> <fully_qualified_domain_name> <hostname> <additional_hostnames_as_needed>
The file accepts standard comments using the hash (#) symbol. It's recommended you comment your files so you know what you're looking at later. For example:
# This is my desktop computer
192.168.1.100 example-host1.internal.example.com
# This is my laptop
192.168.1.101 example-host2.internal.example.com
Finally, we set our DHCP reservations in dhcp-reservations.conf
:
- You can do as many as you'd like, one entry per line. The IP address you're reserving does not need to be within one of the scopes you defined above, just within the range of the target subnet.
- Also supports standard comments using the hash (
#
) symbol. Comment your files! - The syntax is:
dhcp-host=<mac_address>,<ip_address>,<hostname>,<leasetime>
- MAC Addresses should be entered in
AB:CD:EF:G1:23:45
format (not case-sensitive) - Lease times can be expressed in
m
,h
,d
, or asinfinite
(i.e.,12h
).
I keep my config files under source version control linked to a private repo. This way, I can keep a record of all changes I've made and easily roll back to a previous version of my config files.
This can be done pretty easily. First, create a new repo on github and call it whatever you'd like. Then, cd into your config directory, and run the following, replacing the <url>
with either https://github.com/<username>/<repoistory_name>
or [email protected]:<username>/<repository>
:
$ git init
$ git add .
$ git commit -m 'message'
$ git remote add origin <url>
$ git push -u origin main
I've included the GPLv3, as that is what dnsmasq uses.
We're not doing anything with the dnsmasq code, so I'm not sure it even applies here, but here we are.
As for the contents of this git repo, do whatever the hell you want with it. :)