28 March 2026
Fault Tolerant DNSMasq With Redundancy
After ISC DHCP Server was deprecated by it’s authors, I followed their recommendation and switched to Kea DHCP Server, and then switched to dnsmasq configured for DHCP only. When I upgraded to an OpenWRT Router, switching BIND to Master/Slave gave me redundant synchronized DNS, with a little effort, I was able to make dnsmasq fault tolerant as well.
First, why I chose dnsmasq over Kea.
Kea DHCP Server
ISC Kea is designed as an enterprise solution to replace the legacy ISC DHCP Server. It looks great on paper.
- Modern JSON configuration
- API‑driven dynamic updates
- SQL‑backed lease storage
- Built‑in HA with state synchronization
- The official successor to ISC DHCP
In practice, the JSON configuration is both cumbersome and surprisingly inflexible. My environment had two profiles: one for unreserved hosts and one for reserved hosts. Kea has no mechanism to assign a profile to a reservation, so any deviation from the default profile had to be manually duplicated into each reservation block. This quickly becomes tedious and error‑prone.
High Availability requires a database backend — and that database must be highly available. Once the system is fully built out, any failure means troubleshooting multiple moving parts: the DHCP daemon, the control agent, the database, the HA state machine, and the JSON configuration itself.
dnsmasq DHCP Server
dnsmasq DHCP is a simple one line configuration for reservations. It supports tagging entries to apply different profiles, a feature Kea lacks, it can associate scopes with interfaces to serve multiple subnets. My Kea configuration was 608 lines, my dnsmasq configuration is 84 lines, not including the guest vlan added after the conversion.
As a DNS Server dnsmasq is a host file with caching, but it’s easy to turn off and switch to BIND or Unbound.
I’ve already touched on an important basic feature dnsmasq has that Kea doesn’t. If you need a feature it lacks, a systemd path unit triggered by changes to the reservations or leases file can run a script to create the feature.
Configuration Example
Kea Reservation
{
"hostname": "hifiberry1",
"hw-address": "a0:ae:a1:87:e7:a0",
"ip-address": "192.168.1.31",
"option-data": [
{
"space": "dhcp4",
"name": "domain-name-servers",
"code": 6,
"data": "192.168.1.1,192.168.1.254"
}
]
}
dnsmasq Reservation
# dnsmasq config allows comments like this one, where JSON does not.
# The tag can be added to multiple reservations unlike kea which
# requires copying the option to each reservation.
dhcp-option=tag:reserved-dns,6,192.168.1.1,192.168.1.254
dhcp-host=a0:ae:a1:87:e7:a0,hifiberry1,192.168.1.31,set:reserved-dns
Implementing dnsmasq With Failover
Split the Config
dnsmasq supports breaking the configuration into smaller files, and I strongly recommend doing this. Jobs that synchronize leases and reservation files become simpler, and editing is easier when each file has a clear purpose.
In your main dnsmasq.conf, add:
conf-dir=/etc/dnsmasq.d/,*.conf
Then break your configuration into sections and move them into .conf files in that directory. Order doesn’t matter unless you accidentally define the same option twice.
Housekeeping
If you want both servers to be equals, make sure both specify dhcp-authoritative on both. If you want a primary/secondary setup, only the primary should be authoritative. Non‑authoritative servers delay about a second before answering requests.
Turn off DNS with port=0 if you’re using another DNS server.
Define Your Scopes
For my network I’ve divided up a class C space into 3 blocks: one for reservations and static addresses, and two for dhcp scopes. Create a reservations.conf in the conf.d directory. Create a scope.conf file in conf.d, where one server has the first scope, the other the second. If you’re running equal servers the scopes should be the same size, and each should be large enough to accommodate all connections when the other is down. If you’re running a Primary and Failover the Failover scope can be smaller, the failover scope can be smaller and should use a short lease time so clients quickly return to the primary after an outage.
Configure SSH Access
Even if you’re running equal servers, you’ll need to pick which host will act as the configuration master, in failover configuration the primary is the logical choice. You’ll need to setup ssh from the configuration primary to the configuration secondary.
Set up SSH from the configuration primary to the secondary. Using root is simpler, but a compromise of the primary’s root account compromises the secondary as well.
A Script to Synchronize Reservations
If you’re using root, the following script will test and reload dnsmasq, then push the updated reservations. Placing it in cron.daily ensures it runs even if you forget to use the script and reload dnsmasq manually.
For better security, use a non‑privileged account on the secondary. Symlink the reservations file into a writable location, and use a systemd path unit (or inotifyd on OpenWrt) to reload dnsmasq when the file changes.
#!/bin/bash
# you may want to use the ip address instead of host name.
dnsmasq --test || { echo "dnsmasq config test failed" ; exit 1; }
systemctl reload dnsmasq.service
rsync /etc/dnsmasq.d/reservations.conf root@secondary:/etc/dnsmasq.d/reservations.conf
# OpenWRT or other non systemd secondary
ssh root@secondary '/etc/init.d/dnsmasq reload'
# Secondary with systemd
ssh root@secondary 'systemctl reload dnsmasq'
Conclusion
dnsmasq’s DNS features are basic by design and easy to outgrow, but its DHCP engine is outstanding. With a few small scripts and a clean configuration model, dnsmasq becomes a reliable and maintainable DHCP server — even at scale.