High-Availability DNS Cluster: Technitium + Keepalived (IPVS) on Debain LXC Container
Domain Name System (DNS) is the backbone of any network infrastructure. When your DNS servers go down, your entire network effectively stops functioning. While many network administrators simply deploy two separate DNS servers and list both in their DHCP scope, this approach does not provide true load balancing or instantaneous failover.
In this guide, we will build a production-grade, highly available DNS cluster using two Technitium DNS servers running inside Proxmox Linux Containers (LXC). We will leverage Keepalived and IPVS (IP Virtual Server) to achieve both seamless load balancing and intelligent failover over a single Virtual IP (VIP) address.
Why Standard Secondary DNS Isn’t Enough
Most home labs and enterprise environments deploy two DNS servers (Primary and Secondary). They hand out both IP addresses via DHCP. However, the client-side implementation of this is flawed:
- Unpredictable Routing: Some operating systems (like Windows) stick to the primary server until it completely times out, causing severe delays during an outage. Other systems (like macOS/Linux) might query both semi-randomly, making traffic distribution unpredictable.
- No Real Load Balancing: Traffic is rarely distributed evenly between the two servers.
- Slow Failover: If the primary DNS server freezes but keeps its network link active, clients will waste precious seconds waiting for timeouts before trying the secondary server.
The Solution: Keepalived + IPVS
By introducing Keepalived with IPVS at Layer 4, we create a single Virtual IP (VIP). Your clients only ever talk to this one IP address.
Keepalived acts as an intelligent traffic director:
- Load Balancing: It splits incoming UDP and TCP port 53 DNS queries evenly across both Technitium instances using a Round Robin algorithm.
- Instant Failover: It continuously polls the health of each Technitium instance. If one container or DNS service crashes, Keepalived immediately removes it from the rotation.
- Infrastructure Redundancy: Keepalived uses VRRP (Virtual Router Redundancy Protocol). If the primary load-balancing container dies entirely, the secondary container instantly assumes the VIP within milliseconds.
Schematic Overview
[ NETWERK CLIENTS ]
(Request DNS via VIP)
│
▼
┌────────────────┐
│ VIRTUEL IP │
│ 192.168.1.10 │
└───────┬────────┘
│
┌──────┴──────┐ (Keepalived VRRP / IPVS)
│ │ (Divide UDP/TCP requests via Round Robin)
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ LXC Container 1 │ │ LXC Container 2 │
│ [MASTER] │ │ [BACKUP] │
│ 192.168.1.11 │ │ 192.168.1.12 │
├─────────────────┤ ├─────────────────┤
│ Technitium #1 │ │ Technitium #2 │
│ (lo: .1.10/32) │ │ (lo: .1.10/32) │
└────────┬────────┘ └────────┬────────┘
│ │
└──────────┬──────────┘
│ (Direct Routing - DR Mode)
▼
[ Direct Answer ]
(Back to Clients)
Explanation of the data flow:
- Inbound traffic: Network clients send all their DNS requests exclusively to the Virtual IP (192.168.1.10).
- Load Balancing: The container currently holding the MASTER role (Container 1) intercepts the traffic and distributes the requests across the two Technitium DNS backends using the Linux IPVS kernel module (Round Robin).
- Direct Routing (DR): Thanks to the loopback configuration (lo: 192.168.1.10/32), both containers process the packets directly and send the response straight back to the client, bypassing the load balancer. This ensures minimal latency.
- Failover: If Container 1 fails, Keepalived moves the VIP to Container 2 within a fraction of a second; from that point on, Container 2 handles the requests independently.
Architectural Overview
- Virtual IP (VIP):
192.168.1.10(The single DNS address given to your clients) - Technitium Container 1 (MASTER):
192.168.1.11 - Technitium Container 2 (BACKUP):
192.168.1.12
Step 1: Preparing the Proxmox Host (Crucial for LXC)
Because LXC containers share the host’s Linux kernel, they cannot load kernel modules or manipulate network routing infrastructure by default. We must prepare the Proxmox host first.
1. Load IPVS Modules on the Host
Log into your Proxmox VE Host via SSH and run the following commands to load the required IPVS load-balancing kernel modules:
modprobe ip_vs
modprobe ip_vs_rr
To ensure these modules survive a Proxmox host reboot, append them to the host’s /etc/modules file:
echo "ip_vs" >> /etc/modules
echo "ip_vs_rr" >> /etc/modules
2. Adjust LXC Container Permissions
You must grant your containers permission to interact with the network stack. On your Proxmox host, open the configuration files for both containers (located at /etc/pve/lxc/YOUR_CONTAINER_ID.conf) and add these lines:
Make sure the the LXC container are running in privilegded mode. Option “unprivileged: 0” in
| |
Restart both LXC containers after saving these changes.
Step 2: Configuring the Loopback Interface on the Containers
We will be using Direct Routing (DR) mode in IPVS. This is the fastest method of load balancing because incoming traffic goes through the load balancer, but the backend Technitium servers reply directly to the client.
For this to work, both containers must accept packets destined for the VIP (192.168.1.10), but they must not broadcast this IP to the local network to avoid IP conflicts. We solve this by binding the VIP to the local loopback (lo) interface.
Inside both Debian LXC containers, open /etc/network/interfaces:
nano /etc/network/interfaces
Modify the loopback configuration block to match the following:
auto lo
iface lo inet loopback
up ip addr add 192.168.1.10/32 dev lo
down ip addr del 192.168.1.10/32 dev lo
Apply the changes instantly without a reboot:
ifdown lo && ifup lo
Step 3: Installing and Configuring Keepalived
Now, log into both containers to install Keepalived and the IPVS administration utility:apt update && apt install -y keepalived ipvsadm
1. Configuration for Container 1 (MASTER)
Create the configuration file /etc/keepalived/keepalived.conf on your first Technitium container:
| |
2. Configuration for Container 2 (BACKUP)
Create the exact same file on your second Technitium container, but change the vrrp_instance configuration block to reflect its backup status and lower priority:
state BACKUP
priority 100 # Lower than the MASTER server
3. Enable and Start Keepalived
Run this command on both containers to start the service and ensure it launches automatically at boot:
systemctl enable --now keepalived
Step 4: Verification and Testing
Your high-availability cluster is now live! Let’s verify that everything is working perfectly.
1. Check IP Allocation
On Container 1 (MASTER), run:
ip addr show eth0
You should see both its local IP (192.168.1.11) and the VIP (192.168.1.10). If you run the same command on Container 2, the VIP should not be present.
2. Inspect the Load Balancing Table
Run the following command on the container that is currently acting as the MASTER:
ipvsadm -ln
You will see a clean routing matrix mapping your VIP to both backend servers across TCP and UDP protocols.
3. Simulating a Failure
To test the failover capability, stop the Keepalived service on Container 1:
systemctl stop keepalived
If you run ip addr show eth0 on Container 2, you will notice that it has gracefully assumed control of the VIP (192.168.1.10) in a fraction of a second. Your network clients will experience zero downtime, and DNS queries will keep resolving seamlessly.
4. Monitoring Real-Time Traffic Distribution
Once your high-availability DNS cluster is running, you will want to see it in action. The best way to monitor how Keepalived and IPVS are distributing traffic between your Technitium servers is by using the following debugging command:
watch -n 0.5 ipvsadm -Ln
What it does
This command combines two powerful Linux utilities. The ipvsadm -Ln command lists the current IP Virtual Server kernel routing table in a clean, numeric format (-n), skipping slow DNS lookups. By wrapping it in watch -n 0.5, the terminal automatically refreshes the output every half-second, providing a near-real-time view of your live network traffic.
How to interpret the output When you run this on the active MASTER container, you will see an output structured like this:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
UDP 192.168.1.10:53 rr
-> 192.168.1.11:53 Route 1 0 142
-> 192.168.1.12:53 Route 1 0 139
Key metrics to look out for:
- UDP/TCP … rr: Confirms that IPVS is listening on your Virtual IP (VIP) on port 53 and using the Round Robin (rr) scheduler.
- Forward (Route): Indicates that Direct Routing (DR) is working properly.
- Weight: A value of 1 means the server is healthy. If Keepalived detects that a Technitium instance is down, this weight will immediately drop to 0, removing it from rotation.
- InActConn (Inactive Connections): Since DNS over UDP is stateless, queries do not stay open. Instead, they quickly register as inactive connections. Watch these numbers increment evenly on both rows as clients make requests—this is visual proof that your load balancer is dividing the work perfectly!
Conclusion
By coupling Technitium DNS with Keepalived and IPVS, you eliminate the classic pitfalls of primary/secondary DNS configurations. You get an enterprise-grade setup that guarantees absolute uptime, linear traffic distribution, and instantaneous failover management—all running within lightweight, low-overhead Proxmox LXC containers.
