Das HomeLab von außen bewachen: Gatus auf dem VPS mit ntfy-Alarm
Teil 10 der Reihe Server im Netz: Gatus prüft vom VPS aus Website, DNS-Server und HomeLab und schickt Alarme über eine eigene ntfy-Instanz mit Anmeldung. Mit echtem Ausfall, gemessener Alarmzeit und der Falle Status 200.
Geprüft am 05.11.2026 · für Gatus 5.38.0, ntfy 2.37.2, Caddy 2.11.7
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

Ein Dienst im HomeLab fällt aus, und man merkt es erst, wenn man ihn braucht. Eine Überwachung im Heimnetz hilft nur bedingt: Fällt der Strom oder die Leitung aus, schweigt sie mit. Der VPS steht dagegen in einem Rechenzentrum und sieht das HomeLab so, wie es Besucher sehen. Diese Anleitung stellt dort Gatus als Überwachung auf, schickt Alarme über eine eigene ntfy-Instanz aufs Telefon und prüft mit einem echten Ausfall, wie schnell die Nachricht ankommt. Dabei zeigt sich auch, warum eine Prüfung auf Status 200 allein nicht reicht.
Dies ist Teil 10 der Reihe „Server im Netz“. Als Beispiel dient ein netcup-VPS mit Ubuntu und Docker, auf dem Caddy die Domain sedv-lab.de ausliefert. Das HomeLab ist über den frp-Tunnel aus Teil 8 unter heim.sedv-lab.de erreichbar.
Voraussetzungen
- Der VPS aus Teil 4 mit Caddy im Host-Netz und Docker
- Ein Wildcard-Eintrag oder eigene Einträge für
status.sedv-lab.deundntfy.sedv-lab.de - Etwas zum Überwachen, im Beispiel die Website aus Teil 5, der DNS-Server aus Teil 9 und das HomeLab hinter dem Tunnel aus Teil 8
- Für den Empfang die ntfy-App auf dem Telefon oder
curlauf einem Rechner
Schritt 1: ntfy mit Anmeldung einrichten
Gatus kann Alarme an den öffentlichen Dienst ntfy.sh schicken. Dort kann aber jeder ein Thema abonnieren, der den Namen kennt. Ein eigener ntfy auf dem VPS mit Pflicht zur Anmeldung ist kaum mehr Arbeit. Die server.yml:
base-url: "https://ntfy.sedv-lab.de"
listen-http: "127.0.0.1:2586"
behind-proxy: true
cache-file: "/var/cache/ntfy/cache.db"
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"
auth-default-access: "deny-all" sperrt alles für Unangemeldete. Die compose.yaml für ntfy und Gatus:
services:
ntfy:
image: binwiederhier/ntfy:v2.37.2
container_name: ntfy
restart: unless-stopped
network_mode: host
command: ["serve"]
volumes:
- ./ntfy/server.yml:/etc/ntfy/server.yml:ro
- ./ntfy/cache:/var/cache/ntfy
- ./ntfy/lib:/var/lib/ntfy
gatus:
image: twinproduction/gatus:v5.38.0
container_name: gatus
restart: unless-stopped
network_mode: host
env_file: ./gatus/gatus.env
volumes:
- ./gatus/config.yaml:/config/config.yaml:ro
- ./gatus/data:/data
Zuerst nur ntfy starten und zwei Nutzer anlegen: gatus darf ins Thema homelab schreiben, leser darf es nur lesen. Das Passwort übergeben Sie über die Variable NTFY_PASSWORD. Das Passwort von leser geben wir aus, es wird für die App gebraucht:
docker compose up -d ntfy
NTFY_PASSWORD="$(openssl rand -hex 16)" docker exec -e NTFY_PASSWORD ntfy ntfy user add gatus
LESER_PW="$(openssl rand -hex 16)"; echo "$LESER_PW"
NTFY_PASSWORD="$LESER_PW" docker exec -e NTFY_PASSWORD ntfy ntfy user add leser
docker exec ntfy ntfy access gatus homelab write-only
docker exec ntfy ntfy access leser homelab read-only
docker exec ntfy ntfy token add gatus
docker exec ntfy ntfy token add leser
Die beiden Tokens beginnen mit tk_. Bewahren Sie sie auf, sie ersetzen die Passwörter.
Verifizieren: docker exec ntfy ntfy access listet gatus mit write-only access to topic homelab, leser mit read-only und für alle anderen no access to any (other) topics.
Schritt 2: Gatus konfigurieren
Das Token von gatus kommt in gatus/gatus.env mit chmod 600, als Zeile NTFY_TOKEN=tk_…. Gatus setzt Umgebungsvariablen in der Konfiguration ein, so steht das Token nicht in der config.yaml:
storage:
type: sqlite
path: /data/gatus.db
web:
address: 127.0.0.1
port: 8090
ui:
title: "Status sedv-lab.de"
header: "Status sedv-lab.de"
alerting:
ntfy:
url: "https://ntfy.sedv-lab.de"
topic: "homelab"
token: "${NTFY_TOKEN}"
priority: 4
default-alert:
failure-threshold: 3
success-threshold: 2
send-on-resolved: true
endpoints:
- name: Website
group: VPS
url: "https://sedv-lab.de/"
interval: 1m
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 1000"
- "[CERTIFICATE_EXPIRATION] > 240h"
alerts:
- type: ntfy
- name: DNS-over-TLS
group: VPS
url: "tls://dns.sedv-lab.de:853"
interval: 5m
conditions:
- "[CONNECTED] == true"
- "[CERTIFICATE_EXPIRATION] > 240h"
alerts:
- type: ntfy
- name: HomeLab über Tunnel
group: HomeLab
url: "https://heim.sedv-lab.de/"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[BODY] == pat(*HomeLab*)"
alerts:
- type: ntfy
Die drei Prüfungen zeigen drei Arten: eine Website mit Status, Antwortzeit und Restlaufzeit des Zertifikats, ein TLS-Dienst ohne HTTP, hier der DNS-Server auf Port 853, und das HomeLab mit einer Prüfung des Inhalts. pat(*HomeLab*) verlangt, dass das Wort „HomeLab“ in der Antwort vorkommt. Mit failure-threshold: 3 meldet Gatus erst nach drei Fehlschlägen hintereinander, so lösen einzelne Aussetzer keinen Alarm aus. send-on-resolved schickt eine Entwarnung. Die Ergebnisse speichert Gatus in SQLite, damit der Verlauf einen Neustart übersteht.
Die Website liegt hinter Anubis aus Teil 6. Gatus meldet sich als Gatus/1.0, Anubis schickt nur Kennungen mit „Mozilla“ in die Rechenaufgabe. Prüfen Sie trotzdem auch hier den Inhalt, denn die Prüfseite von Anubis kommt ebenfalls mit Status 200.
docker compose up -d gatus
docker logs gatus 2>&1 | grep -E "Monitored|ntfy" | tail -5
Verifizieren: Im Log steht configuredProviders=[ntfy] und für jede Prüfung eine Zeile Monitored group=… success=true.
Schritt 3: Statusseite und ntfy über Caddy
Beide Dienste lauschen nur auf 127.0.0.1. Caddy macht sie mit HTTPS erreichbar:
status.sedv-lab.de {
import sicher
reverse_proxy 127.0.0.1:8090
}
ntfy.sedv-lab.de {
import sicher
reverse_proxy 127.0.0.1:2586
}
Die Statusseite ist damit öffentlich. Das ist bei vielen Projekten gewollt, verrät aber Namen und Adressen der überwachten Dienste. Wer das nicht möchte, setzt im Caddy-Block basic_auth davor.
Verifizieren: curl -s -o /dev/null -w '%{http_code}\n' https://ntfy.sedv-lab.de/v1/health liefert 200, ein anonymer Abruf von https://ntfy.sedv-lab.de/homelab/json?poll=1 403.
Schritt 4: Alarme empfangen
Am Rechner reicht curl mit dem Token von leser. Die Verbindung bleibt offen, jede Nachricht erscheint als eine Zeile JSON:
curl -sN -H "Authorization: Bearer tk_…" https://ntfy.sedv-lab.de/homelab/json
In der ntfy-App für Android und iOS tragen Sie den eigenen Server sowie Nutzer und Passwort von leser ein. Für Sofort-Benachrichtigungen unter iOS braucht der Server laut Doku zusätzlich upstream-base-url: "https://ntfy.sh" in der server.yml. Die Rechte haben wir gegengeprüft: Anonym senden, mit leser senden, mit leser ein anderes Thema lesen und mit gatus lesen ergab jeweils 403. Mit dem Token von gatus ging eine Testnachricht durch.
Verifizieren: curl -H "Authorization: Bearer tk_…" -d "Test" https://ntfy.sedv-lab.de/homelab mit dem Token von gatus erscheint beim Abo.
Schritt 5: Ein echter Ausfall
Für den Test haben wir den Tunnel im Heimnetz vier Minuten lang gestoppt und danach den Inhalt der Seite durch eine Wartungsseite ersetzt, die weiter Status 200 lieferte. Die Statusseite zeigt den Ausfall nach der nächsten Prüfung an:

Gemessen haben wir die Zeit vom Eingriff bis zur Ankunft der Nachricht beim Abo:

89 Sekunden bis zum Alarm ergeben sich aus der Einstellung: drei Prüfungen im Abstand von 30 Sekunden, die erste kann bis zu 30 Sekunden nach dem Ausfall liegen. Die Entwarnung kam nach zwei erfolgreichen Prüfungen. Die Nachricht nennt die verletzten Bedingungen:
Gatus: HomeLab/HomeLab über Tunnel
An alert has been triggered due to having failed 3 time(s) in a row
[STATUS] (404) == 200
[BODY] (<!DOCTYPE html>
<html>
<h...(truncated)) == pat(*HomeLab*)
Vor jeder Bedingung setzt Gatus in der Nachricht ein rotes oder grünes Symbol, hier weggelassen. Die 404 kam vom Tunnel-Server, solange kein Client verbunden war, wie in Teil 8 beschrieben. Der zweite Fall ist der lehrreichere: Die Wartungsseite lieferte Status 200, die Nachricht meldete nur die Bedingung für den Inhalt als verletzt. Ohne [BODY] hätte Gatus die Seite für gesund gehalten. Dasselbe passiert, wenn ein Reverse Proxy eine eigene Fehlerseite mit 200 ausliefert oder eine Anwendung nach einem Update nur noch ihren Einrichtungsassistenten zeigt.
Unter jedem Endpunkt führt Gatus ein Protokoll der Ereignisse mit Dauer:

