๐๏ธ Project Overview
This project addresses a Single Point of Failure (SPOF) in home network infrastructure. By implementing a high-availability (HA) DNS cluster using AdGuard Home and Keepalived, I have ensured that network-wide ad-blocking and DNS resolution remain active even if the primary server fails.
๐ ๏ธ Toolset & Hardware
| Tool | Purpose | Environment |
|---|---|---|
| Truthwatcher | Primary DNS Node | Proxmox VM (Ubuntu/Debian) |
| Pattern | Secondary DNS Node | Raspberry Pi 2B+ (DietPi) |
| Keepalived | VRRP Failover Management | Linux Service |
| AdGuard Home | DNS Sinkhole / Security | Application |
| AdGuardHome-Sync | Configuration Mirroring | Go Binary (ARMv7) |
| Uptime Kuma | Health Monitoring | Monitoring Suite |
๐ The Process
Phase 1: High Availability (Layer 3)
I configured the Virtual Router Redundancy Protocol (VRRP) to create a “Floating IP” (Virtual IP). This allows devices to point to one address that automatically moves to the active server.
Primary Node Config (/etc/keepalived/keepalived.conf):
vrrp_instance VI_DNS {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass <password>
}
virtual_ipaddress {
10.0.0.231 # IPv4 VIP
fd00::231/64 # IPv6 VIP
}
}
Phase 2: Configuration Sync (Layer 7)
Because AdGuard Home stores its own local database, I used adguardhome-sync on the Raspberry Pi to “pull” the rules from the VM every 5 minutes.
Sync Config (/etc/adguardhome-sync.yaml):
YAML
origin:
url: [http://10.0.0.230:80](http://10.0.0.230:80)
username: vm_admin
password: vm_password
replicas:
- url: http://localhost:8083
username: pi_admin
password: pi_password
cron: "*/5 * * * *
๐งช Verification & Health Script
I developed a custom bash script to verify both the network state (VIP location) and the application state (filter rule count).
Health Script (/home/matt/dns-health.sh):
Bash
#!/bin/bash
# File: ~/dns-health.sh
VIP="10.0.0.231"
RULE_COUNT=$(curl -s -u admin:pass "http://localhost:8083/control/filtering/status" | grep -oP '"url":' | wc -l)
echo "--- Wardeck DNS Health Check ---"
if ip addr show | grep -q "$VIP"; then
echo "[INFO] VIP ($VIP) is ACTIVE on this Node (MASTER)."
else
echo "[INFO] VIP ($VIP) is ACTIVE on Primary VM (BACKUP)."
fi
echo "[INFO] Local AdGuard Filter Rules: $RULE_COUNT"
๐ก๏ธ Disaster Recovery & Maintenance
To Restart Cluster:sudo systemctl restart keepalived on both nodes.
To Force Sync: /usr/local/bin/adguardhome-sync run --config /etc/adguardhome-sync.yaml
Network Impact: Failover occurs in <3 seconds. Clients experience zero loss of connectivity.