Eintrag

DNS und Reverse Proxy in HA: Hochverfuegbarkeit fuer dein Homelab

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-sync synchronisiert 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:

Single vs. HA Single vs. HA

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:

HA-Architektur HA-Architektur

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 (.21 MASTER, .22 BACKUP), 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 (.10 PRIMARY, .11 REPLICA), die per adguard-home-sync ihre 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-01 auf Host A, caddy-02/adguard-02 auf 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 yes ist 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 redis zeigt beide Caddy-Instanzen auf denselben Redis. Caddy nutzt das Plugin caddy-storage-redis, das redislock fuer verteiltes Locking verwendet.
  • acme_dns cloudflare aktiviert 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:Read und Zone.DNS:Edit fuer deine Domain. Niemals ins Caddyfile hardcoden, immer ueber .env oder 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 51 muss 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.

Failover-Ablauf Failover-Ablauf

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:2019 und caddy-02:2019 direkt - 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

Dieser Eintrag ist vom Autor unter CC BY 4.0 lizensiert.