Verifizieren: Stoppen Sie einen überwachten Dienst und warten Sie die eingestellte Zeit, im Beispiel rund eineinhalb Minuten. Die Nachricht muss beim Abo ankommen.
Typische Fehler
| Meldung oder Beobachtung | Ursache und Lösung |
|---|---|
| Abo bekommt 403 oder keine Nachrichten | Nutzer hat keine Leserechte auf das Thema oder falsches Token. Mit ntfy access prüfen. |
| Gatus meldet gesund, obwohl der Dienst kaputt ist | Nur [STATUS] == 200 geprüft. Eine Bedingung für den Inhalt mit [BODY] ergänzen. |
| Alarm schon nach kurzen Aussetzern | failure-threshold zu niedrig oder interval zu kurz. Werte abwägen: höher heißt ruhiger, aber später. |
| Statt der Seite kommt die Prüfseite eines Bot-Schutzes | Ein Bot-Schutz wie Anubis hält Gatus für einen Browser, etwa nach einer eigenen Kennung mit „Mozilla“. Kennung ohne „Mozilla“ verwenden und den Inhalt mit [BODY] prüfen. |
| Verlauf nach Neustart leer | Standard ist Speicher im RAM. storage.type: sqlite mit Pfad im Volume setzen. |
Häufige Fragen
Warum nicht Uptime Kuma?
Uptime Kuma ist sehr verbreitet und wird über die Oberfläche eingerichtet. Gatus liest eine YAML-Datei, die sich versionieren und mit einer Pipeline ausrollen lässt, und braucht kaum Speicher: im Test 22 MiB, ntfy 13 MiB.
Was, wenn der VPS selbst ausfällt?
Dann schweigt auch die Überwachung. Für diesen Fall braucht es eine zweite Stelle außerhalb, etwa einen kostenlosen externen Dienst, der nur die Statusseite oder die Website prüft. Die Gegenrichtung lässt sich auch aus dem HomeLab heraus überwachen.
Brauche ich ntfy auf dem eigenen Server?
Nein, Gatus kann auch an ntfy.sh und viele andere Dienste wie E-Mail, Matrix oder Telegram senden. Der eigene ntfy hat den Vorteil, dass die Nachrichten nur mit Token lesbar sind und auf Ihrem Server bleiben.
Fazit
Gatus und ntfy auf dem VPS ergeben in einer halben Stunde eine Überwachung, die das HomeLab von außen sieht und im Test nach rund anderthalb Minuten Bescheid gab. Die wichtigste Lehre aus dem Test: Prüfen Sie nicht nur den Status, sondern auch den Inhalt. Eine Wartungsseite mit Status 200 wäre sonst als gesund durchgegangen. Und sperren Sie ntfy mit deny-all, damit niemand mitliest.
Weiterführende Anleitungen und Quellen
- Teil 8: HomeLab ohne Portfreigabe
- Teil 9: Eigener DNS für unterwegs
- Teil 4: Caddy als Eingangstür
- Teil 6: Anubis vor der Website
- Docker und Docker Compose auf Linux installieren
- Docker Compose absichern
- Gatus auf GitHub
- Gatus: Dokumentation v5.38.0
- ntfy: Konfiguration und Zugriffsrechte
- ntfy: Abonnieren über die API


