PatchMon mit Docker Compose: Linux-Patches zentral überwachen
Diese Anleitung zeigt, wie Sie die Linux-Patch-Management-Plattform PatchMon mit dem offiziellen Docker-Stack betreiben, den ersten Admin sicher anlegen, einen Debian-Host per Agent anbinden, die Datenbank sichern und nach einem Totalverlust wiederherstellen sowie Server und Agenten auf 2.1.6 aktualisieren.
Geprüft am 24.10.2026 · für PatchMon 2.1.6
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Welche Maschine hat offene Sicherheitsupdates, wo wartet ein Neustart, welcher Host meldet sich nicht mehr? PatchMon beantwortet diese Fragen in einer Weboberfläche. Ein kleiner Agent auf jedem Host meldet installierte Pakete, verfügbare Updates und Systemdaten an einen zentralen Server, von dem aus Sie Patches auch gezielt einspielen können. Das Projekt steht unter AGPL-3.0, hat rund 3.500 GitHub-Sterne und wurde am 23. Oktober 2026 im Newsletter Self-Host Weekly vorgestellt. Diese Anleitung zeigt den offiziellen Docker-Stack, die Anbindung eines Debian-Hosts, Backup, Restore und Update. Alle Meldungen stammen aus unserem Testlauf mit 2.1.5 und 2.1.6.
Voraussetzungen
- Ein Linux-Server, zum Beispiel Debian 12 oder Ubuntu 24.04, mit Docker Engine und Docker Compose v2. Die Grundinstallation beschreibt unsere Anleitung Docker Compose unter Linux als Selfhosting-Grundlage.
- Laut Projektdokumentation mindestens 1 GB RAM, empfohlen 2 GB. Im Leerlauf belegten in unserem Test Server, Datenbank, Redis und guacd zusammen rund 120 MB. 2 Kerne und 4 GB RAM lassen viel Luft für wachsende Host-Zahlen.
- Etwa 2 GB freier Speicher: Das Server-Image ist 779 MB groß, PostgreSQL und guacd kommen hinzu.
- x86_64 oder ARM64 für den Server. Agenten gibt es laut README für Linux (amd64, 386, arm64, arm), FreeBSD und Windows.
- Für den Produktivbetrieb einen Reverse Proxy mit gültigem TLS-Zertifikat und eine eigene Subdomain, zum Beispiel
patchmon.example.de. Die überwachten Hosts müssen diese Adresse erreichen.
Schritt 1: Compose-Datei und Geheimnisse vorbereiten
PatchMon liefert die Compose-Datei und eine kommentierte env.example im Ordner docker/ des Repositorys. Laden Sie beide und schreiben Sie die Image-Version fest, statt latest zu nutzen. So entscheiden Sie selbst, wann ein Update kommt.
mkdir -p /opt/patchmon && cd /opt/patchmon
curl -fsSL -o compose.yaml https://raw.githubusercontent.com/PatchMon/PatchMon/v2.1.6/docker/docker-compose.yml
curl -fsSL -o env.example https://raw.githubusercontent.com/PatchMon/PatchMon/v2.1.6/docker/env.example
sed -i 's#patchmon-server:latest#patchmon-server:2.1.6#' compose.yaml
cp env.example .env
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$(openssl rand -hex 32)/" .env
sed -i "s/^REDIS_PASSWORD=.*/REDIS_PASSWORD=$(openssl rand -hex 32)/" .env
sed -i "s/^JWT_SECRET=.*/JWT_SECRET=$(openssl rand -hex 64)/" .env
sed -i "s/^SESSION_SECRET=.*/SESSION_SECRET=$(openssl rand -hex 64)/" .env
sed -i "s/^AI_ENCRYPTION_KEY=.*/AI_ENCRYPTION_KEY=$(openssl rand -hex 64)/" .env
chmod 600 .env
Danach tragen Sie in der .env die Adresse ein, unter der Browser und Agenten PatchMon erreichen. Mehrere Adressen trennen Sie mit Komma ohne Leerzeichen:
CORS_ORIGIN=https://patchmon.example.de
TZ=Europe/Berlin
Die Compose-Datei selbst müssen Sie nicht anpassen. Ihr zentraler Teil ist der Server-Dienst, der die ganze .env per env_file übernimmt:
services:
server:
image: ghcr.io/patchmon/patchmon-server:2.1.6
restart: unless-stopped
hostname: patchmon-server
env_file: .env
environment:
GUACD_ADDRESS: "127.0.0.1:4822"
ports:
- "${PORT:-3000}:${PORT:-3000}"
depends_on:
database:
condition: service_healthy
redis:
condition: service_healthy
Der Dienst guacd teilt sich per network_mode: "service:server" den Netzwerk-Namensraum mit dem Server, läuft mit read_only: true, ohne Capabilities und mit Healthcheck. Datenbank und Redis prüfen ihre Bereitschaft ebenfalls per Healthcheck. Wie Sie eigene Stacks auf diese Art härten, erklärt die Anleitung Docker Compose absichern mit Secrets, Healthchecks und Non-Root.
| Eckdatum | Wert |
|---|---|
| Image | ghcr.io/patchmon/patchmon-server:2.1.6, dazu postgres:17-alpine, redis:7-alpine, guacamole/guacd:1.6.0 |
| Port | 3000 (Oberfläche, API und Agenten-WebSocket) |
| Volumes | postgres_data (alle Daten), redis_data (Warteschlangen) |
| Pflicht-Env | CORS_ORIGIN, JWT_SECRET, POSTGRES_PASSWORD, REDIS_PASSWORD, AI_ENCRYPTION_KEY, SESSION_SECRET |
| Lizenz | AGPL-3.0, Selbstbetrieb kostenlos, gehostete Variante PatchMon Cloud |
Verifizieren: docker compose config --quiet endet ohne Ausgabe, und grep -E '^[A-Z_]+=$' .env findet keine leeren Werte mehr. Bleibt JWT_SECRET leer, startet der Server später nicht (siehe Troubleshooting).
Schritt 2: Stack starten
docker compose up -d --pull always
docker compose ps
docker compose logs --no-log-prefix server | grep -E 'migrat|listening'
Beim ersten Start legt der Server das Datenbankschema an. In unserem Test, beim Erststart noch mit 2.1.5, waren alle vier Container nach weniger als 30 Sekunden healthy, das Log zeigte:
[migrate] applied successfully (version 58)
{"level":"INFO","msg":"redis connected","addr":"redis:6379"}
{"level":"INFO","msg":"server listening","version":"2.1.5","port":3000,"addr":":3000"}
Verifizieren: curl -s http://127.0.0.1:3000/health antwortet mit healthy. Die laufende Version zeigt docker inspect --format '{{index .Config.Labels "org.opencontainers.image.version"}}' $(docker compose ps -q server).
Schritt 3: Ersten Admin anlegen
Solange kein Admin existiert, zeigt PatchMon statt des Logins einen Einrichtungsassistenten. Wichtig: Wer die Seite zuerst erreicht, wird Superadmin. Öffnen Sie Port 3000 deshalb nicht ins Internet, bevor Sie den Assistenten abgeschlossen haben. Der Assistent fragt Name, Benutzername, E-Mail und Passwort ab (Standard: mindestens 8 Zeichen, Groß- und Kleinbuchstaben, Ziffer, Sonderzeichen) und bietet danach TOTP-MFA an. Nutzen Sie das für das Admin-Konto. Ohne Browser, etwa per SSH-Tunnel, geht es auch über die API, die der Assistent selbst aufruft:
read -rs PM_PW
jq -n --arg p "$PM_PW" '{firstName:"Erika",lastName:"Admin",username:"admin",email:"admin@example.de",password:$p}' \
| curl -s -H 'Content-Type: application/json' -d @- http://127.0.0.1:3000/api/v1/auth/setup-admin | jq -r .message
Die Antwort lautet Admin user created successfully mit HTTP 201, der Benutzer erhält die Rolle superadmin. Ein zweiter Aufruf wird abgewiesen.
Verifizieren: Ein erneuter Aufruf von /api/v1/auth/setup-admin liefert HTTP 400 mit Admin users already exist. This endpoint is only for first-time setup. Ab jetzt zeigt die Startseite das normale Login.
Schritt 4: Server-URL setzen und Host anbinden
Unter Settings legen Sie Protokoll, Host und Port fest, über die Agenten den Server erreichen, etwa https, patchmon.example.de und 443. Dieser Hostname muss in CORS_ORIGIN stehen, sonst lehnt der Server den Installer ab. Anschließend wählen Sie Hosts, Add Host, das Betriebssystem und einen Anzeigenamen. Der Assistent erzeugt einen Einzeiler mit einer API-ID und einem Schlüssel, die nur einmal angezeigt werden:
curl -s "https://patchmon.example.de/api/v1/hosts/install" \
-H "X-API-ID: patchmon_xxxxxxxxxxxxxxxx" \
-H "X-API-KEY: IHR_SCHLUESSEL" | sudo sh
Der Installer installiert bei Bedarf curl, tauscht ein fünf Minuten gültiges Bootstrap-Token gegen die endgültigen Zugangsdaten, legt /etc/patchmon/config.yml und credentials.yml an und lädt das passende Agent-Binary nach /usr/local/bin/patchmon-agent. Auf Servern mit systemd richtet er den Dienst patchmon-agent.service ein. Wir haben einen Debian-12-Host in einem Container ohne systemd angebunden, dort wich der Installer auf einen crontab-Eintrag aus und meldete:
✅ API credentials are valid
✅ Connectivity test successful
WARNING: No init system detected (systemd, OpenRC, or FreeBSD). Using crontab for service management.
SUCCESS: PatchMon Agent installation completed successfully!
Wenige Sekunden später stand der Host mit 133 Paketen, Debian GNU/Linux 12 (bookworm) und einem offenen Sicherheitsupdate für tzdata im Dashboard.


