Uptime Kuma Auto-Repair Architektur
🛠️ DIY & Open Source 🔧 Infrastruktur

Uptime Kuma Auto-Repair

Monitoring mit Selbstheilung: Uptime Kuma auf getrennter Instanz, Telegram-Alarme und ein Bash-Script, das bei Downtime automatisch Docker-Container neustartet — aber nur, wenn der RepairbyBot-Tag es erlaubt.

📅 Juni 2026 · Letztes Update: 07.06.2026

TL;DR

Ein Uptime Kuma auf einem externen Server überwacht alle Dienste. Fällt einer aus, schickt Kuma eine Telegram-Nachricht an einen Bot. Ein DevOps-Agent liest die Nachricht, prüft den RepairbyBot-Tag und startet — wenn er darf — automatisch den betroffenen Docker-Container neu. Keine LLM-Tokens, keine manuellen Eingriffe: Ein 150-Zeilen-Bash-Script macht alles autonom.

Stack: Uptime Kuma · Telegram Bot API · Bash · Docker · SQLite · SSH

1. Warum Monitoring mit Selbstheilung?

Klassisches Monitoring macht nur die Hälfte des Jobs: Es sagt dir, dass etwas kaputt ist. Die Frage „und wer fixt das jetzt?" bleibt offen — und landet um 3 Uhr nachts auf deinem Handy.

Die Lösung: Monitoring + Auto-Repair als geschlossener Kreislauf. Uptime Kuma erkennt Downtime → Telegram benachrichtigt den DevOps-Agenten → Der Agent prüft, ob er reparieren darf → Wenn ja: Container-Neustart, Verifikation, Erfolgsmeldung. Wenn nein: Eskalation mit Kontext.

Das Kernprinzip:

  • Getrennte Instanz: Kuma läuft auf einem anderen Server als die überwachten Dienste. Fällt der Produktivserver komplett aus, läuft Kuma weiter und meldet den Ausfall.
  • Explizite Freigabe: Nicht jeder Dienst darf automatisch repariert werden — der RepairbyBot-Tag entscheidet. Kein Tag = kein Auto-Repair.
  • 3-Strike-Regel: Kein盲er Alarm. Erst nach 3 aufeinanderfolgenden Downtime-Checks (9 Minuten) wird der Alarm ausgelöst und die Reparatur gestartet.
  • LLM-frei: Ein einfaches Bash-Script, getriggert per Cron. Kostet keine API-Tokens, läuft zuverlässig und deterministisch.

2. Architektur: Getrennte Instanzen

Der Monitoring-Server ist physisch vom Produktivserver getrennt — ein essenzielles Design-Prinzip:

┌─────────────────────────┐     ┌──────────────────────────┐
│  Monitoring-Server      │     │  Produktiv-Server         │
│  (Hetzner Cloud)        │     │  (Lokales RZ)             │
│                         │     │                           │
│  Uptime Kuma :3001      │────▶│  hotzmatic.com            │
│  ┌─ SQLite DB           │     │  Docker: nginx + sites    │
│  │─ Monitore (30+)      │     │  Gateway + API            │
│  │─ Tags (RepairbyBot)  │     │  Datenbanken              │
│  │─ Heartbeat-Historie  │     │                           │
│  └──────────────────────│     │                           │
│                         │     │                           │
│  🔴 DOWN → Telegram ────│────▶│  Telegram-Gruppe          │
│                         │     │  "IT Infrastructure"      │
└─────────────────────────┘     └──────────────────────────┘
                                          │
                                          ▼
                                   ┌──────────────┐
                                   │ DevOps-Agent  │
                                   │ (Bash-Script) │
                                   │              │
                                   │ Prüft Tag    │
                                   │ SSH → Docker │
                                   │ restart      │
                                   │ Verifikation │
                                   └──────────────┘

💡 Warum getrennte Instanzen? Würde Kuma auf demselben Server laufen, den es überwacht, wäre es beim Server-Ausfall selbst betroffen — und könnte keinen Alarm mehr senden. Die externe Instanz garantiert, dass Downtime immer erkannt und gemeldet wird.

3. Uptime Kuma Setup

3.1 Docker Compose

Uptime Kuma läuft als einzelner Docker-Container mit Host-Networking — schlank, kein Reverse Proxy nötig (die Monitoring-Instanz ist nur intern erreichbar):

# docker-compose.yml
services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    network_mode: host
    restart: unless-stopped
    volumes:
      - ./kuma:/app/data

network_mode: host gibt Kuma direkten Zugriff auf das Host-Netzwerk — es kann alle Dienste auf allen Interfaces erreichen. Das Volume ./kuma:/app/data persistiert die SQLite-Datenbank mit allen Monitoren, Heartbeats und Tags.

3.2 Monitore anlegen

Monitore folgen einer strengen Namenskonvention: {STANDORT} - {Dienst} — das gruppiert sie automatisch in der Sidebar:

PräfixStandortBeispiele
DCFHetzner Cloud FinnlandDCF - Docker, DCF - DNS, DCF - Dashboard
GD1Lokales RZGD1 - hotzmatic.com, GD1 - Factory Core
DCEExterne SaaSDCE - Mail Infrastructure

3.3 SQLite — das Geheimnis der Automatisierung

Uptime Kuma hat keine REST-API für Management-Operationen. Alle Automatisierung läuft über direkten SQLite-Zugriff:

# Alle Monitore mit Tags abfragen
ssh monitoring-host "docker exec uptime-kuma sqlite3 /app/data/kuma.db -json '
  SELECT m.name, t.name as tag, mt.value
  FROM monitor m
  JOIN monitor_tag mt ON m.id = mt.monitor_id
  JOIN tag t ON mt.tag_id = t.id
  WHERE m.active = 1
  ORDER BY m.name;
'"

💡 SQLite statt REST: Uptime Kuma nutzt intern WebSockets (Socket.IO), hat aber keine dokumentierte REST-API für CRUD-Operationen. SQLite-Direktzugriff ist die zuverlässigste Methode für Automation — schneller als Browser-Automation und komplett deterministisch.

4. Telegram-Integration

Downtime-Alarme landen in einer dedizierten Telegram-Gruppe. Der Ablauf:

  1. Bot erstellen via @BotFather → API-Token
  2. Bot in Gruppe einladen und zum Admin machen
  3. Chat-ID ermitteln via getUpdates-API
  4. In Kuma einrichten: Settings → Notifications → Telegram → Token + Chat-ID

Kuma sendet bei Statuswechsel automatisch:

🔴 DCF - Dashboard is down
Monitor: DCF - Dashboard
Status: Down
Time: 07.06.2026, 14:23:15
URL: https://dashboard.example.com
Error: timeout

⚠️ Bot braucht Admin-Rechte: Ohne Admin-Rechte in der Gruppe kann der Bot keine Nachrichten senden. Nach dem Einladen in der Gruppe auf „Administrator ernennen" klicken.

5. Tag-System: RepairbyBot

Nicht jeder Dienst darf automatisch repariert werden. Die Entscheidung trifft ein simples Tag-System in Kuma:

TagWertBedeutung
RepairbyBotTrue✅ Bot darf reparieren (Docker restart)
RepairbyBotFalse❌ Nur Alarm, keine automatische Reparatur
HostIP-AdresseWelcher Server hostet den Dienst

Tags werden direkt in der SQLite-Datenbank gesetzt — viel schneller als die UI für dutzende Monitore:

# RepairbyBot=True für alle DCF-Monitore
ssh monitoring-host "docker exec uptime-kuma sqlite3 /app/data/kuma.db '
  INSERT INTO monitor_tag (monitor_id, tag_id, value)
  SELECT m.id, 1, \"True\"
  FROM monitor m
  WHERE m.name LIKE \"DCF - %\" AND m.active = 1;
'"

Erreichbarkeit bestimmt den Tag-Wert: Nur Dienste, die per SSH vom Agenten erreichbar sind, bekommen RepairbyBot=True. Dienste im lokalen Netz (andere Subnetze) sind per Definition False — der Bot kann sie nicht erreichen, also auch nicht reparieren.

💡 Tag-Änderungen nur per SQL: Die Kuma-UI erlaubt keine nachträgliche Änderung von Tag-Werten — nur Löschen und Neu-Anlegen. Massen-Updates immer per UPDATE monitor_tag SET value = ... direkt in SQLite.

6. Auto-Repair-Script

Das Herzstück: Ein 150-Zeilen-Bash-Script, das per Cron alle 3 Minuten läuft — komplett LLM-frei, null Token-Verbrauch.

6.1 Der Ablauf

1. SQL-Abfrage: Alle RepairbyBot=True Monitore mit status=0 (DOWN)
2. Für jeden: Strike-Counter hochzählen (State-Datei)
3. Bei 3 Strikes (9 Minuten): Alarm per Telegram
4. SSH zum Produktivserver → docker restart aller exited Container
5. 60s warten → Heartbeat-Status erneut prüfen
6. Erfolg: "✅ Repariert" in Telegram
   Fehlschlag: "❌ Reparatur fehlgeschlagen" + Logs

6.2 Kernlogik (Auszug)

#!/bin/bash
MAX_STRIKES=3

