Status: Geplant · Schwierigkeit: Einsteiger · Werkzeuge: n8n, HTTP Request, Telegram Bot API

Die Idee

↑ Zur Kapitelübersicht

Heimserver, NAS, Router, lessat.net – alles läuft still im Hintergrund, solange es läuft. Wenn nicht, merkt man es meist zu spät.

Ein professionelles Monitoring-System wie Nagios oder Grafana ist für den Heimgebrauch überdimensioniert. Was gebraucht wird, ist einfacher: Eine regelmäßige Prüfung ob die wichtigsten Dienste noch erreichbar sind – und eine sofortige Nachricht wenn nicht.

n8n ist dafür gut geeignet. Ein Workflow prüft alle fünf Minuten die definierten Prüfpunkte, vergleicht den Status mit dem letzten bekannten Zustand und sendet nur dann eine Meldung, wenn sich etwas verändert hat. Kein Dauerbeschuss mit „alles OK"-Nachrichten – nur Signal, kein Rauschen.

Beispiel-Alarm:

🔴 AUSFALL erkannt – 14:37 Uhr

Dienst: lessat.net
Status: nicht erreichbar (Timeout nach 10s)
Letzter OK: 14:32 Uhr

Bitte prüfen.

— und nach Wiederherstellung —

🟢 WIEDERHERGESTELLT – 14:51 Uhr

Dienst: lessat.net
Ausfallzeit: ca. 14 Minuten

Was das Projekt können soll

↑ Zur Kapitelübersicht

Klare Anforderungen – kein überflüssiges Feature-Creep.

Muss-Anforderungen

✓ Mehrere URLs / Dienste regelmäßig prüfen.
✓ Ausfall erkennen und sofort per Telegram melden.
✓ Wiederherstellung erkennen und melden.
✓ Nur bei Statusänderung melden – kein Spam bei jedem Prüfzyklus.
✓ Täglichen Kurzbericht um 08:00 Uhr senden.

Bewusst nicht enthalten

✗ Kein grafisches Dashboard im Browser.
✗ Keine Langzeit-Statistiken oder Verfügbarkeitsgraphen.
✗ Kein Monitoring von CPU, RAM oder Festplatte (das würde Agenten auf den Zielrechnern erfordern).
✗ Keine SMS oder E-Mail – nur Telegram.

Die Lösung im Überblick

↑ Zur Kapitelübersicht

Zwei Workflows arbeiten zusammen: ein schneller Prüf-Workflow alle 5 Minuten und ein täglicher Report-Workflow.

Workflow A – Prüf-Zyklus (alle 5 Minuten):

[Schedule Trigger] alle 5 Minuten
  ↓
[HTTP Request × N] jeden Dienst prüfen
  ↓ Statuscode + Antwortzeit
[Code Node] Status auswerten
  ↓ OK / FEHLER je Dienst
[Code Node] mit letztem Status vergleichen
  ↓ nur bei Änderung
[Telegram Node] Alarm oder Entwarnung senden

Workflow B – Tagesbericht (täglich 08:00):

[Schedule Trigger] täglich 08:00 Uhr
  ↓
[Code Node] gespeicherte Status laden
  ↓
[Telegram Node] Tagesbericht senden

Statusgedächtnis: wie n8n sich den letzten Zustand merkt

Das zentrale Problem beim Monitoring ist das Gedächtnis: Wie weiß der Workflow ob sich der Status gegenüber dem letzten Lauf verändert hat?

Lösung: Eine JSON-Datei auf dem lokalen Dateisystem (oder in n8n Static Data) speichert nach jedem Lauf den letzten bekannten Status jedes Dienstes. Beim nächsten Lauf wird dieser Status geladen und mit dem aktuellen verglichen. Nur bei Abweichung wird eine Nachricht gesendet.

Voraussetzungen

↑ Zur Kapitelübersicht

Dieses Projekt ist das einsteigerfreundlichste der vier – keine externen APIs mit Kosten, keine Dateiverarbeitung.

n8n-Instanz (dauerhaft laufend)