Verifizieren: Auf dem Host zeigt sudo patchmon-agent ping gültige Zugangsdaten, /etc/patchmon/logs/patchmon-agent.log enthält Report sent successfully und Initial report sent successfully. In der Oberfläche trägt der Host die Markierungen WS und Reporting.
Schritt 5: Hinter einen Reverse Proxy stellen
PatchMon nutzt WebSockets für Agenten, das Web-Terminal und RDP. Der Proxy muss diese durchreichen und X-Forwarded-Proto sowie X-Forwarded-For setzen. Mit Caddy reicht laut Projektdoku dieser Block, die langen Timeouts halten die dauerhaften Agentenverbindungen offen:
patchmon.example.de {
reverse_proxy 127.0.0.1:3000 {
transport http {
read_timeout 86400s
write_timeout 86400s
}
}
}
In der .env ergänzen Sie danach TRUST_PROXY=true und ENABLE_HSTS=true und starten den Server mit docker compose up -d neu. Binden Sie den Port anschließend an die Loopback-Adresse ("127.0.0.1:3000:3000") oder sperren Sie ihn per Firewall. Unsere Testinstanz lief hinter einem Reverse Proxy mit HTTPS, Login und Oberfläche funktionierten ohne weitere Anpassung. Grundlagen zu Caddy finden Sie in der Anleitung Caddy als Reverse Proxy mit automatischem HTTPS.
Verifizieren: curl -sI https://patchmon.example.de/health liefert HTTP 200, und die Agenten-Logs zeigen nach einem Neustart WebSocket connected.
Schritt 6: Backup und Restore
Alle Daten liegen in PostgreSQL: Hosts, Pakethistorie, Benutzer, Einstellungen und Logos. Redis hält nur Job-Warteschlangen. Zum Backup gehört zwingend die .env, denn AI_ENCRYPTION_KEY verschlüsselt laut Doku unter anderem OIDC-Secrets und Zugangsdaten für Benachrichtigungen. Geht der Schlüssel verloren, sind diese Werte nicht mehr lesbar.
mkdir -p backup
docker compose exec -T database sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > backup/patchmon-$(date +%F).dump
cp .env backup/env-$(date +%F)
Für den Test haben wir vorher eine Host-Gruppe Restore-Marker-2410 angelegt, gesichert und dann mit docker compose down -v beide Volumes gelöscht. Die Wiederherstellung startet zuerst nur Datenbank und Redis, spielt den Dump ein und fährt dann den Rest hoch:
docker compose up -d --wait database redis
docker compose exec -T database sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --exit-on-error --no-owner' < backup/patchmon-2026-10-24.dump
docker compose up -d
pg_restore endete mit Exit-Code 0, der Server meldete [migrate] already up to date. Login, Marker-Gruppe und der Debian-Host waren zurück. Der Agent verband sich nach der Ausfallzeit von selbst wieder. Weitere Optionen für Dumps beschreibt die Anleitung PostgreSQL mit pg_dump und pg_restore sichern.
Verifizieren: Nach dem Restore liefert /health den Wert healthy, das Login mit dem alten Passwort funktioniert, und Ihre Hosts stehen mit Status active in der Liste.
Schritt 7: PatchMon und Agenten aktualisieren
Wir haben mit 2.1.5 installiert und dann auf 2.1.6 gewechselt. Lesen Sie vorher die Release Notes, ziehen Sie ein frisches Backup und ändern Sie den Tag:
sed -i 's#patchmon-server:2.1.5#patchmon-server:2.1.6#' compose.yaml
docker compose pull server
docker compose up -d
Compose erstellte Server und guacd neu, Datenbank und Redis liefen weiter. 2.1.6 brachte keine Schemaänderung, das Log zeigte migrations: already up to date und "version":"2.1.6". Die Agenten bleiben zunächst auf ihrer Version. Mit aktivem Auto-Update ziehen sie beim nächsten Neustart oder täglichen Vollbericht nach. Sofort geht es auf der Host-Seite mit Force Agent Version Upgrade und Update Now. In unserem Test meldete der Agent nach rund 40 Sekunden Agent is up to date version=2.1.6. Für Update-Meldungen zu Containern hilft die Anleitung Docker-Container-Updates mit Diun und WUD.

Verifizieren: docker compose ps zeigt patchmon-server:2.1.6 als healthy, auf dem Host gibt patchmon-agent --version die Zeile patchmon-agent version 2.1.6 aus.
Troubleshooting
| Meldung | Ursache und Lösung |
|---|---|
{"code":"host_mismatch","error":"Host not allowed. Access this app via the URL configured in CORS_ORIGIN ..."}, HTTP 403 | Sie rufen PatchMon über eine Adresse auf, die nicht in CORS_ORIGIN steht, zum Beispiel über die Server-IP. Nur Loopback-Adressen sind immer erlaubt. Adresse ergänzen und docker compose up -d ausführen. |
{"code":"cors_mismatch","error":"CORS_ORIGIN mismatch. ..."}, HTTP 403 | Derselbe Fehler hinter einem Reverse Proxy: Der Proxy reicht einen Hostnamen per X-Forwarded-Host weiter, der nicht in CORS_ORIGIN steht. |
[fatal] config: JWT_SECRET is required | JWT_SECRET fehlt oder ist leer, der Server beendet sich sofort. Wert per openssl rand -hex 64 erzeugen und nie wieder ändern, sonst sind alle Sitzungen ungültig. |
Admin users already exist. This endpoint is only for first-time setup. | Der erste Admin wurde bereits angelegt. Melden Sie sich mit diesem Konto an. |
ERROR: Failed to fetch credentials. Bootstrap token may have expired. | Laut Doku ist das Token im Installationsbefehl nur fünf Minuten und einmal gültig. Befehl in der Oberfläche neu kopieren. |
| Agent bleibt bei „Waiting for connection“ | Host erreicht die Server-URL nicht, oder der Proxy leitet den WebSocket /api/v1/agents/ws nicht weiter. Auf dem Host curl -v https://patchmon.example.de/health prüfen. |
Die beiden Host-Fehler und das fehlende JWT_SECRET haben wir gezielt ausgelöst.
Häufige Fragen
Spielt PatchMon Updates selbstständig ein?
Nur, wenn Sie es anstoßen oder Richtlinien anlegen. Laut README gibt es selektives Patchen, Probeläufe, Freigaben, Zeitpläne und eine Patch-Historie. Für reine Sicherheitsupdates ohne zentrale Steuerung bleibt unattended-upgrades eine schlanke Alternative, PatchMon zeigt dann zumindest, wo etwas offen ist.
Welche Distributionen unterstützt der Agent?
Das README nennt die Paketmanager apt, dnf, yum, apk und pacman, dazu FreeBSD (pkg) und Windows. Seit 2.1.4 kommen laut Release Notes openSUSE und Alpine beim Patchen hinzu.
Muss ich Redis sichern?
In unserem Restore-Test nicht: Mit leerem Redis-Volume, Dump und .env war der Zustand vollständig zurück. Redis enthält laut Doku die Hintergrund-Warteschlangen.
Telefoniert PatchMon nach Hause?
Nutzungsstatistiken sind laut Doku Opt-in unter Settings, Metrics. Einmal täglich prüft der Server, ob eine neue Version verfügbar ist; der Newsletter im Assistenten sendet nur bei aktivem Schalter.
Fazit
PatchMon füllt die Lücke zwischen „jeder Server patcht sich selbst“ und schweren Automatisierungsplattformen: vier Container, ein Einzeiler pro Host, und offene Updates, Neustartbedarf und stumme Hosts sind auf einen Blick sichtbar. Im Test liefen Installation, Agent-Anbindung, Restore nach Totalverlust und das Update von Server und Agent ohne Nacharbeit. Ernst nehmen sollten Sie den offenen Einrichtungsassistenten direkt nach dem Start und die .env, die ins Backup gehört. PatchMon gehört hinter einen Proxy mit TLS und möglichst in ein VPN, denn das Admin-Konto kann auf allen Hosts Pakete installieren.
Weiterführende Anleitungen und Quellen
- Docker Compose unter Linux als Selfhosting-Grundlage
- Linux-Server absichern mit ufw und fail2ban
- Beszel: Server-Monitoring mit Docker
- PatchMon auf GitHub (Quellcode, README, Lizenz)
- Release Notes PatchMon 2.1.6 vom 17. Oktober 2026
- PatchMon Operator Guide (Installation, Env-Referenz, Agent)
- PatchMon-Dokumentation
- Self-Host Weekly vom 23. Oktober 2026


