DNS und Reverse Proxy in HA: Hochverfuegbarkeit fuer dein Homelab
In den meisten Homelabs laufen DNS und Reverse Proxy als ein einzelner Container auf einer einzelnen VM. Solange alles laeuft, faellt das nicht auf - bis du fuer ein Update einen Reboot machst und ploetzlich kein Geraet mehr ins Internet kommt, weil DNS weg ist. Oder bis dein Reverse-Proxy-Container nach einem Crash nicht mehr startet und alle deine Services unter HTTPS unerreichbar sind.
Dieser Post nimmt sich genau diese beiden kritischen Bausteine vor: Er vergleicht die gaengigen Optionen (Pi-hole vs. AdGuard Home auf DNS-Seite, Nginx Proxy Manager, Traefik und Caddy auf der Proxy-Seite) und zeigt dann ein konkretes, nachbaubares Best-Practice-HA-Setup mit floating VIP, Caddy als Reverse Proxy und Redis als shared certificate storage.
Warum Hochverfuegbarkeit im Homelab?
“HA im Homelab” klingt erstmal nach Overkill - hier laufen ja keine Banking-Systeme. Trotzdem hat es ganz praktischen Wert, sobald andere Personen im Haushalt deine Services benutzen oder du dein Homelab fuer wichtige Sachen einsetzt (Smart Home, Foto-Backup, Kalender, Mail).
RPO und RTO - kurz erklaert
Zwei Begriffe aus der Server-Welt helfen, das Ganze realistisch einzuordnen:
- RPO (Recovery Point Objective): Wie viel Datenverlust ist tolerierbar? Bei DNS und Proxy faktisch null, weil beide zustandslos sind - Cache und Log darf weg sein.
- RTO (Recovery Time Objective): Wie lange darf ein Ausfall dauern? Im Homelab realistisch: ein paar Sekunden statt 5-30 Minuten Reboot-Zeit.
Wenn du die Kinder anrufen lassen willst, waehrend du Updates fahrst, brauchst du HA. Wenn du das Update um 3 Uhr morgens machst und alle schlafen, reicht ein Reboot.
Welche Services rechtfertigen den Aufwand?
DNS und Reverse Proxy sind die zwei Kandidaten, bei denen sich HA im Homelab fast immer lohnt. Der Grund: Beide sind Single-Point-Multipliers. Faellt einer aus, wirken sich die Folgen auf jedes einzelne Geraet und jeden einzelnen Dienst im Netz aus.
| Komponente | Faellt aus -> Folgen |
|---|---|
| DNS | Keine Namensaufloesung, kein Internet, keine internen Services per Hostname erreichbar |
| Reverse Proxy | Alle HTTPS-Services unerreichbar (Jellyfin, GitLab, Home Assistant, …) |
| Einzelne App (z.B. Jellyfin) | Nur diese App weg, alles andere laeuft weiter |
Bei einer einzelnen App reicht ein Reboot, bei DNS und Proxy nicht.
Die zwei kritischen Dienste: DNS und Reverse Proxy
Was passiert, wenn DNS ausfaellt?
DNS ist die telefonische Auskunft des Netzwerks. Faellt sie aus, weiss kein Geraet mehr, dass gitlab.homelab.local auf 192.168.1.20 zeigt - und genauso wenig, wie es update.example.com aufloesen soll. Faktisch hast du dann kein Internet, obwohl die Leitung steht.
Was passiert, wenn der Reverse Proxy ausfaellt?
Der Reverse Proxy ist die Eingangstuer zu allen deinen Web-Services. Er nimmt HTTPS-Anfragen entgegen, terminiert SSL und leitet sie an den richtigen Backend-Container weiter. Faellt er aus, sind alle deine Services unter ihren Hostnamen nicht erreichbar.
Im Vergleich: Faellt DNS aus, geht gar nichts. Faellt der Proxy aus, gehen die meisten Dinge nicht. In beiden Faellen merken alle Mitbewohner es sofort.
DNS-Server im Vergleich: Pi-hole vs. AdGuard Home
Beide Tools tun im Kern dasselbe: lokal aufloesen, blockieren, optional verschluesselt nach upstream weitergeben. Die Unterschiede liegen im Detail.
Feature-Matrix
| Feature | Pi-hole | AdGuard Home |
|---|---|---|
| Web-UI | Klassisch, sehr maechtig | Modern, kompakt |
| DoH / DoT / DoQ | Nur via Unbound oder cloudflared | Nativ eingebaut |
| Wildcard-DNS-Rewrites | Ueber dnsmasq, etwas hakelig | Per Klick im UI |
| HA-Sync-Tool | gravity-sync | adguard-home-sync |
| Container-Footprint | leichtgewichtig | leichtgewichtig |
| Community / Plugins | Sehr gross | Mittel, dafuer modernerer Code |
Detaillierte Setups stehen in den Einzelposts: Pi-hole im Detail und AdGuard Home im Detail.
HA-Moeglichkeiten beider Loesungen
Pi-hole und AdGuard Home funktionieren beide nach dem gleichen Schema fuer Redundanz: zwei Instanzen, eines der beiden Sync-Tools, beide IP-Adressen per DHCP an die Clients verteilen. Einen “Cluster” gibt es bei keinem davon - die Replikation ist Konfigurations-Sync, kein State-Sharing.
sequenceDiagram
participant C as Client
participant P as DNS Primary (.10)
participant S as DNS Secondary (.11)
C->>P: Query example.com
Note right of P: timeout / down
C->>S: Query example.com (Fallback)
S-->>C: 93.184.216.34
Das Schoene: Der Fallback passiert auf Client-Seite. Sobald Windows/macOS/Linux nach ~1 Sekunde keine Antwort von .10 bekommen, fragen sie automatisch .11. Du brauchst keinen Loadbalancer fuer DNS.
Empfehlung fuer HA-Szenarien
AdGuard Home ist fuer ein HA-Setup die etwas pragmatischere Wahl:
adguard-home-syncsynchronisiert per HTTP-API gegen die Web-UI - nicht gegen die Datenbank-Datei. Das macht Versionsmismatches zwischen den Instanzen viel weniger schmerzhaft.- DoH/DoT/DoQ ist ohne extra Sidecar moeglich.
- Wildcard-DNS-Rewrites (z.B.
*.homelab.local -> 192.168.1.20) sind ein Klick.
Pi-hole ist nicht schlechter, hat aber bei gravity-sync ein paar Stolperfallen mehr (SSH-Schluessel zwischen den Nodes, Versionsabhaengigkeiten). Wer Pi-hole liebt: bleib dabei. Wer neu aufsetzt und HA von Anfang an einplant: AdGuard Home.
Reverse Proxy im Vergleich: NPM vs. Traefik vs. Caddy
Drei Reverse Proxies dominieren den Homelab-Markt. Auf den ersten Blick machen alle dasselbe (HTTPS terminieren, an Backends weiterleiten), unter der Haube ticken sie sehr unterschiedlich - besonders bei HA.
Feature-Matrix
| Feature | Nginx Proxy Manager | Traefik | Caddy |
|---|---|---|---|
| Konfigurations-Modell | Web-UI | Labels / YAML / API | Caddyfile (sehr kompakt) |
| Auto-HTTPS | manuell | per Konfig | default an |
| Service-Discovery | Manuell pro Host | Nativ via Docker-Labels | Plugin caddy-docker-proxy |
| HA-Eignung | Schwach (SQLite-Lock) | Mittel (NFS-Hack) | Stark (Redis/S3 Cluster) |
| Datenbank | SQLite | Datei (acme.json) |
Storage-Backend (FS/Redis/S3/…) |
| Cluster-Mode | nein | Workaround mit Shared Storage | Eingebaut |
| Footprint | mittel | mittel | klein, single binary |
| Lernkurve | sehr flach | mittel | flach (klassisch) bis mittel (HA) |
| Community | gross | sehr gross | mittel, schnell wachsend |
Detail-Setups: Nginx Proxy Manager im Detail und Traefik im Detail.
HA-Eignung im Vergleich
NPM ist nicht fuer HA designed. Die Konfiguration steckt in einer SQLite-Datenbank, die nicht zwischen mehreren Instanzen geteilt werden kann (SQLite und shared filesystem moegen sich nicht). Wer NPM trotzdem hochverfuegbar haben will, muss zwei Instanzen mit separaten Datenbanken pflegen und manuell synchron halten - kein Spass.
Traefik liest Konfiguration aus drei Quellen: statisches YAML, Docker-Labels und einer dynamischen Datei. Der einzig kritische Zustand sind die Let’s-Encrypt-Zertifikate in acme.json. Diese Datei laesst sich auf ein NFS-Share legen, hat aber zwei Probleme: NFS-File-Locking ist nicht zuverlaessig, und beide Traefik-Instanzen duerfen nicht gleichzeitig schreiben - in der Praxis bedeutet das Active/Passive mit “nur MASTER renewed”.
Caddy ist fuer HA so designed, dass es einfach funktioniert: Du gibst mehreren Caddy-Instanzen denselben Storage-Backend (Filesystem, Redis, S3, Consul, etcd), und sie koordinieren Zertifikats-Renewal automatisch via verteiltem Locking - kein Custom-Hack noetig. Citation aus der offiziellen Doku:
“Any Caddy instances that are configured to use the same storage will automatically share those resources and coordinate certificate management as a cluster.”
Mit Redis als Storage-Backend hast du echtes Active/Active: Beide Caddy-Knoten koennen gleichzeitig Zertifikate erneuern, Redis sorgt via Distributed Lock dafuer, dass es keine Race-Condition gibt.
Empfehlung fuer HA-Szenarien
Caddy ist fuer HA-Setups die sauberste Wahl. Der Konfigurations-Aufwand ist deutlich kleiner als bei Traefik, das HA-Modell ist eingebaut und nicht draufgeklebt, der Footprint ist winzig (~25 MB statisches Binary).
NPM bleibt grossartig fuer Single-Server-Setups mit Web-UI. Traefik bleibt eine sehr gute Wahl, wenn man das Label-System bereits liebt und mit dem NFS-Workaround leben kann. Aber wer neu aufsetzt und HA von Anfang an einplant: Caddy.
Single Points of Failure analysieren
Bevor wir das HA-Setup bauen, schauen wir uns die typischen SPOFs in einem Standard-Homelab an. Die meisten Homelab-Setups starten mit einer Topologie wie auf der linken Seite:
Alles haengt an einer Maschine. Geht die VM down, ist Schluss. Im HA-Setup rechts uebernimmt der zweite Knoten in Sekunden, ohne dass der Client davon merkt - die VIP wandert per VRRP auf den Backup-Knoten.
Wichtig: HA hilft gegen Software-Crashes, geplante Wartung, Reboots. Sie hilft nicht gegen netzweite Probleme (Stromausfall, Internet down, Router weg). Wer dagegen absichern will, braucht zusaetzlich USV, Mobilfunk-Backup und einen redundanten Router.
Best-Practice-Architektur fuer HA
Hier ist das vollstaendige Setup, das wir gleich Schritt fuer Schritt aufbauen:
Komponenten-Uebersicht
- Layer 0 (Internet): Faellt unter “wir kontrollieren das nicht” - DNS-HA hilft hier nicht.
- Layer 1 (Router): Verteilt per DHCP zwei DNS-Adressen an die Clients und leitet 80/443 auf die VIP weiter.
- Layer 2 (VIP): Floating IP
192.168.1.20, gehalten vom aktiven Caddy-Knoten via keepalived/VRRP. - Layer 3 (Reverse Proxy): Zwei Caddy-VMs (
.21MASTER,.22BACKUP), die gemeinsam einen Redis als Storage-Backend nutzen. Beide Knoten koennen unabhaengig voneinander Zertifikate erneuern, Redis koordiniert das Locking. - Layer 4 (DNS): Zwei AdGuard-Home-VMs (
.10PRIMARY,.11REPLICA), die peradguard-home-syncihre Konfiguration alle 60 Sekunden abgleichen.
IP-Schema
| Host | IP | Rolle |
|---|---|---|
| Router/Firewall | 192.168.1.1 | DHCP, Port-Forwarding |
| adguard-01 | 192.168.1.10 | DNS Primary + Sync-Origin |
| adguard-02 | 192.168.1.11 | DNS Replica |
| Caddy VIP | 192.168.1.20 | Floating IP (keepalived) |
| caddy-01 | 192.168.1.21 | Reverse Proxy MASTER |
| caddy-02 | 192.168.1.22 | Reverse Proxy BACKUP |
| redis-01 | 192.168.1.30 | Shared Cert-Storage |
Alle Hosts liegen im selben L2-Segment - das ist Voraussetzung fuer VRRP.
Warum nur eine Redis-Instanz?
Strenggenommen ist redis-01 ein neuer SPOF. In der Praxis ist das aber unproblematisch:
- Caddy cached Zertifikate lokal im Speicher nach dem ersten Read aus Redis. Faellt Redis aus, laeuft der Traffic weiter.
- Renewal scheitert waehrend des Redis-Ausfalls - Zertifikate haben aber 90 Tage Laufzeit. Du hast Tage Zeit, Redis zu reparieren, bevor das erste Zertifikat abgelaeuft ist.
- Einen echten Redis-Cluster (Sentinel oder Redis Cluster) zu betreiben verdoppelt die Komplexitaet, ohne im Homelab signifikant mehr Verfuegbarkeit zu liefern.
Wer trotzdem mehr will: Redis Sentinel mit drei Nodes ist die naechste Stufe.
Anforderungen
- 5 VMs/LXC-Container mit je 1 vCPU und 512 MB RAM
- Idealerweise 2 Proxmox-Hosts:
caddy-01/adguard-01auf Host A,caddy-02/adguard-02auf Host B - Eine Domain (du brauchst sie sowieso fuer Let’s Encrypt) bei einem Provider mit DNS-API (Cloudflare, OVH, Hetzner)
Schritt 1: VMs vorbereiten
Du brauchst vier VMs (oder LXC-Container) mit Debian/Ubuntu fuer die Apps und eine fuenfte fuer Redis. Layout-Empfehlung: jede aktive Komponente und ihr Backup auf unterschiedlichen Proxmox-Hosts. So uebersteht das Setup auch den Reboot eines kompletten Proxmox-Nodes.
1
2
3
# Auf jeder der vier App-VMs (adguard-01/02, caddy-01/02):
sudo apt update && sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
Hostnamen sauber setzen (hostnamectl set-hostname caddy-01) und im Router/DHCP statische Reservierungen anlegen.
Schritt 2: Redis als shared cert storage
Redis ist hier nicht primaer ein Cache, sondern die zentrale Stelle fuer Caddys Zertifikate und Locking-State. Auf redis-01 (192.168.1.30):
1
2
3
4
5
6
7
8
9
10
services:
redis:
image: redis:7-alpine
container_name: redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
ports:
- "192.168.1.30:6379:6379"
volumes:
- ./data:/data
.env-Datei daneben:
1
REDIS_PASSWORD=hier-ein-langes-zufaelliges-passwort
1
2
docker compose up -d
docker exec redis redis-cli -a "$REDIS_PASSWORD" ping # PONG
Persistierung mit
appendonly yesist hier wichtig: Sonst sind nach einem Redis-Neustart alle Zertifikate weg und Caddy muss alles neu beziehen - das gibt Let’s-Encrypt-Rate-Limits.
Schritt 3: DNS-HA mit AdGuard Home
Docker Compose fuer beide Nodes
Auf adguard-01 und adguard-02 jeweils dieselbe Compose-Datei:
1
2
3
4
5
6
7
8
9
services:
adguard:
image: adguard/adguardhome:latest
container_name: adguard
restart: unless-stopped
network_mode: host
volumes:
- ./work:/opt/adguardhome/work
- ./conf:/opt/adguardhome/conf
1
docker compose up -d
Initial-Setup machst du nur auf adguard-01 (http://192.168.1.10:3000): Admin-User anlegen, Upstream-DNS auswaehlen (z.B. Cloudflare DoH/DoT), Filterlisten aktivieren, lokale Rewrites anlegen.
adguard-02 laesst du in der Default-Konfiguration - die wird gleich vom Sync-Tool ueberschrieben.
adguard-home-sync einrichten
Das Tool adguard-home-sync repliziert die Konfiguration vom Origin auf eine Liste von Replicas. Es laeuft als Container neben einer der Instanzen (typisch auf adguard-01):
1
2
3
4
5
6
7
8
services:
adguardhome-sync:
image: ghcr.io/bakito/adguardhome-sync:latest
container_name: adguardhome-sync
restart: unless-stopped
volumes:
- ./adguardhome-sync.yaml:/config/adguardhome-sync.yaml:ro
command: ["run", "--config", "/config/adguardhome-sync.yaml"]
Konfiguration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cron: "*/1 * * * *"
runOnStart: true
origin:
url: http://192.168.1.10:3000
username: admin
password: ${ORIGIN_PW}
replicas:
- url: http://192.168.1.11:3000
username: admin
password: ${REPLICA_PW}
features:
generalSettings: true
queryLogConfig: true
statsConfig: true
clientSettings: true
services: true
filters: true
dhcp:
serverConfig: false
staticLeases: false
dns:
serverConfig: true
accessLists: true
rewrites: true
Der Cron-Eintrag */1 * * * * triggert die Replikation jede Minute. Fuer ein Homelab vollkommen ausreichend.
Aenderungen NUR auf dem Origin (
adguard-01) machen. Aenderungen auf der Replica werden beim naechsten Sync wieder weggebuegelt.
Schritt 4: Reverse-Proxy-HA mit Caddy
Caddy mit Redis-Storage und Cloudflare-DNS bauen
Caddy braucht zwei Plugins: caddy-storage-redis fuer den geteilten Cert-Storage und caddy-dns/cloudflare fuer die DNS-01-Challenge. Die offiziellen Caddy-Images haben diese Plugins nicht eingebaut - aber das offizielle Builder-Image macht den Custom-Build trivial.
1
2
3
4
5
6
7
FROM caddy:2-builder AS builder
RUN xcaddy build \
--with github.com/pberkel/caddy-storage-redis \
--with github.com/caddy-dns/cloudflare
FROM caddy:2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
Caddyfile (auf beiden Knoten identisch)
{
email [email protected]
storage redis {
host 192.168.1.30
port 6379
password {$REDIS_PASSWORD}
db 0
key_prefix "caddy"
}
acme_dns cloudflare {$CF_API_TOKEN}
}
# Beispiel-Service
gitlab.example.com {
reverse_proxy 192.168.1.40:8080
}
jellyfin.example.com {
reverse_proxy 192.168.1.41:8096
}
homepage.example.com {
reverse_proxy 192.168.1.42:3000
}
Der globale Block oben ist die ganze HA-Magie:
storage rediszeigt beide Caddy-Instanzen auf denselben Redis. Caddy nutzt das Plugincaddy-storage-redis, dasredislockfuer verteiltes Locking verwendet.acme_dns cloudflareaktiviert die DNS-01-Challenge global - perfekt fuer ein internes Homelab, weil kein Port 80 von aussen erforderlich ist.- Pro Service-Block wird automatisch ein Zertifikat geholt und in Redis abgelegt - der zweite Caddy-Knoten findet es dort und braucht nichts neu zu beziehen.
Docker Compose fuer beide Caddy-Knoten
1
2
3
4
5
6
7
8
9
10
11
12
13
14
services:
caddy:
build: .
image: caddy-redis-cf:latest
container_name: caddy
restart: unless-stopped
network_mode: host
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
- CF_API_TOKEN=${CF_API_TOKEN}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
1
2
3
4
5
6
echo "REDIS_PASSWORD=...
CF_API_TOKEN=..." > .env
chmod 600 .env
docker compose build
docker compose up -d
Auf beiden Caddy-Knoten dasselbe Compose, dasselbe Caddyfile, dieselbe .env. Der lokale data/-Ordner enthaelt nur einen Cache - die kanonischen Zertifikate liegen in Redis.
Cloudflare-API-Token: Erstelle einen Token mit den Rechten
Zone.Zone:ReadundZone.DNS:Editfuer deine Domain. Niemals ins Caddyfile hardcoden, immer ueber.envoder Docker Secrets.
Verifikation
1
2
3
4
5
6
# Redis sieht Caddys Cert-Eintraege?
docker exec -it redis redis-cli -a "$REDIS_PASSWORD" --scan --pattern "caddy*" | head
# Caddy-Status auf beiden Knoten
docker exec -it caddy caddy status
docker logs caddy --tail 30 | grep -i certificate
Wenn beide Knoten ein neues Service einlesen, holt nur einer das Zertifikat (der mit dem Redis-Lock), und der andere bekommt es automatisch zur Verfuegung gestellt.
Schritt 5: Floating VIP mit keepalived
VRRP - Funktionsprinzip
VRRP (Virtual Router Redundancy Protocol) hat einen einfachen Mechanismus: Mehrere Hosts teilen sich eine virtuelle IP, einer ist MASTER und schickt periodische Heartbeats an eine Multicast-Gruppe. Hoeren die anderen drei Heartbeats hintereinander nicht (Default: 3 Sekunden), uebernimmt der mit der naechsthoechsten Prioritaet die VIP.
stateDiagram-v2
[*] --> Init
Init --> Backup: niedrige Prio
Init --> Master: hoechste Prio
Master --> Fault: healthcheck failed
Master --> Backup: anderer mit hoeherer Prio gesehen
Backup --> Master: 3x Heartbeat verpasst
Fault --> Backup: healthcheck wieder ok
keepalived auf MASTER und BACKUP
1
sudo apt install -y keepalived
Auf caddy-01 (MASTER):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vrrp_script chk_caddy {
script "/usr/local/bin/check_caddy.sh"
interval 2
weight -20
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass changeMe123
}
virtual_ipaddress {
192.168.1.20/24
}
track_script {
chk_caddy
}
}
Auf caddy-02 (BACKUP) dieselbe Datei mit state BACKUP und priority 100. virtual_router_id muss identisch sein, auth_pass ebenfalls.
Healthcheck-Skript
1
2
#!/bin/sh
docker exec caddy wget -q -O - http://127.0.0.1:2019/config/ 2>/dev/null | grep -q apps
1
2
sudo chmod +x /usr/local/bin/check_caddy.sh
sudo systemctl enable --now keepalived
Das Skript prueft alle 2 Sekunden ueber Caddys Admin-API auf Port 2019, ob die Konfiguration geladen ist. Faellt der Check zweimal hintereinander aus, reduziert keepalived die Prioritaet um 20 - der Backup-Knoten hat dann effektiv 100 vs. 90 und uebernimmt die VIP.
virtual_router_id 51muss eindeutig im L2-Segment sein. Wenn dein Router pfSense/OPNsense mit CARP nutzt, kann es zu Konflikten kommen - eine andere ID waehlen (z.B. 91).
Schritt 6: Router und DHCP konfigurieren
Zwei DNS-Adressen an Clients verteilen
Im DHCP-Server (Router/UniFi/OPNsense) beide AdGuard-IPs als DNS-Server eintragen:
- Primary DNS:
192.168.1.10 - Secondary DNS:
192.168.1.11
Wichtig: das ist kein VIP-Setup. Clients fragen primaer .10 und fallen bei Timeout selbststaendig auf .11 zurueck. Diese Logik steckt schon in jedem modernen OS.
Port-Forwarding 80/443 auf VIP
Im Router 80 und 443 nicht auf caddy-01.21, sondern auf die VIP 192.168.1.20 weiterleiten. Wenn die VIP wandert, geht der Traffic automatisch zum neuen MASTER - ohne Aenderung am Router.
Internes Wildcard-DNS
In AdGuard Home eine Wildcard-Rewrite anlegen:
| Domain | Antwort |
|---|---|
*.example.com |
192.168.1.20 |
Damit zeigen alle internen Service-Hostnamen automatisch auf die VIP - der Caddy-Cluster uebernimmt von dort.
Failover-Tests
Hier kommt der wichtigste Teil: Ein HA-Setup, das nicht regelmaessig getestet wird, ist im Ernstfall haeufig kaputt. Die folgenden vier Tests solltest du nach dem ersten Setup einmal komplett durchspielen.
Test 1: Aktiven AdGuard-Node herunterfahren
1
2
3
4
5
ssh [email protected] "systemctl stop docker"
# Auf einem Client:
dig @192.168.1.10 example.com +short # Timeout
dig @192.168.1.11 example.com +short # 93.184.216.34
nslookup gitlab.example.com # Geht weiter, weil Client auf .11 faellt
Erwartung: Client merkt eine kurze Verzoegerung beim ersten Lookup, danach ist alles normal.
Test 2: Caddy-MASTER abschalten
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Vor dem Test: VIP-Status pruefen
ssh [email protected] "ip -br addr show eth0 | grep 192.168.1.20"
# -> .20 sollte hier sichtbar sein
# Master stoppen
ssh [email protected] "systemctl stop docker"
sleep 5
# Pruefen, wo die VIP jetzt haengt
ssh [email protected] "ip -br addr show eth0 | grep 192.168.1.20"
# -> jetzt auf .22
# HTTPS-Service testen
curl -sI https://gitlab.example.com | head -1
Erwartung: VIP wandert in ~3-5 Sekunden auf .22. Der Curl-Request kann einmal fehlschlagen, der zweite geht durch - Caddy auf .22 hat das Zertifikat aus Redis bereits gecached und beantwortet HTTPS sofort.
Test 3: Redis-Ausfall simulieren
1
2
3
4
5
6
7
8
9
ssh [email protected] "docker stop redis"
# Caddy laeuft erstmal weiter (Zertifikate sind im Memory-Cache)
curl -sI https://gitlab.example.com | head -1 # 200/301 OK
docker logs caddy --tail 20 | grep -i redis # Connection refused, retries
# Redis wieder hoch
ssh [email protected] "docker start redis"
docker logs caddy --tail 20 | grep -i redis # Reconnected
Erwartung: HTTPS-Traffic laeuft weiter, weil Caddy die Certs lokal cached. Renewal pausiert bis Redis wieder da ist.
Test 4: RTO messen
1
2
# In einem Terminal die VIP pingen, in einem anderen den Master killen
ping -i 0.2 192.168.1.20
Erwartung: 2-5 Pings verloren waehrend des Failovers, danach geht es weiter.
Monitoring der HA-Komponenten
Failover ist nichts wert, wenn niemand merkt, dass der Backup uebernommen hat - dann laeuft das Setup wochenlang auf nur einem Knoten und beim naechsten Ausfall ist Schluss.
Uptime Kuma
Uptime Kuma ist die einfachste Loesung fuer Homelabs. Wichtige Checks:
- DNS Test gegen
192.168.1.10:dig @192.168.1.10 google.com - DNS Test gegen
192.168.1.11: dito - HTTP/HTTPS gegen die VIP
https://gitlab.example.com - TCP gegen Caddys Admin-API auf
caddy-01:2019undcaddy-02:2019direkt - so siehst du, ob beide Knoten “alive” sind - TCP gegen
redis-01:6379
Prometheus-Metriken aus Caddy und keepalived
Caddy hat einen eingebauten Prometheus-Endpoint. Erweitere das Caddyfile um:
{
servers {
metrics
}
}
Danach liefert http://caddy-01:2019/metrics alle relevanten Metriken (Request-Zaehler, Response-Zeiten, Zertifikats-Ablaeufe).
Fuer keepalived gibt es den keepalived_exporter, der vrrp_state (1=MASTER, 2=BACKUP) als Metric exportiert. Mit Grafana kannst du dann visualisieren, wann genau die VIP gewandert ist.
Wichtige Alarmregel: Wenn beide Knoten
vrrp_state=1(MASTER) melden, hat dein Setup eine Split-Brain-Situation. Meistens Ursache: VRRP-Heartbeats kommen wegen Switch-Problemen nicht durch.
Komplexitaet vs. Verfuegbarkeit - die ehrliche Bilanz
Nicht jedes Homelab braucht ein vollstaendiges HA-Setup. Die folgende Tabelle hilft bei der Einschaetzung:
| Setup | Komplexitaet | Verfuegbarkeit | Hauptrisiken |
|---|---|---|---|
| Single AdGuard + Single NPM | Sehr niedrig | ~95% | Reboots, Crashes ziehen alles mit |
| Single AdGuard + Single Caddy | Niedrig | ~95% | wie oben, aber Auto-HTTPS |
| 2x AdGuard (Sync) + Single Proxy | Niedrig | ~97% | Proxy bleibt SPOF |
| 2x AdGuard + 2x Caddy + VIP + Redis | Mittel | ~99,5% | Redis-VM, Power, Switch |
| 2x AdGuard + 2x Caddy + VIP + Redis Sentinel | Hoeher | ~99,7% | Mehr Komplexitaet, Power, Switch |
| K3s/Docker-Swarm-Cluster | Hoch | ~99,5% | Mehr Fehlerquellen |
Die mittlere Variante (das hier beschriebene Setup) ist der Sweet Spot fuer die meisten Homelabs: ueberschaubar viel Aufwand, aber bereits unbemerktes Failover bei den haeufigsten Ausfallszenarien.
Fazit und Ausblick
Ein HA-Setup mit AdGuard Home, Caddy, Redis und keepalived ist im Homelab kein Hexenwerk - vier kleine VMs fuer DNS und Proxy, eine fuer Redis, ein Sync-Tool, ein Caddyfile auf beiden Proxy-Knoten, ein VRRP-Heartbeat. Der spuerbare Effekt: Wenn du das naechste Mal eine VM rebootest, merkt es niemand. Wenn ein Container crasht, uebernimmt der Backup. Wenn ein Proxmox-Node ungeplant ausfaellt, laufen die Services weiter, weil das Backup auf einem anderen Host liegt.
Was das Caddy-basierte Setup gegenueber Traefik+NFS so viel angenehmer macht: Caddy ist fuer HA designed, nicht retrofitted. Es gibt keinen “nur einer darf renewen”-Disclaimer, keine NFS-Locking-Sorgen, keine Split-Brain-Risiken auf Storage-Ebene. Beide Caddy-Knoten machen einfach ihren Job, Redis koordiniert.
Was als naechstes? Wer dieses Setup hat und mehr will:
- Redis Sentinel fuer echtes HA des Cert-Storage (3 Nodes mit Voting)
- Internes BGP zum Router fuer ECMP statt VRRP - jeder Knoten kann gleichzeitig Traffic bekommen
- K3s/Docker Swarm fuer wirklich verteilte Reverse-Proxy-Cluster
- Externes Object-Storage (S3 statt Redis) - cloud-native, eliminiert die Redis-VM komplett
Aber das ist alles “nice to have”. Mit dem Setup aus diesem Post sind die haeufigsten Ausfallszenarien im Homelab abgedeckt - und das ohne grosse Komplexitaet.
Weiterfuehrende Posts
- Pi-hole im Detail - DNS-Adblocker Grundlagen
- AdGuard Home im Detail - Modernes DNS-Filtering
- Nginx Proxy Manager im Detail - Reverse Proxy mit Web-UI
- Traefik im Detail - Container-natives Reverse-Proxy-Setup