LibreNMS
Siehe auch
Icinga
LibreNMS (Network Monitoring System) ist ein PHP (Laravel)/MySQL-basiertes Netzwerk-Monitoring-System mit Autodiscovery-Fähigkeiten. Es entstand durch einen Fork der Software Observium. Geräte müssen zu Beginn über SNMP- oder IPMI-Fähigkeiten verfügen, um Out-of-the-Box überwacht werden zu können. Im Bereich SNMP verzichtet LibreNMS auf den Einsatz von MIBs, und setzt auf Erkennungs-Definitionen in YAML oder PHP - MIBs nutzt es nur, um OIDs leichter lesbarer zu gestalten. Es aktualisiert sich im Standard täglich selbst aus dem Github-Repo.
Es unterstützt eine breite Masse an Netzwerk-Hardware von verschiedenen Herstellern, z. B. Cisco, FS (Fiberstore), Dell oder HP. Vorkonfigurierte Alert-Rules gibt es unter anderem für folgende spezifischen Geräte:
APC UPS
Aruba Wireless AP
AXIS camera
Cisco ASA, Cisco NX-OS
Comware
Dell iDRAC, Dell Server
F5 appliance
HP Procurve, HPE BladeSystem, HPE iLo
Netscaler
Palo Alto Networks
QNAP NAS
RITTAL
Synology NAS
UBNT EdgeSwitch
LibreNMS kann direkt an Graylog und diverse Zeitreihendatenbanken wie Graphite, InfluxDB, OpenTSDB, Prometheus und RRDToolDB angeschlossen werden. Zudem bietet es die Möglichkeit, Nagios-Plugins zu nutzen, um zusätzliche Überwachung ausserhalb von SNMP oder IPMI durchzuführen.
LibreNMS führt im Standard folgende Tasks aus:
Suche nach Alerts: minütlich
Discovery für neu hinzugefügte Devices: alle 5 Minuten (es dauert also bis zu 5 Minuten, bis alle Eigenschaften eines neuen Gerätes erkannt wurden)
Nagios-Checks ausführen: alle 5 Minuten
Abfrage von Daten für Rechnungen: alle 5 Minuten
Rechnungsdaten zusammenstellen: stündlich
Automatische Updates: täglich (funktioniert auch für Stable Releases)
Minimale Voraussetzungen:
2x CPU
8 GB RAM (weniger macht im Real-Life-Betrieb keinen Sinn)
10 GB Disk
Installation
Einsatz auf RHEL 8, unter Apache mit PHP >= 7.3 (PHP 8+ funktioniert einwandfrei).
EPEL-Repo installieren.
Dann:
dnf -y install bash-completion cronie fping git httpd ImageMagick mtr net-snmp net-snmp-utils nmap python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
MariaDB-Server aus dem Hersteller-Repo installieren und absichern.
MariaDB konfigurieren:
cat > /etc/my.cnf.d/z00-server.cnf << EOF
[mysqld]
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 0
lower_case_table_names = 0
EOF
systemctl restart mariadb
# create db and db-user
mysql --user root --execute="CREATE DATABASE librenms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON librenms.* TO 'librenms'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON librenms.* TO 'librenms'@'::1' IDENTIFIED BY 'password'; FLUSH PRIVILEGES;"
LibreNMS von Github ziehen und installieren, und dabei auf eine offizielle Version setzen:
cd /opt
git clone https://github.com/librenms/librenms.git
cd /opt/librenms
git fetch --tags
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
useradd librenms -d /opt/librenms -M -r -s "$(which bash)"
chown -R librenms:librenms /opt/librenms
chmod 771 /opt/librenms
chmod -R g=rwx /opt/librenms/rrd /opt/librenms/logs /opt/librenms/bootstrap/cache /opt/librenms/storage
# enable lnms command completion
ln -s /opt/librenms/lnms /usr/bin/lnms
cp /opt/librenms/misc/lnms-completion.bash /etc/bash_completion.d/
Remi-Repo installieren.
PHP 8 aus dem Remi-Repo installieren.
Anschliessend:
dnf -y install php-fpm php-cli php-common php-curl php-gd php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd
# Install PHP dependencies
sudo -u librenms -i ./scripts/composer_wrapper.php install --no-dev
# set the timezones
sed -i "s|^;date.timezone.*|date.timezone = Europe/Zurich|g" /etc/php.ini
timedatectl set-timezone Europe/Zurich
# configure php-fpm
cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/librenms.conf
sed -i "s|^\[www\]|[librenms]|g" /etc/php-fpm.d/librenms.conf
sed -i "s|^user = .*|user = librenms|g" /etc/php-fpm.d/librenms.conf
sed -i "s|^group = .*|group = librenms|g" /etc/php-fpm.d/librenms.conf
sed -i "s|^listen = .*|listen = /run/php-fpm-librenms.sock|g" /etc/php-fpm.d/librenms.conf
# if there are no other PHP web applications on this server:
mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.orig
Apache konfigurieren:
cat > /etc/httpd/conf.d/librenms.conf << EOF
<VirtualHost *:80>
DocumentRoot /opt/librenms/html/
ServerName librenms.example.com
Protocols h2 h2c http/1.1
AllowEncodedSlashes NoDecode
<Directory "/opt/librenms/html/">
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
</Directory>
# Enable http authorization headers
<IfModule setenvif_module>
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
</IfModule>
<FilesMatch ".+\.php$">
SetHandler "proxy:unix:/run/php-fpm-librenms.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
EOF
> /etc/httpd/conf.d/welcome.conf
systemctl enable --now httpd
systemctl enable --now php-fpm
rrdcached installieren:
setsebool -P httpd_setrlimit on
systemctl enable --now rrdcached
$config['rrdcached'] = "unix:/tmp/rrdcached.sock";
SELinux:
dnf -y install policycoreutils-python-utils
semanage fcontext -a -t httpd_sys_content_t '/opt/librenms/html(/.*)?'
# httpd_log_t is required for the logrotate to work
semanage fcontext -a -t httpd_log_t '/opt/librenms/logs(/.*)?'
semanage fcontext -a -t httpd_sys_rw_content_t '/opt/librenms/(rrd|storage)(/.*)?'
restorecon -RFvv /opt/librenms
setsebool -P httpd_can_sendmail 1
setsebool -P httpd_execmem 1
chcon -t httpd_sys_rw_content_t /opt/librenms/.env
cat > /tmp/http_fping.tt << EOF
module http_fping 1.0;
require {
type httpd_t;
class capability net_raw;
class rawip_socket { getopt create setopt write read };
}
#============= httpd_t ==============
allow httpd_t self:capability net_raw;
allow httpd_t self:rawip_socket { getopt create setopt write read };
EOF
checkmodule -M -m -o /tmp/http_fping.mod /tmp/http_fping.tt
semodule_package -o /tmp/http_fping.pp -m /tmp/http_fping.mod
semodule -i /tmp/http_fping.pp
Python:
pip3 install -r /opt/librenms/requirements.txt
SNMP konfigurieren:
\cp /opt/librenms/snmpd.conf.example /etc/snmp/snmpd.conf
# set community string to "public" for example
sed -i "s/RANDOMSTRINGGOESHERE/public/g" /etc/snmp/snmpd.conf
curl -o /usr/bin/distro https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/distro
chmod +x /usr/bin/distro
systemctl enable snmpd
systemctl restart snmpd
Cronjobs, Logrotate:
cp /opt/librenms/librenms.nonroot.cron /etc/cron.d/librenms
cp /opt/librenms/misc/librenms.logrotate /etc/logrotate.d/librenms
Firewall: Port 80/443 freischalten.
Der Webinstaller kann über http://librenms.example.com aufgerufen werden, wird am Ende aber die Datei /opt/librenms/config.php
nicht schreiben können. Er zeigt dafür den generierten Inhalt an - diesen kopieren und manuell in die Datei einfügen.
Beispiel für diese Datei:
<?php
## Have a look in misc/config_definitions.json for examples of settings you can set here. DO NOT EDIT misc/config_definitions.json!
// This is the user LibreNMS will run as
//Please ensure this user is created and has the correct permissions to your install
$config['user'] = 'librenms';
### This should *only* be set if you want to *force* a particular hostname/port
### It will prevent the web interface being usable form any other hostname
#$config['base_url'] = "/";
### Enable this to use rrdcached. Be sure rrd_dir is within the rrdcached dir
### and that your web server has permission to talk to rrdcached.
$config['rrdcached'] = "unix:/tmp/rrdcached.sock";
### Default community
$config['snmp']['community'] = array('public');
### Authentication Model
$config['auth_mechanism'] = "mysql"; # default, other options: ldap, http-auth
#$config['http_auth_guest'] = "guest"; # remember to configure this user if you use http-auth
### List of RFC1918 networks to allow scanning-based discovery
#$config['nets'][] = "10.0.0.0/8";
#$config['nets'][] = "172.16.0.0/12";
#$config['nets'][] = "192.168.0.0/16";
# Uncomment the next line to disable daily updates
#$config['update'] = 0;
# Number in days of how long to keep old rrd files. 0 disables this feature
$config['rrd_purge'] = 0;
# Uncomment to submit callback stats via proxy
#$config['callback_proxy'] = "hostname:port";
# Set default port association mode for new devices (default: ifIndex)
#$config['default_port_association_mode'] = 'ifIndex';
# Enable the in-built billing extension
$config['enable_billing'] = 1;
# Enable the in-built services support (Nagios plugins)
$config['show_services'] = 1;
Danach:
echo '$config["update_channel"] = "release";' >> /opt/librenms/config.php
chown librenms:librenms /opt/librenms/config.php
Nach der Installation empfiehlt sich
Eine Validation: Settings (Zahnrad-Symbol oben rechts) > Validate Settings.
Das Anlegen der ersten Alert Rules: Alerts > Alert Rules > Click here to create the default alert rules
Alert Rules anpassen, z.B. Ping Latency: Severity auf Warning und Latency > 100 stellen.
Anlegen erster Devices.
Erste Alerts bestätigen und beheben: Alerts > Notifications
LibreNMS-Panel statt Grafana-Panel bei den Alerts
https://community.librenms.org/ > slamlomsk8er
Details siehe https://docs.librenms.org/Installation/Install-LibreNMS/.
AutoDiscovery
AutoDiscovery für Netze aktivieren - Netze bekanntgeben (im Beispiel nicht über die Web-Oberfläche, sondern per Config-Datei):
# https://docs.librenms.org/Extensions/Auto-Discovery/
# v1 or v2c
$config['snmp']['community'][] = "public";
#$config['snmp']['community'][] = "another_community";
$config['nets'][] = '10.80.32.0/24';
Die Netzmasken müssen zum Netz passen - ein 192.168.1.0/22 funktioniert beispielsweise nicht.
SNMP-Scan manuell anstossen:
su - librenms
./snmp-scan.py --verbose
Services
LibreNMS kann Nagios-Plugins ausführen, beispielsweise die Monitoring-Plugins der Linuxfabrik (hier müssen die Python3-Varianten eingesetzt werden). Services können lokal oder remote ausgeführt werden - letzteres erfolgt per NRPE. Mehr dazu unter https://docs.librenms.org/Extensions/Services/.
Der Check-Dateiname muss mit check_
beginnen, sie müssen per chmod +x
ausführbar sein, und sie müssen den -H
-Parameter unterstützen (LibreNMS setzt diesen immer, auch wenn bei der Service-Definition im Web-GUI unter „Remote Host“ nichts angegeben wird).
mkdir -p /usr/lib64/nagios/plugins/{lib,logs}
touch /usr/lib64/nagios/plugins/logs/services_wrapper.log
chown -R librenms:librenms /usr/lib64/nagios/plugins
$config['nagios_plugins'] = "/usr/lib64/nagios/plugins";
$config['service_discovery_enabled'] = true;
$config['service_discovery_frequency'] = 3600;
$config['service_discovery_workers'] = 16;
$config['service_poller_down_retry'] = 5;
$config['service_poller_enabled'] = true;
$config['service_poller_frequency'] = 300;
$config['service_poller_workers'] = 16;
$config['service_services_enabled'] = true;
$config['service_services_frequency'] = 60;
$config['service_services_workers'] = 16;
*/5 * * * * librenms /opt/librenms/services-wrapper.py 1
Probleme bei der Check-Ausführung untersucht man so:
su - librenms
# d = Debug
./check-services.php -d
Die Optionen sind:
d: Debug
h: Hostname oder Device-ID
Alert Rules
Ein Beispiel:
devices.os = "Netscaler" AND sensors.sensor_current != `sensors.sensor_prev` AND sensors.lastupdate < "DATE_SUB(NOW(),INTERVAL 5 MINUTE)"
Beispiele für Eigenschaften:
%applications.app_type = 'portactivity'
%applications_metrics.http_total_to > '100'
application_metrics.metric = ".status"
application_metrics.value >= "2"
applications.app_state != "OK"
applications.app_type = "mysql"
bgpPeers.bgpPeerAdminStatus != "stop"
bgpPeers.bgpPeerFsmEstablishedTime < "300"
bgpPeers.bgpPeerState != "established"
ciscoASA.data > "5000"
component.disabled = 0
component.ignore = 0
component.type = "ISIS"
customoids.customoid_alert = "1"
customoids.customoid_current >= `customoids.customoid_limit_warn`
devices.inserted >= `macros.past_60m`
devices.last_ping_timetaken > "10"
devices.last_polled < DATE_SUBNOW, INTERVAL 6 MINUTE
devices.os = "qnap"
devices.status_reason = "snmp"
devices.uptime < "300"
eventlog.datetime >= `macros.past_60m`
eventlog.message LIKE 'ifSpeed:%'
eventlog.message ~ "@autodiscovered@"
eventlog.type = "discovery"
ipsec_tunnels.tunnel_status != "active"
isis_adjacencies.isisISAdjState = "down"
macros.bill_cdr_over_quota >= "75"
macros.bill_quota_over_quota >= "75"
macros.device = "1"
macros.device_down = "1"
macros.device_up = "1"
macros.port_down = "1"
macros.port_up = "1"
macros.port_usage_perc >= "80"
macros.sensor_port_link = "1"
macros.state_sensor_critical = 1
macros.state_sensor_warning = 1
ports.disabled = 0
ports.ifOperStatus = "down"
ports.ifOperStatus_prev = "up"
ports.ifOutErrors_rate >= "100" || ports.ifInErrors_rate >= "100"
ports.ifSpeed < ports.ifSpeed_prev
ports.port_id = eventlog.reference
processors.processor_usage > "85"
sensors.lastupdate < "DATE_SUBNOW,INTERVAL 5 MINUTE"
sensors.sensor_alert = "1"
sensors.sensor_current != `sensors.sensor_prev`
sensors.sensor_current < `sensors.sensor_limit_low`
sensors.sensor_current ~ "[2|4|5|7|10|11]"
sensors.sensor_current ~ "[3-4]"
sensors.sensor_descr = "Primary Unit.*"
sensors.sensor_descr REGEXP ".*PEM.*"
sensors.sensor_descr ~ "Percentage load"
sensors.sensor_oid ~ ".1.3.6.1.4.1.11.2.14.11.1.2.6.1.4.[2-5]"
sensors.sensor_prev = "2"
sensors.sensor_type = "cefcFanTrayOperStatus"
services.service_status != "0"
state_indexes.state_name = "UPSUPSOverloaded"
storage.storage_deleted = 0
storage.storage_descr = "/"
storage.storage_perc >= 95
syslog.msg ~ "@arp table is full@"
syslog.priority ~ "alert"
syslog.timestamp >= `macros.past_5m`
wireless_sensors.sensor_alert = "1"
wireless_sensors.sensor_class = "clients"
wireless_sensors.sensor_current >= `wireless_sensors.sensor_limit`
wireless_sensors.sensor_type == "arubaos"
API
Die Schnittstelle wurde als Restful API realisiert, befindet sich aber noch in der Entwicklung. Das API liefert JSON oder PNG zurück. Um das API nutzen zu können, sollte unter Settings > API > API-Settings ein Token erzeugt werden.
Alle verfügbaren Methoden auslesen:
curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.example.com/api/v0
# example: getting sensor values
curl -H 'X-Auth-Token: YOURAPITOKENHERE' 'http://librenms.example.com/api/v0/resources/sensor' | jq
Die möglichen Routen finden sich in der routes/api.php
, die passenden API-Funktionen in includes/html/api_functions.inc.php
.
Troubleshooting
tail -f /opt/librenms/logs/librenms.log /var/log/httpd/*log /var/log/php-fpm/error.log
Installation überprüfen:
sudo su - librenms
./validate.php
exit
Device-Grafiken werden nicht richtig erzeugt? Prüfen, ob die durch folgendes Kommando erzeugten Pfad-Outputs vorliegen:
sudo su - librenms
./poller.php -h DEVICE -d -f
exit
Device lässt sich nicht über das GUI oder per ./delhost DEVICE
löschen?
mysql --user librenms --password
DELETE FROM devices WHERE device_id=9999999;
FAQ
- Woher kommen Schwellwerte („limits“) während der Discovery?
Die Schwellwerte werden automatisch bei der Discovery eines neuen Devices gesetzt. Falls es Hersteller-spezifische Definitionen gibt (unter
includes/discovery
), werden diese verwendet (für Details siehe https://docs.librenms.org/Developing/os/Health-Information). Falls dies nicht der Fall ist, und sensors.guess_limits in der Config gesetzt ist, versucht LibreNMS zu erraten, welche Schwellwerte verwendet werden sollen. Dies passiert in dersensor_limit()
undsensor_low_limit()
-Funktion inincludes/discovery/functions.inc.php
. Z.B. für Temperaturen ist Stand 2022-11-24:Low Limit:
$limit = $current - 10;
High Limit:
$limit = $current + 20;
- Warum sind Schwellwerte („limits“) schon bei einzelnen Geräten pro Core manchmal unterschiedlich? Also zum Beispiel unter Device > Edit > Health.
Dazu muss man verstehen, woher die Schwellwerte überhaupt kommen (siehe vorherige Frage). Sowohl bei den Hersteller-Defaults als auch bei den von LibreNMS erratenen Schwellwerte kann es sein, dass diese Schwellwerte anhand von dem aktuellen Wert festgelegt werden. Da die Cores zum Zeitpunkt der Discovery verschiedene Temperaturen haben, sind auch die Schwellwerte entsprechend verschieden.
- Woher weiss man, welche Werte man z.B. in einer Alert-Rule zu einem Device abfragen kann?
Laut der offiziellen Dokumentation zu Alert-Rules sind das sogenannte „Entities“. Eine „Entity“ basiert direkt auf dem MySQL-Schema, also
tabelle.spalte
, z.B.devices.hostname
. Eine Liste der häufig verwendeten Entities findet man hier: https://docs.librenms.org/Alerting/Entities/.- Disk-Schwellwerte: Wenn man keine Schwellwerte im Graphen per rrdtool sieht, heisst das, dass man nicht alarmiert wird?
Schwellwerte sind in dem Fall meist trotzdem vorhanden, diese sieht man, wenn man auf Device > Edit geht. Alarmiert wird allerdings nur, wenn es auch eine passende Alert-Rule gibt (z.B.
storage.storage_perc >= "storage_perc_warn"
).- Wie werden SNMP-Traps ausgewertet, bzw in Alert-Rules verwendet?
Es gibt es schon mitgelieferte Trap-Handlers (siehe Liste der Handlers, Mapping „Trap zu Handler“ bzw Details im Developer Guide). Normalerweise generiert so ein Handler einen Eintrag im Event Log (der Handler kann aber theoretisch alles mögliche machen).
Alternativ kann man unter General Settings > External > SNMP Traps Integration: „Create eventlog for snmptraps“ auf „All“ setzen, und somit für alle Traps einen Eintrag im Event Log generieren.
Sobald man einen Eintrag im Event Log hat, kann man basierend darauf Alert-Rules erstellen. Ob mit oder ohne Handler,
snmptrapd
muss richtig konfiguriert werden, inklusive explizierter Angabe der MIBs, an denen man interessiert ist. Siehe https://docs.librenms.org/Extensions/SNMP-Trap-Handler.
Built on 2023-09-21