Monitoring & Resilienz
Was macht es?
Uptime Monitoring prüft in regelmäßigen Abständen, ob die Backends deiner Routen erreichbar sind. Ohne Monitoring siehst du erst einen Fehler, wenn ein Benutzer ihn meldet.
Ohne Monitoring:
Client → Caddy → Backend (abgestürzt) → 502 Bad Gateway
↑ niemand weiß es
Mit Monitoring:
Monitor prüft alle 60s → Backend antwortet nicht → Status: DOWN (rot)
→ Email-Alert
→ Webhook: route_monitor_down
→ Circuit Breaker reagiert
Wie funktioniert es technisch?
GateControl startet einen Poller, der im konfigurierten Intervall (Standard: 60 Sekunden) alle Routen mit monitoring_enabled = 1 prüft.
HTTP-Routen (Layer 7):
- HTTP GET auf
http(s)://<Peer-IP>:<Target-Port>/ - User-Agent:
GateControl-Monitor/1.0 - Erwartung: Statuscode 200-399 = UP, alles andere = DOWN
- Bei
backend_https: HTTPS mitrejectUnauthorized: false(akzeptiert Self-Signed) - Timeout: konfiguriert in
config.timeouts.monitorHttp
L4-Routen (TCP/UDP):
- TCP Connect zum Backend-Port
- Verbindungsaufbau erfolgreich = UP, Timeout/Fehler = DOWN
- Timeout: konfiguriert in
config.timeouts.monitorTcp
Parallelisierung: Maximal 10 gleichzeitige Checks pro Zyklus.
Auto-WoL bei Gateway-Routen: Wenn eine Gateway-Route mit wol_enabled = 1 von UP auf DOWN wechselt, ruft der Monitor handleRouteDownDetected auf, das einen Magic Packet über das Gateway absetzt (gateways.notifyWol, Timeout 60s). So wacht der LAN-Host automatisch auf, wenn er ausgefallen ist — siehe concepts/home-gateway.md.
Gespeicherte Felder pro Route:
| Feld | Beschreibung |
|---|---|
monitoring_status |
up, down oder unknown |
monitoring_last_check |
Zeitpunkt der letzten Prüfung (ISO 8601) |
monitoring_response_time |
Antwortzeit in Millisekunden |
monitoring_last_change |
Zeitpunkt des letzten Statuswechsels |
Use Cases
Synology NAS überwachen
Route nas.example.com → Port 5001 (DSM). Monitoring erkennt, wenn das NAS nach einem Update neu startet. Du bekommst eine E-Mail, wenn es down geht, und eine zweite, wenn es wieder erreichbar ist.
Mehrere Dienste auf einem Server
Drei Routen zeigen auf denselben Peer, aber verschiedene Ports (3000, 8080, 5432). Ein Dienst stürzt ab — Monitoring zeigt genau welcher. Die anderen bleiben grün.
Circuit Breaker aktivieren
Monitoring ist Voraussetzung für den Circuit Breaker. Erst wenn Monitoring einen Ausfall erkennt, kann der Circuit Breaker die Route sperren und 503 zurückgeben, statt Anfragen ins Leere zu schicken.
Kombination mit anderen Features
| Kombination | Wirkung |
|---|---|
| Monitoring + Circuit Breaker | Monitoring-Checks treiben die State Machine des Circuit Breakers |
| Monitoring + Webhooks | Events route_down / route_up an externe Systeme (Slack, Discord, etc.) |
| Monitoring + Email-Alerts | Sofortige Benachrichtigung bei Statuswechsel |
| Monitoring + L4-Routen | TCP-Check statt HTTP-Check, erkennt Port-Erreichbarkeit |
Wichtige Hinweise
- Der erste Check läuft 10 Sekunden nach dem Start von GateControl — damit alle Dienste Zeit haben hochzufahren.
- Monitoring prüft die direkte Verbindung zum Backend (Peer-IP + Port), nicht den öffentlichen Domain-Zugang über Caddy.
- Bei
backend_https-Routen wird HTTPS verwendet, aber das Zertifikat nicht validiert — Self-Signed funktioniert. - Email-Alerts erfordern eine funktionierende SMTP-Konfiguration unter Settings → Email.
- Webhook-Events heißen
route_downundroute_up(nichtroute_monitor_down/route_monitor_up). - Das Monitoring-Intervall gilt global für alle Routen — individuelle Intervalle pro Route sind nicht möglich.
- Wenn Monitoring deaktiviert wird, bleibt der letzte Status stehen (wird nicht auf
unknownzurückgesetzt).
Was macht es?
Der Circuit Breaker erkennt, wenn ein Backend wiederholt nicht erreichbar ist, und schaltet die Route in einen Sperrmodus. Statt Anfragen ins Leere zu schicken (und Clients warten zu lassen), antwortet Caddy sofort mit 503.
Ohne Circuit Breaker:
Client 1 → Caddy → Backend (tot) → 30s Timeout → 502
Client 2 → Caddy → Backend (tot) → 30s Timeout → 502
Client 3 → Caddy → Backend (tot) → 30s Timeout → 502
... 100 Clients warten gleichzeitig 30 Sekunden ...
Mit Circuit Breaker:
Monitoring: Backend tot (5x hintereinander) → Circuit Breaker: OPEN
Client 1 → Caddy → 503 "Service temporarily unavailable" (sofort, <1ms)
Client 2 → Caddy → 503 (sofort)
... nach 30s Timeout ...
Monitoring: Backend wieder da → Circuit Breaker: CLOSED
Client 3 → Caddy → Backend → 200 OK ✓
Wie funktioniert es technisch?
Der Circuit Breaker implementiert eine State Machine mit drei Zuständen:
Threshold Failures erreicht
CLOSED ──────────────────────────────→ OPEN
↑ │
│ Check erfolgreich │ Timeout abgelaufen
│ ↓
└──────────────────────────────── HALF-OPEN
Check fehlgeschlagen ──→ OPEN
Zustände:
| Status | Caddy-Verhalten | Badge-Farbe |
|---|---|---|
| Closed | Normaler Betrieb, Anfragen werden weitergeleitet | Grün |
| Open | Caddy gibt sofort 503 mit Retry-After Header zurück |
Rot |
| Half-Open | Monitoring-Check wird durchgelassen; bei Erfolg → Closed, bei Fehler → Open | Amber |
Konfigurierbare Werte:
| Parameter | Standard | Beschreibung |
|---|---|---|
| Threshold | 5 | Aufeinanderfolgende Fehler bevor der Circuit öffnet |
| Timeout | 30s | Sekunden im Open-Status bevor ein Half-Open-Test stattfindet |
Ablauf im Detail:
- Monitoring prüft das Backend periodisch
- Bei Fehler: Failure-Counter wird inkrementiert (
cb_failure_countin derroutes-Tabelle — persistiert über Neustarts hinweg) - Bei Erfolg: Counter wird auf 0 zurückgesetzt
- Counter erreicht Threshold → Status wechselt zu
open,cb_opened_atwird gesetzt - Caddy-Config wird neu gebaut: Route liefert statische 503-Antwort
- Nach Timeout-Sekunden → Status wechselt zu
half-open - Nächster Monitoring-Check entscheidet:
- Erfolg →
closed, Caddy-Config wird wiederhergestellt - Fehler →
open, Timer startet neu
- Erfolg →
Caddy-Konfiguration im Open-Status (aus src/services/caddyConfig.js):
{
"handle": [{
"handler": "static_response",
"status_code": "503",
"body": "Service temporarily unavailable",
"headers": { "Retry-After": ["30"] }
}]
}
Der Retry-After-Wert entspricht dem konfigurierten Timeout (Default 30).
Use Cases
Request-Stau bei totem Backend verhindern
Ohne Circuit Breaker warten alle eingehenden Anfragen auf den Caddy-Timeout (30s). Bei 100 gleichzeitigen Clients sind das 100 blockierte Verbindungen. Mit Circuit Breaker werden alle sofort mit 503 beantwortet.
Thundering Herd bei Recovery verhindern
Backend war 5 Minuten down, 1000 Clients haben gecacht und warten auf Retry. Ohne Circuit Breaker treffen alle 1000 Anfragen gleichzeitig auf das gerade gestartete Backend. Mit Half-Open lässt der Circuit Breaker nur einen Monitoring-Check durch — erst wenn der erfolgreich ist, wird die Route wieder geöffnet.
Schnelles Feedback für bessere UX
Statt 30 Sekunden auf einen Timeout zu warten, sieht der Benutzer sofort eine "Service vorübergehend nicht verfügbar" Seite. Die Seite kann einen Retry-After Header enthalten, den moderne Browser respektieren.
Kombination mit anderen Features
| Kombination | Wirkung |
|---|---|
| Circuit Breaker + Monitoring | Pflicht: Monitoring-Checks treiben die State Machine |
| Circuit Breaker + Retry | Retry versucht es bei geschlossenem Circuit; bei offenem Circuit sofort 503 |
| Circuit Breaker + Load Balancing | Circuit Breaker greift wenn alle Backends down sind |
| Circuit Breaker + Webhooks | Events circuit_breaker_open / circuit_breaker_closed |
Wichtige Hinweise
- Monitoring ist Pflicht. Ohne aktiviertes Uptime Monitoring hat der Circuit Breaker keine Datenquelle und bleibt immer im Closed-Status.
- Failure-Counter und Open-Timestamp werden in der Datenbank persistiert (
cb_failure_count,cb_opened_at). Offene Circuits überleben Neustarts; fehlt der Timestamp nach einem Neustart, wird er beim ersten Check-Durchlauf neu gesetzt. - Der Circuit Breaker arbeitet pro Route, nicht pro Backend. Bei Load Balancing mit mehreren Backends öffnet der Circuit wenn das Monitoring-Ziel nicht erreichbar ist.
- Im Open-Status werden keine Anfragen ans Backend weitergeleitet — Caddy antwortet mit
503 Service Unavailable+Retry-After-Header. Kein Bypass per API oder einzelnem Request. - Manueller Reset (seit v1.50.4):
POST /api/v1/routes/:id/circuit-breaker/resetoder der Button Circuit-Breaker zurücksetzen im Route-Edit-Modal (nur sichtbar wenn Status ≠ closed). Setztcb_failure_count = 0,cb_opened_at = NULL, Status aufclosed, und re-rendert die Caddy-Config sofort. Ohne diesen Reset wartet ein offener Breaker auf den nächsten Monitoring-Zyklus und durchläuft den normalenopen → half-open → closed-Pfad. - Circuit Breaker ist nur für HTTP-Routen verfügbar, nicht für L4 (TCP/UDP).
Was macht es?
Rate Limiting zählt die Anfragen jeder Client-IP und blockiert weitere Anfragen, sobald das Limit erreicht ist. Der Client erhält dann HTTP 429 (Too Many Requests) statt einer normalen Antwort.
Ohne Rate Limiting:
Bot sendet 10.000 Anfragen/Minute → Backend bearbeitet alle → Server überlastet
Mit Rate Limiting (100 Anfragen/Minute):
Bot sendet 100 Anfragen → Backend bearbeitet alle ✓
Bot sendet Anfrage #101 → Caddy: 429 Too Many Requests ✕
Bot sendet Anfrage #102 → Caddy: 429 Too Many Requests ✕
... nach 1 Minute ...
Bot sendet Anfrage #1 → Backend bearbeitet ✓ (neues Zeitfenster)
Wie funktioniert es technisch?
GateControl nutzt das caddy-ratelimit Plugin für Route-Traffic. Der Rate-Limit-Handler wird vor dem Reverse Proxy in die Caddy Handler-Kette eingefügt (src/services/caddyConfig.js, rate_limit_enabled-Block).
Nicht zu verwechseln mit den Admin-API-Limitern (src/middleware/rateLimit.js): diese schützen das GateControl-Admin-UI (/login, /api/v1/*) und sind separat in Express konfiguriert. Das hier beschriebene Rate Limiting betrifft ausschließlich den Client-Traffic einer konfigurierten Route.
Caddy JSON-Konfiguration:
{
"handler": "rate_limit",
"rate_limits": {
"static": {
"key": "{http.request.remote.host}",
"window": "1m",
"max_events": 100
}
}
}
Schlüssel: {http.request.remote.host} — jede Client-IP bekommt ein eigenes Kontingent.
Konfigurierbare Werte:
| Parameter | Bereich | Standard | Beschreibung |
|---|---|---|---|
| Requests | 1 – 100.000 | 100 | Maximale Anfragen pro Zeitfenster |
| Window | 1s, 1m, 5m, 1h | 1m | Dauer des Zeitfensters |
Handler-Reihenfolge in Caddy:
- ACL / Forward Auth (falls aktiv)
- Custom Request Headers (falls vorhanden)
- Rate Limit ← hier
- Request Mirroring (falls aktiv)
- Compression (falls aktiv)
- Reverse Proxy
Use Cases
Login-Seite gegen Brute-Force schützen
Route app.example.com → Web-App mit Login. Rate Limit: 10 Requests / 1 Minute. Ein Angreifer kann maximal 10 Passwort-Versuche pro Minute machen — das verlangsamt Brute-Force-Angriffe erheblich.
API vor Missbrauch schützen
Route api.example.com → REST API. Rate Limit: 1000 Requests / 5 Minuten. Normale Nutzung bleibt unbeeinträchtigt, aber ein einzelner Client kann die API nicht überlasten.
Scraping verhindern
Route shop.example.com → Webshop. Rate Limit: 60 Requests / 1 Minute. Bots die Preise scrapen werden nach 60 Seitenaufrufen pro Minute gebremst.
Empfohlene Werte:
| Use Case | Requests | Window |
|---|---|---|
| Login-Seite | 10–20 | 1m |
| REST API | 500–1000 | 5m |
| Webshop / Website | 60–120 | 1m |
| Statische Assets | 1000–5000 | 1m |
| Webhook-Endpoint | 50–100 | 1m |
Kombination mit anderen Features
| Kombination | Wirkung |
|---|---|
| Rate Limit + Route Auth | Rate Limit nach Auth-Check — schützt Backend, nicht die Login-Seite |
| Rate Limit + Basic Auth | Rate Limit vor Auth — schützt auch gegen Brute-Force auf Basic Auth |
| Rate Limit + ACL | Nur VPN-Peers kommen durch, diese werden dann rate-limited |
| Rate Limit + IP-Filter | IP-Filter blockiert bekannte IPs, Rate Limit bremst den Rest |
| Rate Limit + Compression | Kein Konflikt — Rate Limit zählt Anfragen, Compression komprimiert Antworten |
Wichtige Hinweise
- Rate Limiting ist pro IP-Adresse, nicht global. 100 Requests/Minute bedeutet: jede einzelne IP darf 100 Anfragen stellen.
- Hinter einem NAT-Router teilen sich alle Clients dieselbe IP — das Limit gilt dann für alle zusammen.
- Erlaubte Window-Werte:
1s,1m,5m,1h. Andere Werte werden auf1mnormalisiert. - HTTP 429 enthält keinen
Retry-AfterHeader — der Client muss selbst warten bis das Fenster abläuft. - Rate Limiting ist nur für HTTP-Routen verfügbar, nicht für L4 (TCP/UDP).
- Bei Routen mit Forward Auth (Route Auth oder IP-Filter) wird Rate Limiting nach dem Auth-Check angewendet.
- WebSocket-Verbindungen zählen nur den initialen HTTP Upgrade als eine Anfrage.
Was macht es?
Wenn das Backend einen Fehler zurückgibt oder nicht erreichbar ist, wiederholt Caddy die Anfrage automatisch, anstatt sofort einen Fehler an den Client zu senden.
Ohne Retry:
Client → Caddy → Backend (gerade neugestartet) → 502 Bad Gateway → Client sieht Fehler
Mit Retry (3 Versuche):
Client → Caddy → Backend (Versuch 1: 502)
→ Backend (Versuch 2: 502)
→ Backend (Versuch 3: 200 OK) → Client sieht normale Antwort
Mit Retry + mehrere Backends:
Client → Caddy → Backend A (502)
→ Backend B (200 OK) → Client sieht normale Antwort
Wie funktioniert es technisch?
GateControl konfiguriert Caddys load_balancing.retries Mechanismus im Reverse-Proxy-Handler (src/services/caddyConfig.js, retry_enabled-Block):
Caddy JSON-Konfiguration:
{
"handler": "reverse_proxy",
"upstreams": [
{ "dial": "10.8.0.3:8080" }
],
"load_balancing": {
"retries": 3
}
}
Verhalten:
- Caddy wiederholt die Anfrage bis zu
retries-mal bei Verbindungsfehlern - Mit einem Backend: alle Retries gehen an dasselbe Backend
- Mit mehreren Backends: Retries rotieren zum nächsten Backend (Round Robin oder gewichtet)
- Die Retry-Logik ist Teil von Caddys Load Balancer — kein separater Handler
- Ausgelöst wird der Retry bei Connect-Fehlern und bei den Status-Codes aus dem UI-Feld Retry Status Codes. Diese Liste wird seit v1.50.4 tatsächlich an Caddy durchgereicht (
reverse_proxy.load_balancing.retry_match), zusammen mittry_duration: 5s(ohne das ignoriert Caddyretriessonst). Ungültige Tokens (nicht-numerisch, außerhalb 100–599) werden stillschweigend verworfen.
Konfigurierbare Werte:
| Parameter | Bereich | Standard | Beschreibung |
|---|---|---|---|
| Retry Count | 1 – 10 | 3 | Anzahl der Wiederholungsversuche |
| Retry Status Codes | CSV | 502,503,504 | Welche Response-Codes einen Retry triggern |
Use Cases
Backend-Neustart abfangen
Route app.example.com → Node.js App auf Port 3000. Beim Deployment wird die App kurz neu gestartet (2-3 Sekunden Downtime). Mit 3 Retries und einem Backend überbrückt Caddy diese Lücke — der Client bemerkt bestenfalls eine leicht längere Ladezeit.
Load Balancing mit Failover
Route api.example.com → 3 API-Server (Backend A, B, C). Server B fällt aus. Caddy versucht B, bekommt einen Fehler, und leitet die Anfrage automatisch an C weiter. Der Client merkt nichts.
Temporäre 503-Fehler bei hoher Last
Route service.example.com → Microservice der bei Überlastung 503 zurückgibt. Mit Retries hat der Service einen Moment Zeit sich zu erholen, und die nächste Anfrage geht durch.
Kombination mit anderen Features
| Kombination | Wirkung |
|---|---|
| Retry + Load Balancing | Retries rotieren zwischen Backends — effektiver als bei einem Backend |
| Retry + Circuit Breaker | Circuit Breaker verhindert Retries wenn das Backend dauerhaft down ist |
| Retry + Monitoring | Monitoring erkennt ob das Backend dauerhaft down ist; Retry hilft bei kurzen Aussetzern |
| Retry + Rate Limiting | Jeder Retry-Versuch zählt als eine Anfrage für das Backend, nicht für das Rate Limit des Clients |
Wichtige Hinweise
- POST/PUT/DELETE werden ebenfalls wiederholt. GateControl führt keine automatische Idempotenz-Prüfung durch — der Admin muss selbst wissen, ob das Backend wiederholbare Schreiboperationen unterstützt. Beispiel: Ein Retry auf
POST /api/orderskönnte eine doppelte Bestellung auslösen. Retry nur aktivieren wenn das Backend idempotente Operationen unterstützt oder nur GET-Anfragen verarbeitet. - Retry ist nur für HTTP-Routen verfügbar, nicht für L4 (TCP/UDP).
- Die Retries erfolgen sofort hintereinander — es gibt kein exponentielles Backoff.
- Bei einem einzelnen Backend können Retries den Server zusätzlich belasten, wenn er bereits überlastet ist.
- Retry Count von 1 bedeutet: 1 initialer Versuch + 1 Retry = maximal 2 Anfragen ans Backend.
- Retries sind für den Client unsichtbar — er bekommt entweder die erfolgreiche Antwort oder den letzten Fehler.
- In Kombination mit Circuit Breaker: Wenn der Circuit Breaker offen ist, werden keine Retries versucht (Caddy liefert sofort 503).