Server Überwachung via SMS und Mail

Heute ergab sich die Anforderung eine Server Überwachung im Netzwerk eines Kunden zu integrieren. Der Grund dafür ist ein Problem zu bemerken und zu beheben, eher der Kunde überhaupt bemerkt, dass er eins hat.

Für eine schnelle Reaktion ist es also wichtig, dass die Nachricht über den Ausfall eines Servers sofort gesendet und auch empfangen wird. Wert ständig ein Smartphone mit sich trägt, dem eröffnen sich zwei Benachrichtigungsverfahren: Email & SMS. Für eine Email spricht der kostengünstige Versand, dagegen aber ein relativ lahmer Transportweg. Eine SMS ist zwar im Versand teurer, dafür in der Zustellung schneller. Da für uns eine schnelle Benachrichtigung wichtig ist und die Kosten zu verschmerzen sind, integrieren wir der Einfachheit halber eine doppeltes Benachrichtigungsverfahren – sicher ist sicher 🙂

Wahl des SMS Providers

Die Wahl eines SMS Providers schwankte bei uns aus Verbundenheit zu Vodafone und als Qnap-Standard-Provider Clickatell. Bei Vodafone muss man seine Handy-Nr für den Gateway freischalten lassen (via SMS) und anschließend für jede empfangene SMS über diesen Gateway 0,20 Euro bezahlen. Das Verfahren heisst „Vodafone SMS-to-eMail“ und wird im InfoDok 354 beschrieben. Kurz erklärt sendet man aus seiner Applikation heraus eine Email an „handynr@vodafone-sms.de“, also in meinem Fall z.B. „01621770699@vodafone-sms.de“. Das klappt soweit ganz gut, ist aber ziemlich teuer.

Clickatell ist der von QNAP empfohlene SMS Provider. Nach einer Anmeldung über die Webseite erhält man Zugang zu verschiedenen Schnittstellen, über die SMS versendet werden können: Email, POST & GET Request, Webservice und … . Zum Testen werden einen 10 Frei-SMS zur Verfügung gestellt ohne das weitere Kosten entstehen. Möchte man den Dienst weiter nutzen, so müssen SMS via Kreditkarte oder auch Paypal gekauft werden. Die kleinste Einheit ist dabei 400 SMS zum Preis von 17,60 Euro zu kaufen, was einem Stückpreis von 0,044 Euro entspricht (für Vodafone & T-Mobile Kunden, sonst das doppelte).

Ich hab mich für Clickatell entschieden, da dieser Dienst mich nur 4 Cent pro SMS kostet und ich ihn auch direkt für QNAP Benachrichtigungen nutzen kann. Die Vielfalt der Schnittstellen bietet mir mehr Möglichkeiten zum Ausprobieren und herumspielen. Einfacher dagegen ist Vodafone, bei dem man nur eine Freischalt-SMS schicken muss, dafür aber auch anschließend 20 Cent pro SMS zahlt.

Szenario

Mein Szenario ist, dass ich vier Server von meinem Script überwacht haben möchte. Drei davon laufen virtuell auf dem Server 1 (SRV01). Die Überwachung soll nicht rund um die Uhr laufen, da in der Nacht die VMs gesichert und dazu heruntergefahren werden. Ich möchte einmal benachrichtigt werde,n wenn ein Server ausgefallen ist und auch dann, wenn er wieder verfügbar ist. Irgendwo muss also ein Status gespeichert werden.

Implementierung

Meine Lösung ist in PHP implementiert. Auf den Quellcode werde ich nicht groß eingehen, da er doch recht verständlich ist und von oben nach unten durchgelesen werden kann. Im Nachhinein habe ich für diesen Beitrag noch eine kleine Logger Klasse eingebaut, die den Code etwas sauberer aussehen lassen soll.

Initial wollte ich den Status der Maschinen über die PHP Funktion exec(‚ping…‘) testen, aber aufgrund von Benutzerbeschränkungen des Apache Users auf dem QNAP können einige Binarys nicht ausgeführt werden. Die Alternative ist via fsockopen() eine Verbindung zu einem Port auf der Maschine aufzubauen. Voraussetzung dafür ist, dass es auch einen offenen Port gibt. Da jeder dieser Server aber eben auch einen Dienst nach außen hin anbietet, ist auf jeden von den Servern auch mindestens ein Port offen. Wer auf seinem Server einen offenen Port sucht, kann in Windows das DOS-Command „netstat“ verwenden. Ich verwenden auf dem SRV01 den VM-Ware Port, auf SRV02 den DNS Port, auf SRV04 den SMTP Port und auf SRV_ALT den MSSQL-Server Port.

Den Status merkt sich das Script in einer Lock-Datei, die ins Filesystem geschrieben wird. In diese Datei wird der Zeitpunkt des letzten Ausfalls geschrieben. Um das Mehrfache versenden von Mails und SMS zu verhindern, ist eine Sperre/Lag/Verzögerung von 1 Stunde eingebaut. Fällt ein System mehrfach innerhalb dieses Zeitraums aus, so wird nur einmal eine Benachrichtigung verschickt.

