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. LibreNMS bringt um die 4’500 MIBs von über 330 Herstellern mit, die es als Basis verwendet, um auf Erkennungs-Definitionen in YAML oder PHP umzusteigen. 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-kompatible Plugins (beispielsweise unsere Monitoring-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 mit Apache und PHP 8.1.
EPEL-Repo sowie PHP 8.1 installieren. Dann:
dnf -y install bash-completion cronie fping gcc git httpd ImageMagick mtr net-snmp net-snmp-utils nmap python3 python3-devel python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
MariaDB-Server (vorzugsweise 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 --execute="CREATE DATABASE librenms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON librenms.* TO 'librenms'@'localhost' IDENTIFIED BY 'linuxfabrik'; GRANT ALL PRIVILEGES ON librenms.* TO 'librenms'@'::1' IDENTIFIED BY 'linuxfabrik'; 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 --home-dir /opt/librenms --no-create-home --system --shell "$(which bash)"
chown -R librenms:librenms /opt/librenms
chmod 771 /opt/librenms
setfacl -d -m g::rwx /opt/librenms/rrd /opt/librenms/logs /opt/librenms/bootstrap/cache/ /opt/librenms/storage/
setfacl -R -m g::rwx /opt/librenms/rrd /opt/librenms/logs /opt/librenms/bootstrap/cache/ /opt/librenms/storage/
# enable lnms command completion
cp /opt/librenms/misc/lnms-completion.bash /etc/bash_completion.d/
ln -s /opt/librenms/lnms /usr/bin/lnms
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-gmp 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
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
rrdcache konfigurieren - siehe https://docs.librenms.org/Extensions/RRDCached/
SELinux:
dnf -y install policycoreutils-python-utils
semanage fcontext --add --type httpd_sys_content_t '/opt/librenms/html(/.*)?'
semanage fcontext --add --type httpd_sys_rw_content_t '/opt/librenms/(rrd|storage)(/.*)?'
semanage fcontext --add --type httpd_log_t "/opt/librenms/logs(/.*)?"
semanage fcontext --add --type bin_t '/opt/librenms/librenms-service.py'
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/dist/librenms.cron /etc/cron.d/librenms
cp /opt/librenms/misc/librenms.logrotate /etc/logrotate.d/librenms
Scheduler:
cp /opt/librenms/dist/librenms-scheduler.service /opt/librenms/dist/librenms-scheduler.timer /etc/systemd/system/
systemctl enable librenms-scheduler.timer
systemctl start librenms-scheduler.timer
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 auf https://librenms.example.com/validate
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
- Logs untersuchen:
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 bzw. zeigen „nan“ an?
Um die möglichen Ursachen einzugrenzen, sollte man als erstes prüfen, ob überhaupt Werte bei der rrd-Datei ankommen:
rrdtool lastupdate /opt/librenms/rrd/host1.example.com/mempool-cmp-system-1.rrd # used free # 1723635908: 121753660 413390740 date --date @1723635908 # Mi 14 Aug 2024 13:45:08 CEST
Ist dies nicht der Fall dann muss der Poller untersucht werden:
sudo su - librenms ./poller.php -h DEVICE -d -f exit
Falls Werte bei rrd ankommen, muss als nächstes geprüft werden, ob rrd diese verwirft. Dazu können die Werte der letzten Stunde ausgelesen werden:
rrdtool fetch /opt/librenms/rrd/host1.example.com/mempool-cmp-system-1.rrd AVERAGE -s 'now - 1hour' # used free # 1723632960: 1.2175385030e+08 4.1339054970e+08 # 1723633080: 1.2175385030e+08 4.1339054970e+08 # 1723633200: 1.2175385030e+08 4.1339054970e+08 # ... rrdtool fetch /opt/librenms/rrd/host2.example.com/mempool-cmp-system-1.rrd AVERAGE -s 'now - 1hour' # used free # 1723632960: -nan -nan # 1723633080: -nan -nan # 1723633200: -nan -nan # ...
Rrd verwirft Werte, die ausserhalb der min / max Einstellung liegen oder zu spät ankommen. Aus der Rrd Doku:
„min and max define the expected range values for data supplied by a data source. If min and/or max are specified any value outside the defined range will be regarded as UNKNOWN.“
„heartbeat defines the maximum number of seconds that may pass between two updates of this data source before the value of the data source is assumed to be UNKNOWN.“
Die Einstellungen der rrd-Datei auslesen:
rrdtool info /opt/librenms/rrd/host1.example.com/mempool-cmp-system-1.rrd | grep -E '(min|max|step|minimal_heartbeat) ' # step = 120 # ds[used].minimal_heartbeat = 600 # ds[used].min = 0.0000000000e+00 # ds[used].max = NaN # ds[free].minimal_heartbeat = 600 # ds[free].min = 0.0000000000e+00 # ds[free].max = NaN
Im Zusammenspiel mit LibreNMS ist meistens der heartbeat am „nan“-Wert schuld, denn der Poller muss innerhalb von diesem Wert durchlaufen können (siehe LibreNMS Doku). Die Laufzeit des Pollers finden sich unter https://librenms.example.com/poller/performance, der heartbeat kann unter https://librenms.example.com/settings/poller/rrdtool entsprechend gesetzt werden. Dabei ist zu bemerken, dass diese Settings nur für neu erstellte Rrd-Datenbanken gelten - die bestehenden Datenbanken müssen mittels
./scripts/rrdstep.php
angepasst werden.Alternativ können einzelne Datenbanken direkt angepasst werden:
rrdtool tune /opt/librenms/rrd/host1.example.com/mempool-cmp-system-1.rrd --heartbeat used:600 --heartbeat free:600
- 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.- Manuell gesetzte Schwellwerte werden bei einem erneuten Discovery-Lauf überschrieben.
Eine (etwas umständliche) Lösung besteht darin, das betroffene Gerät von der Discovery auszuschliessen. Dazu muss die IP des Gerätes unter Global Settings > Discovery > Networks > Networks/IPs to be ignored eingetragen werden.
Built on 2024-11-18