Für sinnvolles Monitoring muss n8n rund um die Uhr laufen – Docker auf einem Heimserver oder NAS ist ideal. Die Desktop-App scheidet aus, da sie nur läuft solange der PC eingeschaltet ist.
n8n installieren

Telegram Bot Token & Chat-ID

Identisch zum EV-Ladesäulen-Finder – denselben Bot und dieselbe Chat-ID verwenden.
Telegram-Bot einrichten

Liste der zu überwachenden Dienste

Vor dem Aufbau festlegen, was überwacht werden soll. Für den Einstieg empfehlen sich 3–5 Dienste:

Liste der zu überwachenden Dienste

Vor dem Aufbau festlegen, was überwacht werden soll. Für den Einstieg empfehlen sich 3–5 Dienste:

Dienst URL / Adresse Erwarteter Statuscode
Beispiel-Webseite https://example.com 200
Test-API https://api.example.com/health 200
Monitoring-Dashboard https://monitor.example.com/status 200
Router-Gateway http://gateway.local 200

Schritt 1: Trigger – alle 5 Minuten

↑ Zur Kapitelübersicht

Der Schedule Trigger startet den Prüf-Zyklus im gewählten Intervall.

Node-Konfiguration

Node: Schedule Trigger
Name: „Alle 5 Minuten"

Trigger interval: Minutes
Minutes between triggers: 5

Intervall wählen:
5 Minuten ist ein guter Kompromiss – kurz genug um Ausfälle schnell zu erkennen, lang genug um nicht übermäßig viele HTTP-Anfragen zu erzeugen. Für eine Homepage reicht auch 10 Minuten. Für einen Dienst der rund um die Uhr erreichbar sein muss (z.B. ein eigener Mailserver) kann 1 Minute sinnvoll sein.

Schritt 2: Prüfpunkte abfragen

↑ Zur Kapitelübersicht

Jeder zu überwachende Dienst bekommt einen eigenen HTTP Request Node. Parallel, nicht sequenziell.

Node-Konfiguration (pro Dienst)

Node: HTTP Request
Name: z.B. „Prüfe: lessat.net"
Method: GET
URL: https://www.lessat.net

Options:
Timeout: 10000 (10 Sekunden)
Ignore SSL Issues: Aus (SSL-Fehler sollen als Ausfall gewertet werden)
Response Format: String (der HTML-Body wird nicht weiterverarbeitet, nur der Statuscode zählt)

On Error: Continue (using error output)
Wichtig: Damit der Workflow bei einem Timeout oder Verbindungsfehler nicht abbricht, sondern den Fehler als Datenpunkt weitergibt.

Alle Prüf-Nodes parallel schalten

Alle HTTP Request Nodes werden direkt an den Trigger-Node angehängt – nicht hintereinander. n8n führt sie dann parallel aus, was den gesamten Prüfzyklus auf maximal 10 Sekunden (Timeout) begrenzt, unabhängig von der Anzahl der Dienste.

Schritt 3: Status auswerten

↑ Zur Kapitelübersicht

Ein Code Node sammelt alle Prüfergebnisse, wertet Statuscodes aus und erzeugt eine einheitliche Status-Liste.

Node-Konfiguration

Node: Code
Name: „Status auswerten"
Language: JavaScript

// Zu überwachende Dienste (Konfiguration)
const dienste = [
    { name: 'lessat.net',    url: 'https://www.lessat.net',        erwartet: 200 },
    { name: 'NAS',           url: 'http://192.168.x.y:5000',      erwartet: 200 },
    { name: 'Fritzbox',      url: 'http://192.168.x.1',            erwartet: 200 },
    { name: 'n8n',           url: 'http://localhost:5678/healthz',  erwartet: 200 },
];

const jetzt = new Date().toLocaleTimeString('de-DE', {
    hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin'
});

const ergebnisse = $input.all().map((item, i) => {
    const dienst = dienste[i] ?? { name: `Dienst ${i+1}`, erwartet: 200 };
    const statusCode = item.json.statusCode ?? item.json.$response?.statusCode ?? 0;
    const antwortzeit = item.json.$response?.responseTime ?? null;
    const fehler = item.json.message ?? null;

    const ok = !fehler && statusCode === dienst.erwartet;

    return {
        name:        dienst.name,
        url:         dienst.url,
        ok,
        statusCode,
        antwortzeit,
        fehler,
        zeitpunkt:   jetzt,
    };
});