Als Schnittstelle zum Clickatell SMS Gateway habe ich mich für den Mail-Versand entschieden.

Aufgerufen wird das Script via Eintrag in der /etc/config/crontab jeden Tag von 6 bis 22 Uhr alle 15 Minuten.

[code language=“bash“]

0,15,30,45 6-22 * * * /usr/bin/wget http://10.10.0.10/sms.php

[/code]

In diesem Post habe ich bereits erklärt, wie man auf dem QNAP NAS Cronjobs einträgt.

Das Script

[code language=“php“]
<?php
error_reporting(E_ALL);

define("LAG", 3600);
define("FROM_MAIL", "from@domain.com");
define("TO_MAIL", "to@domain.com");
define("SMS_PROVIDER_TO", "sms@messaging.clickatell.com");
define("SEND_MAIL_ANYTIME", false);
define("SMS_ENABLED", true);
define("SERVER_TIMEOUT_SEK", 2);

define("SMS_PROVIDER_MAIL_BODY", "user:xxxxxxxxxx
password:yyyyyyyyyy
api_id:zzzzzzzzzz
to: 49173123456789
reply:host@domain.com
text:");

/*
* script
*/

// aray(serverip, port, notification msg, vmware-host-system)
$hosts = array(
array("10.10.0.1", "8333", "SRV01", "SRV01 is not reachable", true),
array("10.10.0.2", "53", "SRV02", "SRV02 is not reachable", false),
array("10.10.0.4", "25", "SRV04", "SRV04 is not reachable", false),
array("10.10.0.249", "5900", "SRV_ALT", "SRV_ALT is not reachable", false),
);

foreach($hosts as $entry) {
if(!checkHost($entry[0], $entry[1], $entry[2], $entry[3]) && $entry[4] === true) {
break;
}
flush();
}

/*
* do not make changes beyond this magic line
* -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
*/

function checkHost($host, $port, $uniqueKey) {
$log = new Logger($uniqueKey);

$log->log("START AT ".date("d.m.Y H:i:s"));
$log->log("CONNECT TO ".$host.":".$port);

$iErr = – 1;
$lckFile = $uniqueKey . ".lck";
$errorMsg = $uniqueKey." is ";

$fp = fsockopen($host, $port, $iErr, $error, SERVER_TIMEOUT_SEK);

if($fp == true) {
fclose($fp);
$log->log("CONNECTED SUCCESFUL");

$lastOutageTime = 0;
if(file_exists($lckFile)) {
$lastOutageTime = file_get_contents($lckFile);
}
if(SMS_ENABLED == true && $lastOutageTime > (time() – LAG)) {
$log->log("SEND SYSTEM ALIVE SMS");
$errorMsg .= "UP";
sendSMS($errorMsg);
sendMail($errorMsg);
}
unlink($lckFile);

} else {
$log->log("CONNECTION FAILED");

$lastOutageTime = 0;
$errorMsg .= "DOWN";
if(file_exists($lckFile)) {
$lastOutageTime = file_get_contents($lckFile);
}

$log->log("LAST OUTAGE ON: " . date("d.m.Y H:i:s", $lastOutageTime));
if(SMS_ENABLED == true && $lastOutageTime < (time() – LAG)) {
$log->log("SEND SMS AND MAIL");

sendSMS($errorMsg);
sendMail($errorMsg);
} else if(SEND_MAIL_ANYTIME == true) {
$log->log("SEND MAIL");
sendMail($errorMsg);
}

file_put_contents($lckFile, $lastOutageTime == 0 ? time() : $lastOutageTime);
}
$log->log("FINISHED");
$log->close();

return $fp;
}

function sendMail($content) {
mail(TO_MAIL, $content, SMS_PROVIDER_MAIL_BODY . $content, "from:" . FROM_MAIL);
}

function sendSMS($content) {
mail(SMS_PROVIDER_TO, $content, SMS_PROVIDER_MAIL_BODY . $content, "from:" . FROM_MAIL);
}

class Logger {

private $system = "n/a";
private $logFile = "no.log";

public function __construct($sys = "N/A") {
$sys = str_replace(" ", "_", $sys);
$this->system = $sys;
$this->logFile = $sys.".log";
$this->start();
}

public function log($msg) {
echo "[" . $this->system. "] \t ".$msg. "\r\n";
}

public function start() {
ob_start();
ob_clean();
echo "<pre>";
}
public function close() {
echo "</pre>";
file_put_contents($this->logFile, file_get_contents($this->logFile).ob_get_contents());
}
}

?>
[/code]

Schlusswort

Bisher läuft das Script einwandfrei und zuverlässig. Die SMS kommen ca. 30 Sekunden nach dem Abschicken an, sodass sich die SMTP Schnittstelle als praxistauglich erwiesen hat.

Die Schwäche des Scripts ist, dass für die Benachrichtigung ein funktionstüchtiger Netzwerkzugang samt Internetverbindung vorausgesetzt ist. Fällt der Router oder das Internet aus, so wird auch keine Benachrichtigung verschickt. Das ist sicher für manche Anwendungsfälle ein K.O.-Kriterium, doch ist in meinem Fall ein zu akzeptierender Umstand.

10 Gedanken zu „Server Überwachung via SMS und Mail“

  1. Hallo,

    warum das Rad neu erfinden? Es gibt eine Menge Tools im Netz
    die das alles schon anbieten und sogar sehr kostengünstig.

    Bloonix (www.bloonix.net) ist zum Beispiel mal einen Blick Wert. 🙂

    Viele Grüße
    opi

  2. Hallo, ich finden den Script „Server Überwachung via SMS und Mail“ echt super, nur habe ich ein problem mit der logdatei das die nicht erstellt wird oder ich sie nicht finde. wenn ich z.B. den script per crontab alle 5 minuten laufen lasse, bekomme ich auch alle 5 minuten eine mail oder wenn ich das mit der SMS eingerichtet habe alle 5 Minuten eine SMS wenn der server länger ausfallen sollte.
    laufen soll der script auf einem debian root server.

    Wäre nett wenn Sie mir da weiter helfen können.

  3. @opi: Wieso für etwas Geld bezahlen, wenn man es umsonst haben kann? 🙂 Das Script dient auch mehr dazu eigene Server im eigenen Internet zu überwachen, deren Daten ich vielleicht nur ungern an einen Dritten weitergeben möchte.

    @Robert: Du solltest sicher stellen, dass der User mit dem dein Apache läuft auch Schreibzugriff auf den Ordner hat. Dein Problem klingt sehr danach, als wenn dir die Berechtigung fehlt: Denn wenn das Script keine „lock“ Datei schreiben kann, bekommst du bei jedem Scriptaufruf eine Benachrichtigungs SMS und Mail, da sich das Script seinen Status nicht „merken“ kann.

    Die Logdateien könntest du manuell von Hand anlegen, damit solltest du zumindest die Logausgaben sehen. Allerdings löst das nicht das Problem, dass das Script die LOCK Dateien nicht schreibt.

    Siehst du denn eine Fehlermeldung, wenn du das Script manuell aufrufst?

  4. Seh ich genau so – warum Geld ausgeben 😉

    Also das mit den log Files hab ich jetzt hin bekommen die werden jetzt erzeugt – es hat an den rechten gelegen.

    Ich mach aber anscheinend immer noch was falsch!
    Normal sollte ich innerahlb einer Stunde 1 eine Nachricht bekommen wenn der Server Down ist. Ich hab die zeiten des Cronjob mal auf eine Minute gestellt. ich bekomme trotz das die log dateinen und eine ..lck alle minute eine nachricht das der server down ist.

  5. oki hab was vergessen er sendet erst sms und mai

    [SRV01] SEND SMS AND MAIL

    und dann nur mail

    [SRV01] SEND MAIL
    ist das richtig so ???

  6. Genau… beim ersten mal sendet er ne SMS und EMail. Dann merkt er sich die Zeit des Ausfall uns beim nächsten Scriptaufruf wird überprüft, wie lange der letzte Ausfall her ist. Wird die Zeitspanne die in der Konstanten „LAG“ eingestellt ist (derzeit 3600 Sekunden also 60 Minuten) nicht überschritten, wird auch keine weitere SMS geschickt und nur eine kostenlose Mail versendet. Eine SMS wird erst dann wieder versendet, wenn der Server nach 60 Minuten immer noch nicht erreichbar ist oder dann, wenn er wieder online ist.

    Ich hab die Sperre eingebaut, damit nicht unnötig viele SMS versendet werden. Über die (neue) Konstante „SEND_MAIL_ANYTIME“ kann eingestellt werden, ob bei jedem Script Aufruf eine EMail versendet wird. Standardmäßig ist sie nun auf „false“ gestellt, versendet also beim erneuten Scriptaufruf und der Nichterreichbarkeit keine Email.

  7. Hallo
    hab es jetzt noch mal getestet.
    Wenn der Server einmal ausfällt Funktioniert das ganz gut das man nur einmal eine Nachricht bekommt.

    Fällt er aber ein nach der 1 Stunde irgend wann noch mal aus, so bekommt alle 5 Minuten wieder eine Nachricht.

    Das geht erst wieder wenn man die .lck Datei löscht.

    Kann man das Problem irgend wie lösen ??
    Ansonst läuft der Script ohne Probleme

    Gruß
    Robby

  8. Hallo,

    ich hab dein Script auf einer Qnap TS410 montiert. Im Browser wird die Abfrage korrekt ausgegeben, aber es wird kein Mail verschickt. Wie hast du das auf der Qnap hinbekommen?

    Danke und Gruß – Adino

  9. Mh? Ich denke mal, dass es Voraussetzung ist, das du in den Admin Interface unter „Benachrichtigungen“ auf jeden Fall nen Mailserver konfiguriert haben solltest. Dann muss das eigentlich funktionieren.

Kommentare sind geschlossen.