# 1. Aktuelle Downtimes abfragen (nur RepairbyBot=True)
DOWN_JSON=$(ssh monitoring-host \
  "docker exec uptime-kuma sqlite3 /app/data/kuma.db -json '
    SELECT m.id, m.name, h.msg
    FROM monitor m
    JOIN monitor_tag mt ON m.id = mt.monitor_id
      AND mt.tag_id = 1 AND mt.value = \"True\"
    LEFT JOIN heartbeat h ON h.id = (
      SELECT id FROM heartbeat
      WHERE monitor_id = m.id ORDER BY time DESC LIMIT 1
    )
    WHERE h.status = 0 AND m.active = 1;
  '")

# 2. Strikes zählen
for monitor in $DOWN_MONITORS; do
  COUNT=$((COUNT + 1))
  if [ $COUNT -ge $MAX_STRIKES ]; then
    tg_send "⚠️ Downtime gesichert: $NAME — starte Reparatur..."

    # 3. Reparieren: Docker-Container neustarten
    ssh prod-host "docker restart $(docker ps -aq --filter status=exited)"

    sleep 60

    # 4. Verifikation
    if kuma_status_check $MONITOR_ID; then
      tg_send "✅ Repariert: $NAME ist wieder online!"
    else
      tg_send "❌ Reparatur fehlgeschlagen: $NAME"
    fi
  fi
done

6.3 Cron-Job

Das Script läuft alle 3 Minuten als no_agent-Job — kein LLM, keine API-Kosten:

# Cron: alle 3 Minuten, nur Script, kein Agent
Schedule: every 3m
Script: repair-agent.sh
No-Agent: true → stdout wird direkt delivered

⚠️ 3-Strike-Fenster: Bei 60-Sekunden-Check-Intervall von Kuma + 3-Minuten-Cron des Scripts ergeben sich etwa 9 Minuten vom ersten Ausfall bis zur Reparatur. Das ist bewusst konservativ — verhindert盲e Aktionen bei kurzen Netzwerkaussetzern.

7. Betrieb & Lessons Learned

Was gut läuft

  • Getrennte Instanz nie betroffen: Egal was auf dem Produktivserver passiert — Kuma läuft und meldet. Kein „der Server ist down, aber keiner weiß es"-Szenario.
  • SQLite ist schneller als jede API: Tag-Queries in <100ms, keine Authentifizierung, keine Sessions. Für Automation unschlagbar.
  • Bash statt LLM spart massiv Tokens: 3-Minuten-Takt × 480 Läufe/Tag = 480 Mal kein LLM-Aufruf. Bei einem Modell mit $0.14/M-Token summiert sich das schnell.
  • RepairbyBot-Tag als Sicherheitsbarriere: Kein Risiko, dass der Bot versehentlich kritische Produktivdienste neustartet. Nur explizit freigegebene Dienste sind betroffen.

Lessons Learned

  • Neue Monitore ohne Heartbeat lösen False-Alarms aus: Ein frisch angelegter Monitor hat noch keinen Heartbeat-Eintrag — ein IS NULL in der Abfrage wertet ihn fälschlich als DOWN. Fix: WHERE h.status = 0 (nur existierende Heartbeats, kein IS NULL).
  • SQLite WAL-Mode erlaubt paralleles Lesen: Uptime Kuma nutzt WAL (Write-Ahead Logging) — das Script kann die DB lesen, während Kuma schreibt. Keine Locks, keine Race Conditions.
  • Strike-State-Datei ist kritisch: Ohne State würde jeder Poll einen neuen Alarm auslösen. /tmp/kuma-monitor-state.txt zählt Strikes pro Monitor — und wird zurückgesetzt, sobald der Monitor wieder UP ist.
  • Erholungserkennung nicht vergessen: Das Script prüft nicht nur auf DOWN, sondern auch: „War vorher DOWN, ist jetzt UP?" → State-Eintrag löschen und „Alle Dienste online"-Nachricht senden.

Monitoring des Monitorings

  • Kuma-Health: curl https://uptime.hotzmatic.com → 200 = Kuma selbst ist erreichbar
  • Cron-Status: hermes cronjob list → checken ob der Repair-Job läuft
  • Script-Logs: hermes cronjob log <job-id> → letzte Ausgaben des Repair-Scripts

8. Fazit & Ausblick

✅ Das funktioniert

  • Getrennte Monitoring-Instanz (Hetzner)
  • Telegram-Alarme mit Bot-Integration
  • 3-Strike-Regel gegen盲e Alarme
  • Auto-Restart per Docker + SSH
  • RepairbyBot-Tag als Sicherheits-Gate
  • LLM-frei: 0 Token-Kosten

🔜 Geplant

  • KI-Agent für komplexe Diagnosen
  • Service-Restart statt Docker-Restart
  • Metriken-basierte Schwellwerte
  • Öffentliche Status-Page

Die Kombination Uptime Kuma + Telegram + Bash-Script ist ein Paradebeispiel für pragmatische Automatisierung: einfache Bausteine, klare Verantwortlichkeiten, null laufende Kosten. Die getrennte Instanz und das Tag-System sorgen für Sicherheit — der Bot repariert nur, was er reparieren darf, und nur, was er erreichen kann.

🤖 KI-Agenten-Integration

Für komplexere Fehler (die über „Container neustarten" hinausgehen) ist ein KI-DevOps-Agent in Vorbereitung. Er analysiert Logs, prüft Abhängigkeiten und entscheidet kontextbasiert — aber nur, wenn der RepairbyBot-Tag es erlaubt. Der einfache Bash-Repair bleibt als erste Verteidigungslinie bestehen.


Disclaimer: Persönliches Projekt. Uptime Kuma ist Open Source (MIT). Keine Affiliate-Links. Die beschriebene Architektur reflektiert den tatsächlichen Produktivbetrieb.