Files
checkbot/deploy
patrickandClaude Sonnet 5.5 d2e2f829ad
test / pytest (3.11) (push) Waiting to run
test / pytest (3.13) (push) Waiting to run
feat: test base (logging with secret masking, timezone, Gitea workflow) and roadmap
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 01:24:24 +01:00
..

checkbot im Debian-LXC (Proxmox) betreiben

Alle Dateien in diesem Ordner sind geschrieben, aber noch auf keinem System ausprobiert. Beim ersten Lauf Meldungen genau lesen und Fehler zurückmelden.

Überblick

Browser --443--> Caddy (TLS, HSTS, /health nur intern) --127.0.0.1:8080--> uvicorn (1 Worker) --> SQLite
                                                                                 |
                                         Checkmk-REST, Ollama, Telegram, Matrix <-+  (nur ausgehend)
Pfad Inhalt Rechte
/opt/checkbot Code und .venv root, für checkbot nur lesbar
/etc/checkbot checkbot.env, master.key, session.secret Ordner 0750 root:checkbot, checkbot.env 0640, Schlüssel 0600 checkbot
/var/lib/checkbot SQLite-Datenbank 0750 checkbot
/var/backups/checkbot tägliche DB-Backups 0700 checkbot, Dateien 0600
/etc/caddy/Caddyfile aus Caddyfile.template gerendert root
Datei Zweck
setup-lxc.sh Erstinstallation (idempotent)
update.sh Update nach git pull mit Backup und Health-Check
backup.sh, systemd/checkbot-backup.* tägliches Backup
checkbot-cli CLI als Benutzer checkbot (wird als /usr/local/sbin/checkbot-cli verlinkt)
systemd/checkbot.service, systemd/checkbot-lxc-relaxed.conf Dienst und Drop-In für unprivilegierte LXCs
Caddyfile.template Reverse-Proxy
checkmk/checkbot-local-check Local Check für den Checkmk-Agent
nftables.conf optionale Firewall
checkbot.env.example Umgebungsdatei ohne Secrets

1. LXC in Proxmox anlegen

Auf dem Proxmox-Host (Template-Name vorher mit pveam available --section system prüfen, Container-ID, Storage, Bridge und Adressen anpassen):

pveam update && pveam download local debian-12-standard_12.7-1_amd64.tar.zst

pct create 210 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
  --hostname checkbot --unprivileged 1 --features nesting=1 \
  --cores 1 --memory 1024 --swap 512 --rootfs local-lvm:8 \
  --net0 name=eth0,bridge=vmbr0,ip=192.168.1.50/24,gw=192.168.1.1 \
  --nameserver 192.168.1.1 --searchdomain example.lan \
  --onboot 1 --start 1

nesting=1 braucht systemd für die Sandbox-Direktiven (PrivateTmp, ProtectSystem) in unprivilegierten Containern. Debian 13 funktioniert genauso (anderes Template).

Der FQDN der UI (z.B. checkbot.example.lan) muss im DNS auf die Container-IP zeigen.

2. Installation

Im Container als root:

apt-get update && apt-get install -y git
git clone <repo-url> /root/checkbot && cd /root/checkbot

CHECKBOT_FQDN=checkbot.example.lan CHECKBOT_MONITOR_IP=192.168.1.10 deploy/setup-lxc.sh

deploy/setup-lxc.sh --help zeigt alle Optionen. Wichtige Parameter:

Parameter Bedeutung
CHECKBOT_FQDN / --fqdn Hostname der UI (Standard hostname -f)
CHECKBOT_MONITOR_IP / --monitor-ip Monitoring-Server(n), die /health per HTTPS abrufen dürfen (Komma-getrennt)
CHECKBOT_TLS_MODE / --tls-mode internal (Caddy-interne CA, Standard) oder files
CHECKBOT_TLS_CERT, CHECKBOT_TLS_KEY PEM-Dateien für files (Zertifikat der Unternehmens-CA, mit Kette)
CHECKBOT_TZ / --tz Systemzeitzone des LXC (Standard Europe/Berlin, geprüft gegen /usr/share/zoneinfo). Die UI zeigt Zeiten samt Kürzel (CET/CEST). Lässt sich die Zeitzone im unprivilegierten LXC nicht setzen, warnt das Skript und fährt fort
--lxc-relaxed gelockertes systemd-Drop-In (siehe unten)
--no-prompt nie nachfragen

Das Skript installiert Pakete (inkl. Caddy), legt Benutzer und Verzeichnisse an, kopiert den Code, baut die venv, erzeugt master.key und session.secret (bestehende bleiben), legt checkbot.env an (bleibt bestehen), installiert die Units, rendert das Caddyfile und startet den Dienst erst danach.

Der erste Admin: mit Terminal fragt das Skript, sonst:

checkbot-cli create-admin

Danach https://<fqdn>/ öffnen, anmelden und den Setup-Assistenten durchlaufen.

Ist Caddy nicht im Debian-Repository, richtet das Skript das offizielle Caddy-Repository mit Signaturprüfung ein und gibt den Fingerabdruck des Schlüssels aus. Mit CHECKBOT_CADDY_KEY_FPR=<Fingerabdruck> kann er fest vorgegeben werden. Scheitert das, bricht das Skript mit dem Verweis auf die manuelle Installation ab.

TLS-Modi

  • internal: Caddy erzeugt eine eigene CA und stellt das Zertifikat aus. Browser und Clients müssen das Root-Zertifikat einmalig akzeptieren (siehe Fehlersuche).
  • files: eigenes Zertifikat der Unternehmens-CA. Das Skript kopiert die Dateien nach /etc/caddy/certs/checkbot.{crt,key} (Schlüssel 0640 root:caddy). Bei Erneuerung neue Dateien bereitstellen und setup-lxc.sh mit denselben Parametern erneut laufen lassen (oder die Dateien tauschen und systemctl reload caddy).

Logging

Der Bot schreibt Zeilen nach stderr, journald stempelt die Zeit (journalctl -u checkbot). Das Level steht in /etc/checkbot/checkbot.env als CHECKBOT_LOG_LEVEL (DEBUG, INFO, WARNING, ERROR, Standard INFO; ungültige Werte ergeben INFO plus Warnung), Änderung wirkt nach systemctl restart checkbot. Bekannte Secrets (Tokens, Checkmk-Secrets) sowie Muster wie /bot<token>/ und Bearer <token> werden aus Meldungen und Exception-Texten maskiert. Die Zeitzone (CHECKBOT_TZ) wird nur beim Setup gesetzt, siehe oben.