return [{ json: { ergebnisse, zeitpunkt: jetzt } }];

Schritt 4: Meldung nur bei Statusänderung

↑ Zur Kapitelübersicht

Das ist der wichtigste Schritt – ohne ihn kommt alle 5 Minuten eine Nachricht. Nur echte Änderungen lösen eine Meldung aus.

Status speichern und vergleichen

Node: Code
Name: „Änderungen erkennen"

const fs = require('fs');
const statusDatei = '/home/node/.n8n/monitoring-status.json';

// Letzten Status laden
let letzterStatus = {};
try {
    letzterStatus = JSON.parse(fs.readFileSync(statusDatei, 'utf8'));
} catch(e) {
    // Erste Ausführung – kein gespeicherter Status
}

const { ergebnisse, zeitpunkt } = $json;
const meldungen = [];

for (const dienst of ergebnisse) {
    const letzt = letzterStatus[dienst.name];

    // Erster Lauf: Status merken, keine Meldung
    if (letzt === undefined) {
        letzterStatus[dienst.name] = { ok: dienst.ok, seit: zeitpunkt };
        continue;
    }

    // Statuswechsel: OK → FEHLER
    if (letzt.ok && !dienst.ok) {
        meldungen.push({
            typ: 'AUSFALL',
            name: dienst.name,
            url: dienst.url,
            statusCode: dienst.statusCode,
            fehler: dienst.fehler,
            zeitpunkt,
        });
        letzterStatus[dienst.name] = { ok: false, seit: zeitpunkt };
    }

    // Statuswechsel: FEHLER → OK
    if (!letzt.ok && dienst.ok) {
        const ausfallSeit = letzt.seit ?? '?';
        meldungen.push({
            typ: 'WIEDERHERGESTELLT',
            name: dienst.name,
            url: dienst.url,
            ausfallSeit,
            zeitpunkt,
        });
        letzterStatus[dienst.name] = { ok: true, seit: zeitpunkt };
    }
}

// Aktualisierten Status speichern
fs.writeFileSync(statusDatei, JSON.stringify(letzterStatus, null, 2));

return [{ json: { meldungen, hatMeldungen: meldungen.length > 0 } }];
IF Node: nur weiter wenn Meldungen vorhanden

Node: IF
Name: „Meldungen vorhanden?"

Value 1 (Expression): {{ $json.hatMeldungen }}
Operation: Equal
Value 2: true

Der false-Ausgang bleibt unverbunden – der Workflow endet still ohne Telegram-Nachricht.

Schritt 5: Telegram-Alarm senden

↑ Zur Kapitelübersicht

Pro Meldung wird eine eigene Telegram-Nachricht mit dem passenden Emoji und allen relevanten Details gesendet.

Nachricht formatieren

Node: Code
Name: „Alarm formatieren"

const nachrichten = [];

for (const m of $json.meldungen) {
    let text = '';

    if (m.typ === 'AUSFALL') {
        text = [
            `🔴 *AUSFALL erkannt* – ${m.zeitpunkt} Uhr`,
            ``,
            `Dienst: ${m.name}`,
            `URL: ${m.url}`,
            `Status: ${m.statusCode || 'kein HTTP-Status'}`,
            m.fehler ? `Fehler: ${m.fehler}` : null,
            ``,
            `Bitte prüfen.`,
        ].filter(Boolean).join('\n');
    }

    if (m.typ === 'WIEDERHERGESTELLT') {
        text = [
            `🟢 *WIEDERHERGESTELLT* – ${m.zeitpunkt} Uhr`,
            ``,
            `Dienst: ${m.name}`,
            `Ausfall seit: ${m.ausfallSeit} Uhr`,
        ].join('\n');
    }

    nachrichten.push({ json: { text } });
}

return nachrichten;
Telegram Node

