Skip to the content.

πŸ›‘οΈ 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

What this doesn’t give you β€” and intentionally:

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:

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:

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.