Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Server & Netzwerk 05.11.2026 · 9 min Lesezeit

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

Symbolbild: Server mit leuchtendem Kabel zur Weltkarte, Titel Das HomeLab von außen bewachen

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.de und ntfy.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 curl auf 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:

Statusseite von Gatus mit dem HomeLab als Unhealthy während des Ausfalls
Statusseite von Gatus während des Ausfalls: Das HomeLab ist als Unhealthy markiert (1), die Leiste zeigt die einzelnen Prüfungen (2). Website und DNS-Server laufen weiter.

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

Messgrafik: Zeit vom Ausfall bis zum Alarm und bis zur Entwarnung
Eigene Messung: Zeit vom Ausfall bis zum Alarm und von der Rückkehr bis zur Entwarnung, gemessen an der Ankunft der ntfy-Nachricht.

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:

Ereignisprotokoll eines Endpunkts in Gatus mit Ausfällen und Dauer
Ereignisse des Endpunkts in Gatus: jeder Ausfall mit Beginn und Dauer, im Test 4 Minuten und 2 Minuten 30 Sekunden, dazu die Zeit vor dem Start des Tunnels.

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 BeobachtungUrsache und Lösung
Abo bekommt 403 oder keine NachrichtenNutzer hat keine Leserechte auf das Thema oder falsches Token. Mit ntfy access prüfen.
Gatus meldet gesund, obwohl der Dienst kaputt istNur [STATUS] == 200 geprüft. Eine Bedingung für den Inhalt mit [BODY] ergänzen.
Alarm schon nach kurzen Aussetzernfailure-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-SchutzesEin 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 leerStandard 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

Server im NetzGatusntfyMonitoringHomeLabStatusseiteDocker