Node: Telegram
Name: „Alarm senden"

Credential: Telegram Bot Token
Operation: Send Message
Chat ID: eigene Chat-ID
Text (Expression): {{ $json.text }}
Parse Mode: Markdown

Bonus: Täglicher Status-Report

↑ Zur Kapitelübersicht

Ein zweiter, einfacher Workflow sendet jeden Morgen eine Übersicht aller überwachten Dienste – zur Bestätigung dass alles in Ordnung ist.

Workflow B – Aufbau

Node 1: Schedule Trigger – täglich 08:00 Uhr

Node 2: Code – gespeicherten Status laden

const fs = require('fs');
const statusDatei = '/home/node/.n8n/monitoring-status.json';

let status = {};
try {
    status = JSON.parse(fs.readFileSync(statusDatei, 'utf8'));
} catch(e) {
    status = {};
}

const jetzt = new Date().toLocaleDateString('de-DE', {
    weekday: 'long', day: '2-digit', month: '2-digit', year: 'numeric',
    timeZone: 'Europe/Berlin'
});

const zeilen = Object.entries(status).map(([name, s]) => {
    const symbol = s.ok ? '✅' : '🔴';
    return `${symbol} ${name}`;
});

const text = [
    `📊 *Monitoring-Report* – ${jetzt}`,
    ``,
    ...zeilen,
    ``,
    zeilen.every(z => z.startsWith('✅'))
        ? '_Alle Dienste erreichbar._'
        : '_⚠️ Mindestens ein Dienst hat Probleme._',
].join('\n');

return [{ json: { text } }];
Node 3: Telegram

Identische Konfiguration wie in Schritt 5 – Chat-ID und Token aus demselben Credential.

Beispiel-Report:

📊 Monitoring-Report – Montag, 26.05.2026

✅ lessat.net
✅ NAS
✅ Fritzbox
✅ n8n

Alle Dienste erreichbar.

Workflow exportieren und importieren

↑ Zur Kapitelübersicht

Beide Workflows als JSON-Dateien zum Download.

Nach dem Import anpassen

1. Dienste-Liste im Code Node „Status auswerten" auf eigene URLs anpassen.
2. Pfad zur Statusdatei anpassen (/home/node/.n8n/monitoring-status.json funktioniert für Docker-Instanzen; für Desktop-App einen anderen Pfad wählen).
3. Telegram Credential hinterlegen und Chat-ID eintragen.
4. Workflow A aktivieren – nach dem ersten Durchlauf existiert die Statusdatei und Vergleiche funktionieren.
5. Workflow B separat aktivieren.

Workflow-JSON: Prüfzyklus

Alternativ zum Download: Inhalt kopieren und in n8n über Workflows → Import from clipboard einfügen.

// workflow-pruefzyklus.json noch nicht vorhanden
Workflow-JSON: Tagesreport

Alternativ zum Download: Inhalt kopieren und in n8n über Workflows → Import from clipboard einfügen.

// workflow-tagesreport.json noch nicht vorhanden

Sicherheit & Credentials

↑ Zur Kapitelübersicht

Dieses Projekt hat die geringsten Sicherheitsanforderungen aller vier Projekte – keine externen API-Kosten, keine Bilddaten.

Telegram Bot Token

Identisch zum EV-Ladesäulen-Finder – denselben Bot und dasselbe Credential wiederverwenden. Der Token ist bereits in n8n gespeichert und muss nicht neu angelegt werden.

Interne IP-Adressen im Workflow

Die Dienste-Liste enthält interne IP-Adressen (z.B. 192.168.x.y). Das ist kein Sicherheitsproblem solange der Workflow auf einem Rechner im selben Netzwerk läuft. Beim Export des Workflows darauf achten, dass interne Adressen nicht versehentlich öffentlich geteilt werden – sie geben Aufschluss über die Netzwerkstruktur.

Statusdatei absichern

Die Datei monitoring-status.json enthält den letzten bekannten Status aller Dienste mit Zeitstempeln. Sie liegt im n8n-Datenverzeichnis und ist von außen nicht erreichbar – kein Handlungsbedarf.

