
Website und Webserver mit Node-Red überwachen
Node-Red ist ja mein neues Universal-Werkzeug für alle möglichen Automationsprobleme und Aufgaben. Warum also nicht eine Überwachung für den Webserver und die eigene Website damit realisieren, die im Fehlerfall, also Website down oder ohne Inhalte per Telegram und E-Mail informiert?
Abgesehen von den Telegram-Nodes, die man zusätzlich installieren muss, setzt mein Flow auf die Standard-Nodes der Grundinstallation von Node-Red.

Regelmäßig beim Server anklopfen
Es beginnt mit einem Injection-Node, der im 5-Minuten-Intervall die Überprüfung auslöst. Für meine Anforderungen ein vollkommen ausreichender Zeitraum.

Dieser löst einen HTTP-Request Node aus, in dem die gewünschte URL eingetragen und per GET-Befehl aufgerufen wird. Zurückgegeben wird dann ein UTF-8 String.

Ab hier teilt sich der Flow in zwei Zweige auf. Der erste Zweig prüft den Response-Code der Seite. Gibt die Website den Response-Code 200 zurück, ist alles okay: Seite und Server sind online.

Der Switch-Node löst aus, wenn der Response-Code ungleich 200 ist.

Eine Antwort bedeutet noch keinen Inhalt
Damit ist aber noch nicht sicher, dass auch wirklich etwas auf der Seite zu sehen ist. Hat man z. B. einen Nginx-Server als Reverse-Proxy im Einsatz, kann dieser zwar 200 als Antwort zurückliefen, die Seite kann aber trotzdem leer sein, weil etwa der Server hinter dem Proxy keine Daten liefert. Daher überprüfe ich in einem zweiten Zweig, ob ein gewisser Inhalt auf der Seite enthalten ist.

Ein HTML-Node sucht nach einem Element auf der Website. Ich nehme dazu das Wort Markus, das im Copyright-Footer von nachbelichtet.com zu finden ist. Damit weiß ich, dass die Seite komplett gerendert wurde. Enthalten ist das Wort im HTML-Element div.copyright-bar, das man einfach mit der „Untersuchen“ Funktion von Chrome finden kann.

Wird der Text im HTML-Element gefunden, wird dessen gesamter Textinhalt als Payload zurückgegeben. Der nachfolgenden Switch-Node prüft mit einem regulären Ausdruck, der hier extrem einfach ausfallen kann, ob auch Markus im Text enthalten ist.

Da die Benachrichtigung nur auslösen soll, wenn das gesuchte Wort NICHT enthalten ist, fügt man mit otherwise einen zweiten Ausgang zum Node hinzu, der dann die nachfolgenden Nodes auslöst.
Benachrichtigen, aber nicht nerven
Nun könnte man an jeden Zweig eine entsprechende Aktion, Benachrichtigung etc. anhängen. Allerdings würde im Fehlerfall diese Aktion oder Nachricht alle 5 Minuten gesendet werden, da ja der Injection-Node am Anfang alle 5 Minuten den Flow ausführt. Daher habe ich in jeden Zweig eine Delay-Node eingefügt.

Mit der Aktion Rate Limit kann man einstellen, wie oft eine Nachricht weitergeleitet werden soll. Im Fehlerfall möchte ich alle 30 Minuten eine weitere Erinnerung bekommen. Alle Nachrichten dazwischen werden einfach verworfen:

Die Benachrichtigungs-Nodes sind in beiden Zweigen, abgesehen von der Nachricht, gleich.
Alarm per Telegram und E-Mail

Eine Benachrichtigung erfolgt per Telegram. Dazu muss ein Telegram-Bot eingerichtet und die ID des Empfängers (der Empfänger) angegeben werden. Wie man das macht, steht in der Beschreibung des Telegram-Nodes.

Zusätzlich sende ich eine E-Mail über den SMTP-Server von Gmail. Hierzu müssen mit der Function-Node erst einmal der Betreff und der Inhalt der E-Mail definiert werden:

return {
payload: `[ALARM] ${msg.responseUrl} Homepage zeigt eine leere Seite`,
topic: 'ALARM: nachbelichtet FEHLER!'
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Im Payload steht der E-Mail Inhalt, im Topic der Betreff. Dieser Function-Node ist auch wieder in beiden Zweigen gleich, nur die Nachricht unterscheidet sich natürlich.
Die Variable msg.responseURL ist praktisch, falls ihr gleich mehrere URLs überwachen möchtet, denn damit wird die überwachte URL automatisch in die Nachricht übernommen.
Beide Function-Nodes enden nun beim Email-Node. Als Userid wird die vollständige Gmail-Adresse eingetragen.

Der Versand erfolgt über den SMTP-Server von Gmail. Dazu muss in den Einstellungen von Gmail unter Sicherheit der „Zugriff für weniger sichere Apps“ aktiviert werden, da man sonst den SMTP nicht für externe Anwendungen nutzen kann.

Damit ist der Flow für die Website- und Webserver-Überwachung abgeschlossen. Testen kann man den Flow am einfachsten, in dem man den Status-Code im entsprechenden Switch-Node auf einen anderen Wert setzt oder im Text-Zweig einen Text einträgt, den es im definierten Element nicht gibt. Nun sollte man eine E-Mail und Telegram Nachricht mit dem Alarm erhalten.
Fazit
An dieser Stelle kann man nun noch diverse andere Funktionen auslösen. So könnte man den Alarm auch per MQTT an einen ESPHome oder ESPeasy weitergeben, der dann eine LED Blinken oder einen Lautsprecher piepsen lässt. Auch die Weitergabe an das Smarthome ist praktisch.
Auf jeden Fall ist es toll, wie man mit wenigen Nodes eine höchst praktische und kostenlose Lösung zur Überwachung der Website und des Webservers bauen kann.
Und hier noch der komplette Flow zum Import in Node-Red:
[
{
"id": "dbd92bb5.58bb68",
"type": "tab",
"label": "Website Monitor",
"disabled": false,
"info": ""
},
{
"id": "3ab27a41.60baa6",
"type": "inject",
"z": "dbd92bb5.58bb68",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "300",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 470,
"y": 580,
"wires": [
[
"6f88489b.7f3f88"
]
]
},
{
"id": "6f88489b.7f3f88",
"type": "http request",
"z": "dbd92bb5.58bb68",
"name": "DeineURL.com",
"method": "GET",
"ret": "txt",
"paytoqs": "ignore",
"url": "https://deineURL",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 670,
"y": 580,
"wires": [
[
"fe359cc8.2f164",
"75d0dac2.a64df4"
]
]
},
{
"id": "fe359cc8.2f164",
"type": "switch",
"z": "dbd92bb5.58bb68",
"name": "200 Status",
"property": "statusCode",
"propertyType": "msg",
"rules": [
{
"t": "neq",
"v": "200",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 1050,
"y": 580,
"wires": [
[
"cea5cfe4.de6c1"
]
]
},
{
"id": "6957b0.d583785",
"type": "switch",
"z": "dbd92bb5.58bb68",
"name": "Inhalt testen",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "Markus",
"vt": "str",
"case": true
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 1050,
"y": 480,
"wires": [
[],
[
"23ee8eb3.661a32"
]
]
},
{
"id": "75d0dac2.a64df4",
"type": "html",
"z": "dbd92bb5.58bb68",
"name": "Text suchen",
"property": "payload",
"outproperty": "payload",
"tag": "div.copyright-bar",
"ret": "text",
"as": "multi",
"x": 880,
"y": 480,
"wires": [
[
"6957b0.d583785"
]
]
},
{
"id": "326cbee7.91dbe2",
"type": "telegrambot-notify",
"z": "dbd92bb5.58bb68",
"name": "Status Website LEER",
"bot": "8334d252.8f3f8",
"chatId": "1234567",
"message": "<b>ALARM: nachbelichtet *LEERER INHALT*</b> <a href=\"https://nachbelichtet.com\">LINK</a>",
"parseMode": "HTML",
"x": 1540,
"y": 400,
"wires": []
},
{
"id": "e3b816ab.b04088",
"type": "telegrambot-notify",
"z": "dbd92bb5.58bb68",
"name": "Status Website DOWN",
"bot": "8334d252.8f3f8",
"chatId": "474756997",
"message": "<b>ALARM: nachbelichtet *DOWN*</b> <a href=\"https://nachbelichtet.com\">LINK</a>",
"parseMode": "HTML",
"x": 1540,
"y": 660,
"wires": []
},
{
"id": "f40e9f3.0caec6",
"type": "e-mail",
"z": "dbd92bb5.58bb68",
"server": "smtp.gmail.com",
"port": "465",
"secure": true,
"tls": false,
"name": "deine-mail",
"dname": "Gmail",
"x": 1710,
"y": 520,
"wires": []
},
{
"id": "beb279ff.93bbe8",
"type": "function",
"z": "dbd92bb5.58bb68",
"name": "Mail Server down",
"func": "\nreturn {\n payload: `[ALARM] ${msg.responseUrl} antwortet mit Status-Code '${msg.statusCode}'`,\n topic: 'ALARM: nachbelichtet DOWN!'\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 1530,
"y": 580,
"wires": [
[
"f40e9f3.0caec6"
]
]
},
{
"id": "ea587cd5.eb755",
"type": "function",
"z": "dbd92bb5.58bb68",
"name": "Mail Seite leer",
"func": "\nreturn {\n payload: `[ALARM] ${msg.responseUrl} Homepage zeigt eine leere Seite`,\n topic: 'ALARM: nachbelichtet FEHLER!'\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 1520,
"y": 480,
"wires": [
[
"f40e9f3.0caec6"
]
]
},
{
"id": "cea5cfe4.de6c1",
"type": "delay",
"z": "dbd92bb5.58bb68",
"name": "30 Minuten warten",
"pauseType": "rate",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "30",
"rateUnits": "minute",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": true,
"x": 1250,
"y": 580,
"wires": [
[
"beb279ff.93bbe8",
"e3b816ab.b04088"
]
]
},
{
"id": "23ee8eb3.661a32",
"type": "delay",
"z": "dbd92bb5.58bb68",
"name": "30 Minuten warten",
"pauseType": "rate",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "30",
"rateUnits": "minute",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": true,
"x": 1250,
"y": 480,
"wires": [
[
"ea587cd5.eb755",
"326cbee7.91dbe2"
]
]
},
{
"id": "8334d252.8f3f8",
"type": "telegrambot-config",
"z": "",
"botname": "Dein Bot",
"usernames": "",
"chatIds": "1234567",
"pollInterval": "1800"
}
]
Code-Sprache: JSON / JSON mit Kommentaren (json)
Letzte Aktualisierung am 27.09.2023 / Affiliate Links / Bilder von der Amazon Product Advertising API
Die mit Sternchen (*) gekennzeichneten Verweise sind sogenannte Provision-Links. Wenn du auf so einen Verweislink klickst und über diesen Link einkaufst, bekomme ich von deinem Einkauf eine Provision. Für dich verändert sich der Preis nicht und du unterstützt damit meine Arbeit. Preisänderungen und Irrtümer vorbehalten.