Kurz gesagt
Problem: Ein Container, der still und leise stoppt, eine Platte, die vollläuft, ein Dienst, der die falsche Seite liefert: Auf einem Heimserver merkt man das meist erst, wenn jemand aus der Familie sagt „es geht nicht“.
Lösung: Home Assistant überwacht den Docker-Host so, wie es auch den Rest des Hauses überwacht: eine Entität pro Container, Host-Werte, HTTP-Prüfungen von außen, den Backup-Status und eine Handvoll Automationen, die eine Telegram-Nachricht schicken, wenn etwas nicht stimmt.
Getestet mit: Home Assistant 2026.10, der Portainer-Integration, meinem eigenen Add-on SSH Linux Management (MQTT), etwa 25 Containern auf einem Docker-Host, Telegram und der Companion-App für Benachrichtigungen
Home Assistant weiß schon, wie es mir sagt, dass ein Fenster offen oder eine Batterie leer ist. Statt also ein eigenes Monitoring für meinen Server zu betreiben, lasse ich Home Assistant auch den überwachen. Alles landet an einem Ort: ein Dashboard, ein Benachrichtigungskanal und Automationen, die ich ohnehin schreiben kann. Dieser Artikel zeigt die zwei Integrationen, mit denen ich den Docker-Host in Home Assistant bringe, die Alarme, die darauf aufbauen, und was ich dabei gelernt habe.
1. Zwei Integrationen, zwei Aufgaben
Home Assistant läuft in einer VM, die Container auf dem Host daneben. Um in den Host hineinzuschauen, nutze ich zwei Integrationen, weil jede in etwas anderem gut ist:
| Portainer-Integration | SSH Linux Management (Add-on) | |
|---|---|---|
| Verbindet sich über | Die API von Portainer mit einem Zugriffstoken | Eine SSH-Verbindung zum Host |
| Pro Container | Status, CPU, Speicher, Neustart-Zähler, Out-of-Memory, Image-Updates, Buttons zum Neustarten/Pausieren/Neuerstellen | Läuft an/aus als Schalter, Neustart-Button |
| Wie schnell | In festen Abständen abgefragt | Vom Docker-Event-Stream geschoben, sofort |
| Host | – | CPU, RAM, Plattenbelegung pro Mountpoint, libvirt-VMs |
| Extra | – | Liest die Statusdatei meines Backup-Setups |
Für die Alarme unten nutze ich die Status-Sensoren von Portainer für die Container und das SSH-Add-on für alles rund um den Host. Wenn du nur eine willst, fang mit Portainer an: Das ist eine eingebaute Integration und liefert pro Container am meisten.
2. Die Portainer-Integration
Läuft Portainer schon auf deinem Docker-Host, ist das der schnellste Einstieg:
- In Portainer dein Benutzerprofil öffnen → Access tokens → Add access token, und den Token kopieren.
- In Home Assistant: Einstellungen → Geräte & Dienste → Integration hinzufügen → Portainer, die Adresse von Portainer und den Token eintragen.
- Home Assistant legt ein Gerät pro Container an, mit Entitäten wie
binary_sensor.<container>_status,sensor.<container>_memory_usage,sensor.<container>_restart_countundupdate.<container>_image_update_available.
Der Token kann, was sein Benutzer kann: Mit dem Token eines Admins kann Home Assistant jeden Container stoppen und neu erstellen. Leg für Home Assistant einen eigenen Portainer-Benutzer an, wenn deine Edition Rollen unterstützt, und behandle den Token wie ein Passwort: Er liegt in der Konfiguration von Home Assistant, also auch in dessen Backups.
Eine Sache macht Portainer nicht: Löschst du einen Container, bleibt sein Gerät in Home Assistant als „nicht verfügbar“ stehen. Entferne es von Hand (Einstellungen → Geräte, das Gerät, Löschen), sonst füllen sich deine Dashboards und Automationen langsam mit toten Entitäten.
3. Das SSH-Add-on: Host-Werte ohne root
Für den Host selbst (Platte, CPU, RAM, VMs) habe ich ein kleines Home-Assistant-Add-on geschrieben, SSH Linux Management. Es öffnet eine ausgehende SSH-Verbindung zum Host und veröffentlicht, was es findet, per MQTT-Discovery, sodass die Entitäten ohne YAML in Home Assistant erscheinen:
- Docker: Der entfernte Docker-Socket wird durch die SSH-Verbindung weitergeleitet. Es wird kein Docker-TCP-Port geöffnet, und Änderungen an Containern kommen sofort über den Docker-Event-Stream an.
- Host-Werte: CPU, Speicher und Plattenbelegung pro Mountpoint (ich beobachte
/und die Datenplatte von Nextcloud). - VMs: libvirt-VMs als Schalter mit Neustart-Button, über
virshauf derselben Verbindung. - Das SSH-Konto ist nicht root: Es ist ein normaler Benutzer in der Gruppe
docker(undlibvirt), und der Host-Schlüssel wird bei der ersten Verbindung festgehalten.
Sei ehrlich zur Gruppe docker: Wer mit dem Docker-Socket sprechen kann, kann einen Container starten, der das Root-Dateisystem des Hosts einbindet. Mitglied dieser Gruppe zu sein heißt praktisch, root auf diesem Rechner zu sein. „Nicht root“ bedeutet hier: kein Root-Passwort in Home Assistant, ein eigener Schlüssel, den du sperren kannst, und nichts anderes, wo sich dieses Konto anmelden kann. Wenn du echte Grenzen willst, setz einen Docker-Socket-Proxy davor, der nur die API-Aufrufe erlaubt, die du brauchst.
Eine Lehre aus dem Betrieb: Die ersten Versionen haben jede Docker-Entität nach der ID des Containers benannt. Jedes docker compose up nach einem Update erzeugt aber einen neuen Container mit neuer ID, also bekam Home Assistant jedes Mal eine neue Entität, und nach ein paar Wochen hatte ich switch.…_traefik, …_traefik_2 bis …_traefik_5. Version 0.11.0 benennt die Entitäten nach dem Namen des Containers und entfernt Discovery-Einträge von Containern, die es nicht mehr gibt. Wenn du selbst MQTT-Discovery schreibst: Nimm für die unique_id etwas, das ein Neuerstellen überlebt.
4. Alarm: ein Container ist gestoppt
Die wichtigste Automation ist auch die einfachste: Ist der Status-Sensor eines Containers zwei Minuten lang aus, kommt eine Nachricht mit seinem Namen. Die zwei Minuten verhindern Fehlalarme bei normalen Neustarts (Updates, Neuerstellen):
alias: System - Docker - Container Down Alert
description: Ein überwachter Container läuft 2 Minuten nicht → Telegram + Push.
mode: parallel
max: 10
triggers:
- trigger: state
entity_id:
- binary_sensor.traefik_status
- binary_sensor.crowdsec_status
- binary_sensor.authentik_server_status
- binary_sensor.nextcloud_nextcloud_1_status
- binary_sensor.vaultwarden_status
- binary_sensor.zigbee2mqtt_status
# … eine Zeile pro Container, der dir wichtig ist
to: "off"
for:
minutes: 2
actions:
- action: telegram_bot.send_message
data:
title: "🔴 Docker-Container gestoppt"
message: "{{ trigger.to_state.attributes.friendly_name }} läuft seit 2 Minuten nicht."
- action: notify.mobile_app_dein_handy
data:
title: "🔴 Docker-Container gestoppt"
message: "{{ trigger.to_state.attributes.friendly_name }} läuft seit 2 Minuten nicht."
mode: parallel: Startet Docker selbst neu, stoppen mehrere Container gleichzeitig. Jeder soll seine eigene Nachricht bekommen, nicht nur der erste.to: "off", nicht „nicht an“: Ein Sensor, derunavailablewird (Portainer nicht erreichbar, Container gelöscht), löst nicht aus. Das ist Absicht: Es verhindert eine Flut von Alarmen, wenn Portainer neu startet, heißt aber auch, dass ein gelöschter Container still aus der Überwachung fällt.
Tipp: Die Liste der Sensoren ist die Schwachstelle. Fügst du einen Container hinzu, benennst ihn um oder entfernst ihn, muss sich die Liste mit ändern, sonst wird der neue Container nie überwacht und der alte bleibt als toter Eintrag stehen. Ich prüfe sie zusammen mit dem Backup-Job jedes neuen Containers. Ein Label an den Status-Sensoren und ein Trigger auf dieses Label würden diesen Schritt sparen, um den Preis, das Label an jedem neuen Sensor zu setzen.
5. Laufen heißt nicht funktionieren: HTTP-Prüfungen
Ein Container kann „laufen“, während der Dienst darin eine Fehlerseite liefert oder der Reverse Proxy davor den Verkehr ins Leere schickt. Deshalb ruft Home Assistant alle zehn Minuten auch die öffentlichen Adressen auf, so wie es ein Besucher tun würde, und prüft den HTTP-Statuscode. Die Aufrufe sind shell_command-Einträge in der configuration.yaml:
shell_command:
curl_check_nextcloud: "curl -s -o /dev/null -w '%{http_code}' --max-time 10 https://cloud.example.com/status.php"
curl_check_traefik: "curl -s -o /dev/null -w '%{http_code}' --max-time 10 https://traefik.example.com/dashboard/"
Die Automation führt jeden Befehl aus, liest den Statuscode aus der Antwort und vergleicht ihn mit dem, was dieser Dienst antworten sollte:
triggers:
- trigger: time_pattern
minutes: "/10"
actions:
- action: shell_command.curl_check_traefik
response_variable: traefik
- if:
- condition: template
value_template: "{{ traefik.stdout not in ['302', '401'] }}"
then:
- action: telegram_bot.send_message
data:
title: "🔴 Prüfung Traefik-Dashboard fehlgeschlagen"
message: "Erwartet war ein Login (302/401), gekommen ist {{ traefik.stdout }}."
- Prüf auf die richtige Antwort, nicht auf irgendeine. Mein Traefik-Dashboard und mein Wiki liegen hinter Single Sign-on, also müssen sie mit einer Umleitung zum Login (302) oder 401 antworten. Ein
200hieße, dass sie plötzlich für alle offen sind. Die Prüfung erwischt einen kaputten Login, nicht nur einen kaputten Dienst. - Plane Wartung ein. Mein nächtliches Nextcloud-Backup schaltet den Wartungsmodus ein, der mit 503 antwortet. Zwischen 02:55 und 04:30 Uhr ignoriert die Automation genau diesen Code für Nextcloud, und nur diesen.
6. Plattenplatz und der Host
Eine volle Platte ist der klassische Grund, warum ein ganzer Server auf einmal ausfällt: Datenbanken schreiben nicht mehr, Container stürzen ab, Logs, die das erklären würden, können nicht geschrieben werden. Mit den Platten-Sensoren des SSH-Add-ons ist das ein Trigger aus zwei Zeilen:
triggers:
- trigger: numeric_state
entity_id:
- sensor.ssh_host_myserver_host_disk_use
- sensor.ssh_host_myserver_host_disk_use_data
above: 85
actions:
- action: telegram_bot.send_message
data:
message: "⚠️ {{ trigger.to_state.attributes.friendly_name }} ist zu {{ trigger.to_state.state }} % belegt."
Bei 85 % habe ich Tage, nicht Minuten, um zu reagieren. Dieselben Sensoren stehen als Anzeigen auf dem Dashboard, neben CPU und Speicher.
7. Backups und Updates
- Backups: Ein Skript auf dem Host schreibt alle fünf Minuten den Zustand jedes Backup-Jobs in eine JSON-Datei. Das SSH-Add-on liest diese Datei und legt einen Sensor pro Job an, dazu einen Binärsensor „Backup-Problem“. Ist der zehn Minuten lang an (ein Job ist fehlgeschlagen, ein Snapshot ist älter als 26 Stunden, die Backup-Platte ist nicht eingehängt), bekomme ich eine Nachricht mit dem Grund. Die Details stehen in meinem Backup-Artikel.
- Updates: Eine Automation startet dreimal pro Woche um 04:00 Uhr mein Docker-Update-Skript per SSH (
docker compose pullundup -dpro Stack). Der Container-Alarm oben ist das Sicherheitsnetz: Macht ein Update einen Container kaputt, weiß ich es vor dem Frühstück. Beim Reverse Proxy hält eine feste Hauptversion dieses Risiko klein (siehe meinen Traefik-Artikel). - Versionswechsel: Für Zigbee2MQTT speichere ich zusätzlich die zuletzt bekannte Version in einem
input_text-Helfer und schicke eine Nachricht, wenn sie sich ändert, mit der Erinnerung, die Release Notes zu lesen. Das habe ich eingebaut, nachdem ein Update das Verhalten einiger Geräte geändert hatte und ich es erst Tage später bemerkt habe.
8. Das Dashboard
Eine Ansicht „Server“ auf meinem Haupt-Dashboard zeigt die Host-Anzeigen (CPU, RAM, beide Platten), den Backup-Status und eine Kachel pro Container. Jede Kachel zeigt, ob der Container läuft, und ein Tipp auf ihr Symbol startet ihn neu:
type: tile
entity: switch.ssh_host_myserver_docker_vaultwarden
name: Vaultwarden
icon: mdi:restart
icon_tap_action:
action: perform-action
perform_action: button.press
target:
entity_id: button.ssh_host_myserver_docker_vaultwarden_restart
Das ist nicht für den täglichen Gebrauch gedacht. Es ist die Seite, die ich öffne, wenn eine Nachricht kommt, um auf einen Blick zu sehen, ob ein einzelner Container ausgefallen ist oder der ganze Host ein Problem hat, und um den offensichtlichen Kandidaten vom Handy aus neu zu starten.
Was ich gelernt habe
- Ein Ort für Alarme. Telegram lese ich sowieso. Ein eigenes Monitoring mit eigener App wäre noch etwas, das ich ignoriere.
- Prüf auch von außen. „Container läuft“ und „Dienst funktioniert für einen Besucher“ sind zwei verschiedene Fragen. Ein Container kann einwandfrei laufen, während sein Login kaputt ist oder der Proxy woandershin zeigt.
- Prüf die erwartete Antwort. Eine Login-Seite, die plötzlich 200 liefert, ist ein Sicherheitsproblem, kein Erfolg.
- Gib jedem Alarm eine kurze Verzögerung. Zwei Minuten für Container, zehn für Backups: Echte Probleme bleiben, Neustarts wecken dich nicht.
- Räum auf, wenn du einen Container entfernst. Gerät löschen, aus der Alarmliste und vom Dashboard nehmen. Tote Entitäten machen ein Dashboard, dem du nicht mehr traust.