Was ich gelernt habe

↑ Zur Kapitelübersicht

Ehrliches Fazit nach der Planung und ersten Tests.

✅ Hat gut funktioniert

Das Konzept „nur bei Änderung melden" ist der entscheidende Unterschied zu einem nutzlosen Alarm-Spam-System. Die JSON-Statusdatei als einfaches Gedächtnis funktioniert zuverlässig und ist leicht zu debuggen – man kann sie jederzeit mit einem Texteditor öffnen und den gespeicherten Zustand prüfen. Parallele HTTP-Prüfungen halten den Zyklus kurz.

⚠️ Hat länger gedauert als gedacht

Die Option „Continue (using error output)" im HTTP Request Node ist nicht offensichtlich. Ohne sie bricht der gesamte Workflow ab, sobald ein Dienst nicht antwortet – was genau das Szenario ist, das erkannt werden soll. Mit der Option läuft der Workflow weiter und behandelt den Fehler als normalen Datenpunkt.

❌ Sackgasse

Versucht, die Statusdatei in n8n Static Data zu speichern statt als JSON-Datei – Static Data wird bei manchen n8n-Versionen bei einem Workflow-Update zurückgesetzt. Die Datei auf dem Dateisystem ist zuverlässiger und transparenter.

Troubleshooting

↑ Zur Kapitelübersicht

Die häufigsten Probleme beim Aufbau dieses Projekts.

Problem: Workflow bricht bei nicht erreichbarem Dienst ab

Ursache: HTTP Request Node bricht bei Fehler ab statt fortzufahren.
Lösung: Im HTTP Request Node unter „Settings"„On Error" auf „Continue (using error output)" stellen. Das ist für jeden Prüf-Node einzeln nötig.

Problem: Jedes Mal Alarm, obwohl Status gleich bleibt

Ursache: Statusdatei wird nicht gefunden oder kann nicht gelesen werden.
Lösung: Pfad zur Statusdatei prüfen. Beim ersten Lauf ist das normal – ab dem zweiten Lauf wird verglichen. Prüfen ob n8n Schreibrechte im Zielverzeichnis hat.

Problem: Interne IP-Adressen nicht erreichbar

Ursache: n8n läuft in Docker und ist vom Heimnetzwerk isoliert.
Lösung: Docker-Container mit --network host starten (Linux) oder die IP-Adresse des Docker-Hosts verwenden statt localhost oder 192.168.x.x.

Problem: Telegram-Nachricht enthält keine Formatierung

Ursache: Parse Mode nicht auf Markdown gestellt.
Lösung: Im Telegram Node unter „Additional Fields"„Parse Mode"„Markdown" auswählen.

Ideen für Weiterentwicklung

↑ Zur Kapitelübersicht

Was das Projekt in einer späteren Version können könnte.

Antwortzeiten überwachen

Nicht nur ob ein Dienst erreichbar ist, sondern auch wie schnell er antwortet. Eine Antwortzeit über 3 Sekunden kann auf Probleme hinweisen, auch wenn der Statuscode noch 200 ist. Alarm bei Überschreitung eines Schwellenwerts.

SSL-Zertifikat-Ablauf prüfen

HTTPS-Zertifikate haben ein Ablaufdatum. Ein abgelaufenes Zertifikat macht eine Website für Besucher unzugänglich. n8n kann das Ablaufdatum über die Zertifikat-Informationen der HTTPS-Verbindung auslesen und rechtzeitig warnen – z.B. 14 Tage vor Ablauf.

Verfügbarkeits-Statistik

Jeden Prüf-Zyklus in eine CSV-Datei oder Google-Tabelle schreiben – Datum, Uhrzeit, Status, Antwortzeit für jeden Dienst. Daraus lässt sich die monatliche Verfügbarkeit berechnen.

Stille Zeiten

Nachts zwischen 23:00 und 07:00 Uhr keine Alarm-Nachrichten senden – Meldungen sammeln und gebündelt beim Morgenbericht ausgeben. Ein IF-Node der die aktuelle Uhrzeit prüft reicht dafür aus.