Lesender Selbsttest (Version, Services, Hosts, Downtimes) beim Start und täglich 04:00, Seite /selftest, Teilcheck checkmk_api in /health, Chat-Meldung bei Wechsel. Toleranter Antwort-Parser (value/members, state_type int/String), Fallbacks für Host-Abfrage und Downtime-Liste, Fehlerhinweise je HTTP-Status. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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 undsetup-lxc.shmit denselben Parametern erneut laufen lassen (oder die Dateien tauschen undsystemctl 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
@BotFathermit/newboteinen Bot anlegen und den Token eintragen. Chat-ID ermitteln: dem Bot (oder der Gruppe, in der er Mitglied ist) eine Nachricht schreiben undhttps://api.telegram.org/bot<TOKEN>/getUpdatesim Browser öffnen,message.chat.idablesen (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. deploy/first-run.sh braucht kein root, legt eine eigene Dev-venv an (nicht unter /opt/checkbot, dort liegen weder Tests noch Dev-Abhängigkeiten) und erledigt alles in einem Lauf:
apt-get install -y python3-venv python3-pip # einmalig, als root
cd ~/checkbot
deploy/first-run.sh # optional: --venv <dir> --out <dir>
Ablauf: venv (Standard $HOME/checkbot-test-venv) anlegen, pip install -r requirements-dev.txt, import app.main, alle Jinja-Templates mit der App-Umgebung kompilieren, danach pytest -q ohne -x, damit alle Fehler in einer Runde zusammenkommen. Zum Schluss packt das Skript first-run-<Datum>.tar.gz (in --out, Standard das aktuelle Verzeichnis) mit pytest-Log, Import- und Template-Log, Python-Versionen, pip freeze, uname -a und der Git-Revision (falls ein Checkout vorliegt). Das Archiv enthält keine Umgebungsvariablen, Datenbanken, Schlüsseldateien und nichts aus /etc/checkbot.
Das Archiv geht unverändert an den Entwickler zurück. 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.keygehört nicht zusammen mit der Datenbank in dasselbe Backup. Ohnemaster.keysind alle gespeicherten Secrets (Tokens, Passwörter) unbrauchbar, mitmaster.keyneben der DB hebt jeder Zugriff aufs Backup die Verschlüsselung auf. Sichere/etc/checkbot/master.keyundsession.secretseparat (Passwortmanager, Tresor) und die DB-Backups an einem anderen Ort.
checkbot-backup.timerlä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)
- In der eigenen Checkmk-Site: Setup, Agents, Linux, das
.deb-Paket herunterladen und im Container mitapt-get install ./check-mk-agent_*.debinstallieren. - Host im Checkmk anlegen (IP des Containers), Service-Discovery ausführen.
- 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_checkmk_api, 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, checkmk_api ohne Checkmk-Konfiguration oder "noch nicht gelaufen") |
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, Selbsttest abweichend oder fehler (checkmk_api) |
CRIT |
| Bot nicht erreichbar oder ungültige Antwort | CRIT für alle Services |
Checkbot_checkmk_api liest nur den zuletzt gespeicherten Selbsttest-Lauf (siehe UI /selftest, Phase 6d), macht selbst keinen eigenen API-Aufruf. "noch nicht gelaufen" (kurz nach dem Start) zählt wie "nicht konfiguriert" als WARN.
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.crtoder 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/checkbot0750 root:checkbot,master.keyundsession.secret0600 checkbot,checkbot.env0640/opt/checkbotgehört root,checkbotkann dort nichts schreibenmaster.keyundsession.secretsind 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-upgradesoder regelmäßigapt-get upgrade; danach prüfen, dasscheckbotundcaddylaufen