🧠 Pi-hole High Availability Cluster (Keepalived)
📖 Überblick
Dieses Setup implementiert ein hochverfügbares DNS-System basierend auf zwei Pi-hole Instanzen und Keepalived (VRRP).
Ziel:
- Automatischer Failover bei Fehlern
- Gemeinsame virtuelle IP (VIP)
- Health-basierter Switch (nicht nur “Host down”)
- Telegram-Benachrichtigung bei Zustandsänderungen
- Monitoring über Uptime Kuma
🏗️ Architektur
Clients
│
▼
VIP (192.168.178.10)
│
├── Pi-hole MASTER (pinguAurum)
└── Pi-hole BACKUP (pinguArgentum)
- Clients nutzen nur die VIP
- Keepalived entscheidet, welcher Node aktiv ist
🌐 Netzwerk
| Komponente | IP |
|---|---|
| VIP | 192.168.178.10 |
| Master | 192.168.178.2 |
| Backup | 192.168.178.3 |
👉 Fritzbox DNS:
192.168.178.10
192.168.178.10
📦 Installation
Auf beiden Nodes:
apt update
apt install keepalived dnsutils -y
⚙️ Konfiguration
📁 /etc/keepalived/keepalived.conf
MASTER
vrrp_script chk_pihole {
script "/usr/local/bin/check_pihole.sh"
interval 2
weight -100
fall 2
rise 2
}
vrrp_instance VI_PIHole {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass CHANGE_ME_SECURE
}
virtual_ipaddress {
192.168.178.10
}
track_script {
chk_pihole
}
notify_master "/usr/local/bin/failover.sh MASTER"
notify_backup "/usr/local/bin/failover.sh BACKUP"
notify_fault "/usr/local/bin/failover.sh FAULT"
}
BACKUP
Unterschied:
state BACKUP
priority 100
nopreempt
🧪 Health Check
📁 /usr/local/bin/check_pihole.sh
#!/bin/bash
# 1. FTL muss laufen
systemctl is-active --quiet pihole-FTL || exit 1
# 2. DNS muss antworten
dig google.com @127.0.0.1 +time=1 +tries=1 +short | grep -q . || exit 1
# 3. Blocking muss funktionieren
dig doubleclick.net @127.0.0.1 +time=1 +tries=1 +short | grep -Eq "0.0.0.0|::" || exit 1
# 4. NTP muss synchron sein
timedatectl | grep -q "synchronized: yes" || exit 1
# 5. Blocking darf nicht deaktiviert sein
pihole status | grep -q "blocking enabled" || exit 1
exit 0
chmod +x /usr/local/bin/check_pihole.sh
📡 Telegram Benachrichtigung
📁 /usr/local/bin/failover.sh
#!/bin/bash
STATE=$1
HOST=$(hostname)
TOKEN="YOUR_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
curl -s -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
-d text="🧠 Pi-hole Cluster Event:
Host: ${HOST}
State: ${STATE}"
chmod +x /usr/local/bin/failover.sh
▶️ Service starten
systemctl enable keepalived
systemctl restart keepalived
🧪 Tests
✅ VIP vorhanden?
ip a | grep 192.168.178.10
✅ DNS funktioniert?
nslookup google.com 192.168.178.10
✅ Blocking funktioniert?
nslookup doubleclick.net 192.168.178.10
🔥 Failover testen
systemctl stop pihole-FTL
Erwartung:
- Backup übernimmt VIP
- Telegram Nachricht wird gesendet
📊 Monitoring (Uptime Kuma)
Empfohlene Checks:
1. VIP DNS
192.168.178.10- Domain:
google.com
2. VIP Blocking
- Domain:
doubleclick.net - Erwartung:
0.0.0.0
3. Einzelne Nodes
- 192.168.178.2
- 192.168.178.3
⚠️ Typische Probleme
| Problem | Ursache |
|---|---|
| Kein Failover | Gewicht zu gering |
| Keine Telegram Alerts | notify_* außerhalb der Instance |
| Werbung trotz Pi-hole | Client nutzt anderen DNS |
| Handy ignoriert Pi-hole | Private DNS / IPv6 |
🧠 Designentscheidungen
- Aggressiver Failover (auch bei Soft-Errors)
- VIP statt Multi-DNS
- Health-basiertes Routing
- Kein echter Cluster-State (bewusst simpel gehalten)
🚀 Mögliche Erweiterungen
- Gravity Sync (Blocklisten synchronisieren)
- Config Sync zwischen Nodes
- Firewall-Regeln gegen externen DNS
- API-basierter Health Check
- GitOps Deployment über Gitea
🧩 Fazit
Dieses Setup bietet:
- Hohe Verfügbarkeit
- Schnellen Failover (<2 Sekunden)
- Transparente Zustandsüberwachung
- Automatische Fehlerreaktion
Status: 🟢 Stabil Failover: 🟢 Funktioniert Monitoring: 🟢 Aktiv Alerts: 🟢 Telegram integriert