3. Erste Konfiguration in der UI

  • Checkmk: In Checkmk (Setup, Benutzer) einen Automation-User mit Rolle "Guest" bzw. einer Rolle mit reinem Lesezugriff auf Hosts und Services anlegen, Secret kopieren. In der UI URL der Site (inkl. Site-Name, z.B. https://checkmk.example.lan/<site>), User und Secret eintragen und den Verbindungstest ausführen.
  • Downtime (optional, standardmäßig aus): eigener Automation-User, der nur Downtimes setzen darf, mit eigenem Secret. Niemals das Secret des Lese-Users wiederverwenden.
  • Telegram: Bei @BotFather mit /newbot einen Bot anlegen und den Token eintragen. Chat-ID ermitteln: dem Bot (oder der Gruppe, in der er Mitglied ist) eine Nachricht schreiben und https://api.telegram.org/bot<TOKEN>/getUpdates im Browser öffnen, message.chat.id ablesen (Gruppen-IDs sind negativ). Danach den Token aus dem Browserverlauf löschen. Allowlist der Telegram-User-IDs füllen, sonst sind Befehle und Buttons aus.
  • Matrix: Auf dem Homeserver einen Bot-User anlegen, Access-Token erzeugen (z.B. per Login-API oder Element unter Einstellungen, Hilfe, Access-Token), unverschlüsselten Raum anlegen, den Bot einladen und beitreten lassen, Raum-ID (!abc:server) eintragen.
  • Ollama: Host-URL (z.B. http://office.sysops.de:11434), bei Reverse-Proxy mit Authentifizierung das Token, bei interner CA das CA-Feld. Die beiden Modelle (Alarmtext, Agent) einstellen und testen.

Erster Testlauf

Vor dem ersten echten Betrieb die Tests im Test-LXC laufen lassen, in einer eigenen Dev-venv und nicht unter /opt/checkbot (dort liegen weder Tests noch Dev-Abhängigkeiten):

apt-get install -y python3-venv python3-pip
cd /root/checkbot
python3 -m venv /root/checkbot-devenv
/root/checkbot-devenv/bin/pip install -r requirements-dev.txt
/root/checkbot-devenv/bin/pytest -x -q

Für eine vollständige Fehlerausgabe ohne -x und zum Sichern:

/root/checkbot-devenv/bin/pytest -q 2>&1 | tee pytest-run.log

Die Datei pytest-run.log geht unverändert an den Entwickler zurück (alle Fehler gesammelt, damit sie in einer Runde korrigiert werden). Integrationstests (-m integration) laufen nie versehentlich mit, sie sind standardmäßig ausgeschlossen.

4. Update

cd /root/checkbot && git pull && deploy/update.sh

Ablauf: DB-Backup, rsync, pip install -r, geänderte systemd-Units, Neustart, /health-Check mit bis zu 60 s Wartezeit. Der Check wertet die Datenbankprüfung aus. Nicht konfigurierte Teilchecks gelten nicht als Fehler.

Schlägt das Update fehl, nennt das Skript das letzte Backup und den zuletzt ausgerollten Commit. Rollback: im Checkout git checkout <vorheriger-commit>, deploy/update.sh erneut. Reicht das nicht (Schema-Migration lief schon), Datenbank aus dem Backup zurückspielen (Abschnitt 5). Die Migrationen sind vorwärts gerichtet, ein altes Programm kann eine neuere Datenbank unter Umständen nicht lesen, deshalb ist das Backup vor jedem Update Pflicht.

5. Backup und Restore

WICHTIG: master.key gehört nicht zusammen mit der Datenbank in dasselbe Backup. Ohne master.key sind alle gespeicherten Secrets (Tokens, Passwörter) unbrauchbar, mit master.key neben der DB hebt jeder Zugriff aufs Backup die Verschlüsselung auf. Sichere /etc/checkbot/master.key und session.secret separat (Passwortmanager, Tresor) und die DB-Backups an einem anderen Ort.

  • checkbot-backup.timer läuft täglich um 03:15 (zufällig bis 15 min versetzt, holt Versäumtes nach) und schreibt /var/backups/checkbot/checkbot-YYYYmmdd-HHMMSS.db (0600) über die SQLite-Backup-API, also konsistent bei laufendem Dienst. Es bleiben 14 Stück (CHECKBOT_BACKUP_KEEP).
  • Manuell: /opt/checkbot/deploy/backup.sh. Status: systemctl list-timers checkbot-backup.timer, Log: journalctl -u checkbot-backup.
  • Kopiere die Backups zusätzlich aus dem Container heraus (Proxmox-Backup des gesamten LXC reicht, ist aber dann inklusive master.key, siehe oben).

Restore:

systemctl stop checkbot
install -m 0600 -o checkbot -g checkbot /var/backups/checkbot/checkbot-<zeit>.db /var/lib/checkbot/checkbot.db
rm -f /var/lib/checkbot/checkbot.db-wal /var/lib/checkbot/checkbot.db-shm
systemctl start checkbot

Restore-Test (ohne den Betrieb zu stören), auf einer Kopie:

python3 -I -c "import sqlite3,sys; c=sqlite3.connect(sys.argv[1]); print(c.execute('PRAGMA integrity_check').fetchone()[0], c.execute('SELECT COUNT(*) FROM users').fetchone()[0], 'Benutzer')" \
  /var/backups/checkbot/checkbot-<zeit>.db

Erwartet: ok und eine plausible Benutzerzahl. Einen vollständigen Test machst du in einem zweiten Container oder lokal mit derselben master.key: DB und Schlüssel einspielen, Dienst starten, in der UI anmelden und prüfen, dass die Verbindungstests laufen (das beweist, dass die Secrets entschlüsselbar sind). Diesen Test nach der Einrichtung einmal durchführen.

6. Monitoring im Checkmk

Den Checkmk-Agent installiert setup-lxc.sh nicht.

Variante A: Agent mit Local Check (zeigt jeden Teilcheck als Service)

  1. In der eigenen Checkmk-Site: Setup, Agents, Linux, das .deb-Paket herunterladen und im Container mit apt-get install ./check-mk-agent_*.deb installieren.
  2. Host im Checkmk anlegen (IP des Containers), Service-Discovery ausführen.
  3. Local Check installieren:
install -m 0755 /opt/checkbot/deploy/checkmk/checkbot-local-check /usr/lib/check_mk_agent/local/checkbot-local-check

Für ein Intervall von 2 Minuten statt jeder Agent-Abfrage in /usr/lib/check_mk_agent/local/120/ ablegen. Der Check braucht nur das System-python3 und ruft http://127.0.0.1:8080/health direkt ab (nicht über Caddy). Andere URL: CHECKBOT_HEALTH_URL. Timeout 15 s, weil der Bot seine Backends selbst mit bis zu 10 s prüft.

Services: Checkbot_api, Checkbot_db, Checkbot_checkmk, Checkbot_ollama, Checkbot_poller, Checkbot_telegram, Checkbot_matrix.

Bewertung (Entscheidung):

Lage im /health Status
Teilcheck ok OK
Telegram/Matrix fehlen im JSON (in der UI deaktiviert) OK, "deaktiviert"
nicht konfiguriert (Checkmk, Ollama, Poller, aktivierter Chat-Adapter) WARN: der Bot ist ohne Konfiguration nicht voll funktionsfähig, aber nichts ist kaputt. Vor der Einrichtung ist WARN erwartbar
Fehler, Timeout, Poller-Zyklus überfällig CRIT
Bot nicht erreichbar oder ungültige Antwort CRIT für alle Services

Variante B: Active Check "HTTP" auf https://<fqdn>/health, erwarteter Status 200. Der Server braucht Zugriff (Monitoring-IP in CHECKBOT_MONITOR_IP) und muss der Caddy-CA vertrauen, sonst Zertifikatsprüfung ausschalten. Achtung: /health liefert 503, solange irgendein Teilcheck nicht ok ist, auch "nicht konfiguriert". Ein WARN/CRIT ist vor der vollständigen Einrichtung also normal, und die Detailtexte bekommt man nur im Body.

7. Firewall

Die Regeln in nftables.conf (Variablen oben anpassen, mit nft -c -f prüfen). In unprivilegierten LXCs lässt sich nftables oft nicht laden (fehlende Rechte für Netfilter im Container). Dann dieselben Regeln in der Proxmox-Firewall abbilden: Firewall am Datacenter, am Host und am Container (Reiter Firewall des CT) aktivieren, Eingangs-Policy DROP, Ausgangs-Policy DROP, dazu die Regeln:

Richtung Aktion Protokoll Quelle / Ziel Port Zweck
IN ACCEPT tcp Quelle Admin-Netz 22 SSH
IN ACCEPT tcp Quelle internes Netz 443 UI (HTTPS)
IN ACCEPT tcp Quelle internes Netz 80 nur HTTP-zu-HTTPS-Redirect (optional)
IN ACCEPT tcp Quelle Monitoring-Server 443 /health (Active Check)
IN ACCEPT tcp Quelle Monitoring-Server 6556 Checkmk-Agent (entfällt bei SSH-Agent)
IN ACCEPT icmp beliebig - Ping
OUT ACCEPT udp/tcp DNS-Server 53 DNS
OUT ACCEPT udp NTP-Server 123 Zeit
OUT ACCEPT tcp beliebig (oder Checkmk, Ollama-Proxy, api.telegram.org, Homeserver) 443 HTTPS-Ziele, apt
OUT ACCEPT tcp Ollama-Host 11434 Ollama direkt
OUT ACCEPT icmp beliebig - Ping

Weitere ausgehende Ziele (Checkmk per HTTP, Matrix auf 8448) bei Bedarf ergänzen. Telegram nutzt api.telegram.org auf 443, die IPs wechseln, deshalb dort nicht auf IPs einschränken.

8. Fehlersuche

systemctl status checkbot
journalctl -u checkbot -n 100 --no-pager      # App
journalctl -u caddy -n 100 --no-pager         # Proxy und Zugriffslog
curl -s http://127.0.0.1:8080/health          # direkt, ohne Caddy
Symptom Ursache und Abhilfe
Dienst startet nicht, "assertion failed ... master.key" /etc/checkbot/master.key fehlt. Aus der separaten Sicherung zurückspielen (0600, Besitzer checkbot). Nur bei einer Neuinstallation setup-lxc.sh erneut ausführen, das fehlende Schlüssel neu erzeugt (neue Schlüssel machen bestehende DB-Secrets unbrauchbar)
Exit-Code 217/USER Benutzer checkbot fehlt, setup-lxc.sh erneut ausführen
Exit-Code 226/NAMESPACE, 218/CAPABILITIES, 228/SECCOMP Sandbox-Direktiven im unprivilegierten LXC nicht erlaubt, siehe unten
Exit-Code 200/CHDIR oder 203/EXEC /opt/checkbot oder .venv fehlt, setup-lxc.sh bzw. update.sh ausführen
/health über Caddy: 403 Absicht. Nur 127.0.0.1 und CHECKBOT_MONITOR_IP; Setup mit der richtigen IP erneut ausführen
Login klappt nicht, kein Cookie App ist über HTTP statt HTTPS aufgerufen (Secure-Cookie), immer https:// verwenden
Browser warnt vor dem Zertifikat Caddy-interne CA, siehe unten
Checkmk-Test: SSL-Fehler Checkmk nutzt eine interne CA: Die CA-Datei auf den LXC legen und in der UI unter Checkmk im Feld "CA-Datei" eintragen (lesbar für den Benutzer checkbot). Für andere Ziele mit interner CA (z.B. Matrix-Homeserver) alternativ CA nach /usr/local/share/ca-certificates/, update-ca-certificates, SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt in checkbot.env aktivieren und systemctl restart checkbot (Annahme: httpx wertet SSL_CERT_FILE aus)
Caddy lädt nicht journalctl -u caddy; das Skript stellt die vorherige Datei /etc/caddy/Caddyfile.bak wieder her

Unprivilegierte LXCs: systemd-Direktiven

Zuerst im Proxmox-Host pct set <id> --features nesting=1 und den Container neu starten. Hilft das nicht, verursachen meist diese Direktiven die Exit-Codes 218, 226 oder 228:

Direktive typischer Fehler
ProtectSystem, ProtectHome, PrivateTmp, ReadWritePaths, RestrictNamespaces 226/NAMESPACE
ProtectKernelTunables/Modules/Logs, ProtectControlGroups 226/NAMESPACE
CapabilityBoundingSet 218/CAPABILITIES
SystemCallFilter, RestrictSUIDSGID, LockPersonality 228/SECCOMP

systemctl status checkbot und journalctl -u checkbot nennen die Direktive meist im Klartext. Abhilfe: setup-lxc.sh --lxc-relaxed erneut ausführen oder das Drop-In systemd/checkbot-lxc-relaxed.conf manuell nach /etc/systemd/system/checkbot.service.d/lxc-relaxed.conf kopieren (das Skript legt es auch für den Backup-Dienst an). Anschließend nur die Zeilen im Drop-In stehen lassen, die nötig sind. Die Datei überschreibt die Direktiven der Unit, systemctl daemon-reload && systemctl restart checkbot nicht vergessen.

Zertifikatsvertrauen für die Caddy-CA

Das Root-Zertifikat liegt im Container unter /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt (öffentlich, enthält keinen Schlüssel). Verteilen:

  • Debian/Ubuntu-Clients: cp root.crt /usr/local/share/ca-certificates/checkbot-caddy.crt && update-ca-certificates
  • Windows: als Administrator certutil -addstore -f Root root.crt oder per Gruppenrichtlinie in "Vertrauenswürdige Stammzertifizierungsstellen"
  • Firefox: eigener Speicher, Einstellungen, Zertifikate, Importieren (oder Richtlinie ImportEnterpriseRoots)
  • Checkmk-Server (für den Active Check): Zertifikat unter Setup, Allgemeine Einstellungen, "Site management", "Trusted certificate authorities for SSL" eintragen

Besser für den Dauerbetrieb: Modus files mit einem Zertifikat der Unternehmens-CA, der Clients ohnehin vertrauen.

9. Sicherheitscheckliste

  • Nach außen offen sind nur 443 (und 80 für den Redirect) aus dem internen Netz und SSH aus dem Admin-Netz; uvicorn lauscht nur auf 127.0.0.1 (ss -tlnp)
  • /etc/checkbot 0750 root:checkbot, master.key und session.secret 0600 checkbot, checkbot.env 0640
  • /opt/checkbot gehört root, checkbot kann dort nichts schreiben
  • master.key und session.secret sind getrennt von den DB-Backups gesichert
  • /health über Caddy nur von localhost und Monitoring-IP (von einem anderen Rechner testen: 403)
  • Automation-User in Checkmk hat nur Lese-Rolle; ein eventueller Downtime-User ist ein eigener User mit eigenem Secret, Downtime-Funktion nur bei Bedarf aktiv
  • Telegram-Allowlist und Matrix-Allowlist sind gefüllt, nur Admins haben Admin-Rolle, TOTP für Admins aktiv
  • Den Telegram-Token nie in Browserverlauf oder Chat stehen lassen; bei Verdacht Token in BotFather erneuern
  • Der Dienst läuft mit genau einem Worker (Rate-Limiter, TOTP-Einrichtung, Downtime-Bestätigungen liegen im Prozessspeicher)
  • Zugriffslog (journalctl -u caddy) enthält keine Query-Strings, Cookies, Authorization-Header (Stichprobe)
  • Updates des Containers: unattended-upgrades oder regelmäßig apt-get upgrade; danach prüfen, dass checkbot und caddy laufen