π‘οΈ Unbound Home Lab DNS
Redundant recursive DNS for a home lab β two Unbound resolvers on Ubuntu VMs, fed by a single Kea DHCPv4 server. All hosts on the LAN get DHCP from one place; DNS queries land on whichever resolver answers first.
π Live README: https://michalaferber.github.io/unbound-homelab/
Note β this repo was originally built around two Raspberry Pi 4 servers running a TSV-driven Unbound config with custom sync scripts. It has since been simplified: stock Unbound on Ubuntu VMs, no custom scripts, no automation. The current docs reflect the simplified setup.
What this gives you
- Redundant DNS β two Unbound resolvers; clients get both as
domain-name-serversvia DHCP - Authoritative local zone β your LANβs hosts resolve by name (e.g.
nas.home.lanβ192.168.X.30) - Reverse DNS β
dig -x 192.168.X.30returns the hostname - DHCP reservations β pin specific MACs to specific IPs (network gear, servers)
- DNSSEC validation at the resolver
- Cache + prefetch β repeat queries answered locally in microseconds
What this doesnβt give you β and intentionally:
- No ad-blocking. Add Pi-hole or AdGuard Home upstream if you want that.
- No automatic config sync between the two resolvers. The two
local.conffiles are kept in sync manually. They diverge in exactly one line (theinterface:binding). - No installer script. Two
apt installs + drop-in config files is all there is.
Stack
| Role | Component | Where it runs |
|---|---|---|
| Recursive resolver (primary) | Unbound 1.19+ | Ubuntu 24.04 LTS VM |
| Recursive resolver (secondary) | Unbound 1.19+ | Ubuntu 24.04 LTS VM |
| DHCPv4 | Kea-DHCP4 | One of the resolver VMs (no DHCP redundancy in this design) |
Both VMs run on a Proxmox host as Ubuntu Server VMs (1-2 vCPU, 1-2 GB RAM is plenty).
Quick start
1. Install on each resolver
sudo apt update
sudo apt install -y unbound
2. Drop in your local.conf
Copy etc/unbound/unbound.conf.d/local.conf.example to /etc/unbound/unbound.conf.d/local.conf on each resolver. Edit:
- The
interface:line β bind to that hostβs LAN IP (primary uses.10, secondary.11, or whatever your scheme is) access-control:β your LAN subnetlocal-zone:andlocal-data:lines β your LAN domain + host map
3. Test, reload, verify
sudo unbound-checkconf
sudo systemctl restart unbound
sudo systemctl status unbound --no-pager
# From a LAN client:
dig @192.168.X.10 router.home.lan # should return the local A
dig @192.168.X.10 google.com # should return a real A
dig @192.168.X.10 google.com +dnssec # ad flag = DNSSEC validated
4. Install Kea on one of the VMs
sudo apt install -y kea-dhcp4-server
Copy etc/kea/kea-dhcp4.conf.example to /etc/kea/kea-dhcp4.conf. Edit:
interfacesβ the actual NIC name (oftenenp6s18on Proxmox VMs,eth0on bare metal)subnet4block β your LAN subnet + pool rangedomain-name-serversβ IPs of your two Unbound resolversreservationsβ MAC-to-IP for your network gear
sudo systemctl enable --now kea-dhcp4-server
sudo systemctl status kea-dhcp4-server --no-pager
5. Disable the routerβs built-in DHCP
Your existing router/firewall (pfSense, OPNsense, Netgate, etc.) should stop handing out DHCP leases β otherwise clients race between the two. The router stays as the default gateway; Kea hands out the gateway IP as the routers option.
Architecture
βββββββββββββββββββββββ
β Router / Firewall β
β 192.168.X.1 β
β (gateway only β β
β DHCP disabled) β
ββββββββββββ¬βββββββββββ
β
ββββββββββββββββββββββΌβββββββββββββββββββββ
β β β
βββββββββΌβββββββββ ββββββββββΌβββββββββ ββββββββββΌβββββββββ
β DNS Primary β β DNS Secondary β β LAN Clients β
β 192.168.X.10 β β 192.168.X.11 β β 192.168.X.100+ β
β β β β β (DHCP pool) β
β Unbound 1.19+ β β Unbound 1.19+ β β β
β Kea-DHCP4 ββββββΌβββΌββββββββββββββββββΌββΊβ resolv.conf: β
β β β β β .10 β
β β β β β .11 β
βββββββββ¬βββββββββ ββββββββββ¬βββββββββ βββββββββββββββββββ
β β
ββββββββββββ¬ββββββββββ
β
Recursive β root, or forward β 1.1.1.1 / 9.9.9.9
DHCP runs on one host only (typically the primary). DNS runs on both. If the primary VM goes down, DNS still works from the secondary. DHCP renewals will fail until the primary is back β but existing leases are valid for valid-lifetime (24 hours by default), so the LAN keeps working.
Repo layout
unbound-homelab/
βββ etc/
β βββ unbound/unbound.conf.d/local.conf.example
β βββ kea/kea-dhcp4.conf.example
βββ docs/
β βββ ARCHITECTURE.md deeper architectural detail + rationale
β βββ CHEATSHEET.md one-screen ops reference
β βββ TROUBLESHOOTING.md when DNS is broken, look here
βββ _config.yml Jekyll/cayman theme for GitHub Pages
βββ LICENSE MIT
βββ README.md you are here
License
MIT β see LICENSE.