Website und Webserver mit Node-Red überwachen

Website-Monitoring muss man keinem externen Dienst überlassen, sondern kann ganz einfach auf Node-Red setzen - komfortable Benachrichtigung inklusive.
Bitte beachte: Dieser Beitrag ist mehr als 3 Jahre alt. Manche Links, Preise, Produkte und Aussagen sind vielleicht nicht mehr aktuell!

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.

Node Red Interval Injection Node
Flow alle 5 Minuten ausführen

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.

Node-Red http request node
Die URL mit einer HTTP-Request Node aufrufen

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.

Zwei Zweige zur Überprüfung zu Erreichbarkeit und Inhalt

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

Node Red Status-Code auslesen
Den Status-Code der Seite mit einem Switch-Node prüfen

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.

HTML-Element mit Node-Red suchen
HTML-Element mit Node-Red suchen

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.

Rate Limit für die Nachrichten

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:

Anzahl der Nachrichten begrenzen Node Red
Anzahl der Nachrichten begrenzen

Die Benachrichtigungs-Nodes sind in beiden Zweigen, abgesehen von der Nachricht, gleich.

Alarm per Telegram und E-Mail

Die Benachrichtiguns-Nodes

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.

Node Red Telegram Node
Der Telegram-Node für die Nachricht einer leeren Website

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:

Node Red E-Mail Inhalt definieren
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.

Node Red E-Mail mit Gmail versenden
Node Red E-Mail mit Gmail versenden

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.

Zugriff für weniger sichere Apps in Gmail freigeben

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 19.04.2024 / Affiliate Links / Bilder von der Amazon Product Advertising API

Melde dich zu meinem Newsletter an!

Du kannst dich jederzeit abmelden und ich verspreche: Kein Spam!


Die mit Sternchen (*) gekennzeichneten Verweise sind sogenannte Provision-Links. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen.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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert