Automated network monitoring for RHEL 10 using Podman and Quadlet
π Automated HTTPS with self-signed certificate generation β’ π³ Podman containerization with Quadlet systemd integration β’ π Idempotent deployment safe to re-run β’ πΎ Persistent storage with bind mounts β’ π‘οΈ SELinux enforcing with proper contexts β’ π₯ Auto-configured firewalls (firewalld/ufw/iptables/nftables) β’ π‘ SNMP trap daemon with testing utilities β’ π₯ Comprehensive health checks β’ ποΈ Clean uninstall with data preservation β’ π€ Helper scripts for common operations β’ π Secrets management via environment variables β’ π Complete documentation with troubleshooting guides
- π― Overview
- ποΈ Architecture
- π¦ Requirements
- πΎ Persistent Storage & Bind Mounts
- π Quick Start
- βοΈ Configuration
- π HTTPS/SSL Support
- π§ Usage
- π‘οΈ Security
- π₯ Firewall Configuration
- π Health Checks
- ποΈ Uninstallation
- π Troubleshooting
- π Helper Scripts
- π§ͺ Testing SNMP Traps
- π License
This project provides fully automated deployment of LibreNMS (network monitoring system) using containerized architecture on RHEL 10. It leverages Podman for rootless-capable container management and Quadlet for native systemd service integration, with comprehensive automation for security, networking, and operations.
- π Automated HTTPS: Self-signed certificates auto-generated, configured, and mounted
- β Idempotent: Safe to re-run without causing errors or duplicating resources
- π Production-ready: SELinux enforcing with
semanage, auto-configured firewalls - β‘ Fully Automated: Zero-touch deployment from prerequisites to health checks
- πΎ Persistent Data: Bind mounts at
/opt/librenmssurvive reboots and uninstalls - π Security First: Complex random database passwords, secrets in
.env, never in git - π₯ Smart Firewall: Auto-detects and configures firewalld/ufw/iptables/nftables
- π‘ SNMP Ready: Includes trap daemon with built-in testing utilities
- π₯ Health Monitoring: Comprehensive validation of all components
- π οΈ Operational Tools: Helper scripts for adding hosts, testing traps
- ποΈ Clean Removal: Uninstall with optional data preservation or complete wipe
- π Well Documented: Extensive guides, troubleshooting, and visual documentation
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RHEL 10 Host β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Internet/Network β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Nginx Reverse Proxy (When HTTPS enabled) β β
β β π SSL/TLS Termination β β
β β β β
β β TCP 80 (HTTP) ββββββββββββΊ 301 Redirect to HTTPS β β
β β TCP 443 (HTTPS) βββββββββββΊ Forward to LibreNMS:8000 β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ β
β β Podman Network: librenms-net β β
β β β β β
β β ββββββββββββββββ βββββββββΌβββββββ ββββββββββββββββ β β
β β β MariaDB β β LibreNMS β β Redis β β β
β β β ποΈ Database β β π Web App β β π¨ Cache β β β
β β β β β β β β β β
β β β Port: 3306 β β Port: 8000 β β Port: 6379 β β β
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β β
β β β β β β
β β βββββββββββ¬ββββββββ΄ββββββββββββββββββ β β
β β β β β β
β β βββββββββββΌβββββββββββββ βββββββββββΌββββββββββ β β
β β β SNMP Trap Daemon β β Nginx Reverse β β β
β β β π‘ Trap Handler β β Proxy (HTTPS) β β β
β β β β β β β β
β β β UDP Port: 162 β β Ports: 80, 443 β β β
β β ββββββββββββββββββββββββ βββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Systemd Quadlet Services β β
β β β’ librenms-db.service β’ librenms.service β β
β β β’ librenms-redis.service β’ librenms-snmptrapd.s.. β β
β β β’ librenms-nginx-proxy.service (when HTTPS enabled) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Persistent Storage: /opt/librenms β β
β β β’ db/ β’ logs/ β’ config/ β β
β β β’ rrd/ β’ plugins/ β’ alerting-templates/ β β
β β β’ certs/ β’ nginx-proxy/ (SSL configs) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Firewall Rules β β
β β β’ UDP 161 (SNMP) β’ UDP 162 (SNMP Traps) β β
β β β’ TCP 80 (HTTP) β’ TCP 443 (HTTPS) π β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SSL/TLS Certificates (if HTTPS enabled) β β
β β Auto-generated self-signed in: /opt/librenms/certs/ β β
β β β’ librenms.crt β’ librenms.key β β
β β Reverse proxy config: /opt/librenms/nginx-proxy/ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Primary: RHEL 10.1 (fully tested) β
- Secondary: Ubuntu 22.04 (best-effort)
β οΈ
- CPU: 2+ cores recommended
- RAM: 4GB minimum, 8GB+ recommended
- Disk: 20GB+ for LibreNMS data and RRD files
- Network: Internet access for container image pulls
The deployment script will automatically install these if missing:
- Podman (4.0+) - Container runtime
- net-snmp & net-snmp-utils - SNMP tools for monitoring
- policycoreutils-python-utils - SELinux management (semanage)
- firewalld - Firewall management (or ufw/iptables/nftables)
- openssl - SSL/TLS certificate generation and management
- curl - HTTP client for health checks and testing
- tar - Archive utility for backup/restore operations
- Root or sudo access required for installation
All LibreNMS data is stored in persistent bind mounts at /opt/librenms/ to ensure data survives
container restarts and host reboots.
/opt/librenms/
βββ db/ (MariaDB database files)
βββ logs/ (Application and trap logs)
βββ rrd/ (RRD graph data)
βββ config/ (LibreNMS configuration)
βββ plugins/ (Installed plugins)
βββ alerting-templates/ (Alert notification templates)
βββ monitoring-plugins/ (Monitoring check plugins)
βββ certs/ (SSL certificates - if HTTPS enabled)
βββ nginx/ (LibreNMS nginx files - extracted from container)
βββ nginx-proxy/ (Reverse proxy config - if HTTPS enabled)
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
/opt/librenms/db |
/var/lib/mysql |
RW | Database storage |
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
/opt/librenms/logs |
/data/logs |
RW | Application logs |
/opt/librenms/rrd |
/data/rrd |
RW | RRD time-series data |
/opt/librenms/config |
/data/config |
RW | Configuration files |
/opt/librenms/plugins |
/opt/librenms/html/plugins |
RW | Web plugins |
/opt/librenms/alerting-templates |
/opt/librenms/resources/templates |
RW | Alert templates |
/opt/librenms/monitoring-plugins |
/usr/lib/monitoring-plugins |
RW | Monitoring checks |
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
/opt/librenms/logs |
/data/logs |
RW | Trap daemon logs |
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
/opt/librenms/nginx-proxy/nginx.conf |
/etc/nginx/nginx.conf |
RO | Reverse proxy config |
/opt/librenms/certs |
/etc/nginx/certs |
RO | SSL certificates |
*Only deployed when LIBRENMS_ENABLE_HTTPS=true
All bind mounts are configured with proper SELinux contexts:
- Label:
container_file_t - Mode:
:Z(private unshared volume) - Tool:
semanage(persistent across reboots)
To backup all LibreNMS data, simply backup /opt/librenms/:
# Backup
sudo tar -czf librenms-backup-$(date +%Y%m%d).tar.gz /opt/librenms/
# Restore
sudo tar -xzf librenms-backup-YYYYMMDD.tar.gz -C /Monitor disk usage of persistent storage:
# Check total usage
du -sh /opt/librenms/
# Check per-directory usage
du -sh /opt/librenms/*
# Check RRD data growth (typically largest)
du -sh /opt/librenms/rrd/π For detailed storage planning: See Storage Sizing Guide for:
- Storage requirements by device count
- Growth rate formulas
- LVM setup procedures
- Capacity planning examples
git clone https://github.com/yourusername/deploy-containerize-libreNMS.git
cd deploy-containerize-libreNMS# Copy the environment template
cp env-example .env
# Edit with your settings
vi .envRequired Configuration:
LIBRENMS_DB_PASSWORD: Database passwordMYSQL_ROOT_PASSWORD: MySQL root passwordLIBRENMS_ADMIN_USER: Admin usernameLIBRENMS_ADMIN_PASSWORD: Admin passwordLIBRENMS_BASE_URL: Your server URL (e.g.,http://192.168.1.100)LIBRENMS_BIND_IP: Bind IP (use0.0.0.0for all interfaces)
sudo ./scripts/deploy-librenms.shThis will:
- β Install all dependencies
- β Configure firewall rules
- β Create persistent storage
- β Set up SELinux contexts
- β Deploy containers via Quadlet
- β Enable and start services
- β Run health check
Open your browser and navigate to:
- HTTP:
http://YOUR_SERVER_IP - HTTPS:
https://YOUR_SERVER_IP(if enabled in.env)
Default Credentials (if using defaults from .env):
- Username:
admin - Password: (as set in
LIBRENMS_ADMIN_PASSWORD)
Enable HTTPS (Optional): Set LIBRENMS_ENABLE_HTTPS=true in .env before deploying
The .env file contains all configuration. Never commit this file to git!
# Database
LIBRENMS_DB_PASSWORD=your_secure_password
MYSQL_ROOT_PASSWORD=your_secure_root_password
# Admin Account
LIBRENMS_ADMIN_USER=admin
LIBRENMS_ADMIN_PASSWORD=your_admin_password
# Network
LIBRENMS_BASE_URL=http://192.168.1.100
LIBRENMS_BIND_IP=0.0.0.0# Use specific versions for production
LIBRENMS_IMAGE=docker.io/librenms/librenms:latest
MARIADB_IMAGE=docker.io/library/mariadb:10.11
REDIS_IMAGE=docker.io/library/redis:7-alpineLIBRENMS_SMTP_HOST=smtp.gmail.com
LIBRENMS_SMTP_PORT=587
LIBRENMS_SMTP_USER=your_email@gmail.com
LIBRENMS_SMTP_PASSWORD=your_app_passwordPurpose: Prevent containers from consuming excessive CPU/memory
When to use:
- Monitoring 50+ devices
- Shared hosting environments
- Production deployments
- Resource-constrained environments
Configuration:
# Enable resource limits
RESOURCE_LIMITS_ENABLED=true
# CPU quotas (percentage of cores)
LIBRENMS_DB_CPU_QUOTA=200% # 2 cores for database
LIBRENMS_CPU_QUOTA=300% # 3 cores for LibreNMS
LIBRENMS_REDIS_CPU_QUOTA=100% # 1 core for Redis
# Memory limits
LIBRENMS_DB_MEMORY_MAX=2G # 2 GB for database
LIBRENMS_MEMORY_MAX=4G # 4 GB for LibreNMS
LIBRENMS_REDIS_MEMORY_MAX=512M # 512 MB for RedisRecommended limits by device count:
| Device Count | DB CPU/Memory | LibreNMS CPU/Memory | Redis CPU/Memory |
|---|---|---|---|
| 10-50 | 200% / 2G | 300% / 4G | 100% / 512M |
| 50-100 | 400% / 4G | 600% / 8G | 200% / 1G |
| 100-500 | 600% / 8G | 800% / 16G | 300% / 2G |
π Detailed guides:
- Resource Limits Documentation - CPU quota, memory limits, performance tuning
- SELinux & Poller Fixes - fping errors, poller not running, AVC denials
This deployment automatically generates and configures HTTPS with self-signed certificates using an nginx reverse proxy for SSL termination.
Enable HTTPS:
-
Edit
.envfile:LIBRENMS_ENABLE_HTTPS=true
-
Deploy:
sudo ./scripts/deploy-librenms.sh
-
Access LibreNMS:
https://your-server-ip (HTTPS - uses self-signed cert) http://your-server-ip (HTTP - redirects to HTTPS)
Architecture:
Browser β Nginx Reverse Proxy (port 443) β LibreNMS (port 8000)
π SSL/TLS Termination HTTP (internal only)
What Happens Automatically:
- β Generates 10-year self-signed certificate (RSA 2048-bit, SHA-256)
- β
Stores certificates in
/opt/librenms/certs/(persistent bind mount) - β
Creates nginx reverse proxy container (
librenms-nginx-proxy) - β Configures SSL termination with TLS 1.2 and 1.3
- β HTTP (port 80) automatically redirects to HTTPS (port 443)
- β Mounts certificates into reverse proxy container
- β Opens firewall ports 80 and 443
- β Adds security headers (HSTS, X-Frame-Options, etc.)
- β Detects existing certificates and reuses them
Certificate Location:
/opt/librenms/certs/
βββ librenms.crt (SSL certificate - public)
βββ librenms.key (Private key - secure)
Browser Warning: Self-signed certificates trigger browser security warnings - this is normal for internal deployments. Click "Advanced" β "Proceed" to accept.
For Details: See SSL Certificates Documentation
Generate Certificates Manually:
sudo ./scripts/installer-scripts-additional/generate-ssl-cert.sh \
--domain librenms.local --ip 192.168.1.100# Standard deployment
sudo ./scripts/deploy-librenms.sh
# Dry-run (see what would be done)
sudo ./scripts/deploy-librenms.sh --dry-run
# Skip health check
sudo ./scripts/deploy-librenms.sh --skip-health-check# Check service status
systemctl status librenms.service
systemctl status librenms-db.service
systemctl status librenms-redis.service
systemctl status librenms-snmptrapd.service
# View logs
journalctl -u librenms.service -f
podman logs -f librenms
# Restart services
systemctl restart librenms.service# List running containers
podman ps
# Execute commands in container
podman exec -it librenms bash
# View container logs
podman logs librenms
podman logs librenms-snmptrapd- β
All secrets stored in
.envfile - β
.envexcluded from git via.gitignore - β Pre-commit hooks scan for accidental secret commits
- β No credentials hardcoded in scripts
The deployment script configures SELinux properly:
# Verify SELinux status
getenforce # Should show "Enforcing"
# Check contexts
ls -Z /opt/librenms
# View SELinux denials
ausearch -m avc -ts recentImportant: Uses semanage (permanent) not chcon (temporary)!
Automatically configured ports:
- UDP 161: SNMP polling
- UDP 162: SNMP traps
- TCP 80: HTTP web interface
- TCP 443: HTTPS (if configured)
The script auto-detects your firewall system:
# View rules
sudo firewall-cmd --list-all
# Verify ports
sudo firewall-cmd --list-ports# View rules
sudo ufw status
# Verify ports
sudo ufw status numberedFirewalld:
sudo firewall-cmd --permanent --add-port=161/udp
sudo firewall-cmd --permanent --add-port=162/udp
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reloadUFW:
sudo ufw allow 161/udp
sudo ufw allow 162/udp
sudo ufw allow 80/tcpRun the health check script to validate your deployment:
sudo ./scripts/health-check.sh
# Verbose mode
sudo ./scripts/health-check.sh --verbose- β Container status (running/stopped)
- β Systemd services (active/inactive)
- β Persistent storage directories
- β Podman network configuration
- β Firewall rules
- β SELinux contexts
- β Web interface accessibility
- β Database connectivity
======================================================================
LibreNMS Health Check
======================================================================
[INFO] Checking container status...
[β
PASS] Container librenms-db is running
[β
PASS] Container librenms-redis is running
[β
PASS] Container librenms is running
[β
PASS] Container librenms-snmptrapd is running
======================================================================
Health Check Summary
======================================================================
Passed: 24
Failed: 0
β
All checks passed!
sudo ./scripts/uninstall-librenms.shThis removes:
- β All containers
- β Systemd service files
- β Podman network
- β Firewall rules
- β
Data preserved at
/opt/librenms
sudo ./scripts/uninstall-librenms.sh --remove-datasudo ./scripts/uninstall-librenms.sh --keep-firewallπ Backup Before Uninstall: See Backup and Restore Guide for:
- VM snapshot procedures (fastest)
- LVM snapshot procedures
- Tar backup procedures
- Complete restore procedures
Check logs:
journalctl -u librenms.service -n 50
podman logs librenmsCommon causes:
- Missing
.envfile - Invalid database password
- Port conflicts (80, 161, 162 already in use)
- SELinux denials
Verify service is running:
systemctl status librenms.service
curl http://localhost:80
# Or for HTTPS:
curl -k https://localhost:443Check firewall:
sudo firewall-cmd --list-portsSee Firewall Configuration for expected ports and manual configuration.
Check container port binding:
podman port librenms
# Should show: 8000/tcp -> 0.0.0.0:80
# If HTTPS enabled: 8443/tcp -> 0.0.0.0:443Check certificates exist:
ls -la /opt/librenms/certs/
# Should show: librenms.crt and librenms.keyCheck nginx reverse proxy:
podman ps | grep nginx-proxy
podman logs librenms-nginx-proxyTest certificate:
openssl s_client -connect localhost:443 -showcertsCheck if HTTPS is enabled in reverse proxy:
podman exec librenms-nginx-proxy cat /etc/nginx/nginx.conf | grep 443Check trap daemon:
systemctl status librenms-snmptrapd.service
podman logs librenms-snmptrapdTest connectivity:
./scripts/post-deploy/test-snmptraps.shVerify firewall:
sudo firewall-cmd --list-ports | grep 162View denials:
ausearch -m avc -ts recentFix contexts:
sudo restorecon -Rv /opt/librenmsCheck database container:
podman exec -it librenms-db mysql -u root -pVerify network:
podman network inspect librenms-netAdd devices to LibreNMS for monitoring:
./scripts/helpers/add-host.sh
# Non-interactive
./scripts/helpers/add-host.sh --hostname switch01.example.com --ip 192.168.1.10Interactive prompts for:
- Hostname/FQDN
- IP address
- SNMP version (v1, v2c, v3)
- SNMP community string
- β Input validation
- β Hostname and IP format checking
- β Confirmation before adding
- β Executes directly in LibreNMS container
Verify that admin user credentials are correctly configured:
sudo ./scripts/post-deploy/verify-login.shPerforms comprehensive checks:
- β
Verifies
.envcredentials are set - β Checks user exists in database
- β Validates user is enabled
- β Confirms admin role is assigned
- β Tests WebUI accessibility
Example Output:
==========================================
LibreNMS Login Verification
==========================================
[β] .env credentials configured
Username: admin
[β] User exists in database
User ID: 1
Email: admin@example.com
Role: admin
Enabled: 1
[β] User is enabled
[β] User has 'admin' role (full privileges)
[β] WebUI is accessible at https://10.1.10.58
[β] All checks passed!
You can now log in to LibreNMS:
URL: https://10.1.10.58
Username: admin
Password: (as set in .env)
Reset the admin password without redeploying:
# Use credentials from .env
sudo ./scripts/installer-scripts-additional/reset-admin-password.sh
# Or specify custom credentials
sudo ./scripts/installer-scripts-additional/reset-admin-password.sh myusername newpasswordUse cases:
- β Password forgotten or lost
- β Password needs to be changed quickly
- β
Password in
.envwas updated - β Testing different password complexity
Note: After running, you can immediately log in with the new password.
Verify that polling and fping (ICMP ping) are working correctly:
sudo ./scripts/post-deploy/verify-poller-fping.sh
# Test with specific target IP
sudo ./scripts/post-deploy/verify-poller-fping.sh 10.1.10.58Performs comprehensive checks:
- β
Verifies
CAP_NET_RAWcapability present - β Tests fping IPv4/IPv6 functionality
- β Checks dispatcher container running
- β Validates dispatcher process active
- β Confirms polling activity in logs
- β
Runs LibreNMS
validate.phpchecks - β Verifies SELinux volume contexts
Use cases:
- β After initial deployment
- β Troubleshooting "Operation not permitted" fping errors
- β Verifying "Poller is not running" fixes
- β Confirming SELinux configuration
- β Testing after Quadlet changes
See also: docs/selinux-poller-fixes.md for detailed troubleshooting
For comprehensive documentation on all available helper scripts, including:
- Device addition (single and bulk)
- Device management (alerts, down ports, discovery modules)
- Diagnostics and troubleshooting
- Common workflows and examples
See: scripts/helpers/README.md - Complete helper scripts guide
Send test SNMP traps to verify trap reception:
./scripts/post-deploy/test-snmptraps.sh
# Test remote instance
./scripts/post-deploy/test-snmptraps.sh --target 192.168.1.100
# Custom community string
./scripts/post-deploy/test-snmptraps.sh --community private- Cold Start - System reinitialization
- Link Up - Interface came online
- Link Down - Interface went offline
- Authentication Failure - SNMP auth failed
- Custom Test Trap - Generic test trap
After sending traps:
- Check LibreNMS web UI: Alerts β Event Log
- View trap daemon logs:
podman logs librenms-snmptrapd - Check trap log files:
/opt/librenms/logs/
This project is licensed under the Apache License 2.0.
Copyright 2026
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Follow coding standards in
docs/ai/CONTEXT.md - Test on RHEL 10.1
- Submit a pull request
- π Requirements Document - Detailed functional requirements
- π€ AI Context - Development standards and guidelines
- π Security & CI Review - Security posture
- βοΈ CI and Pre-commit - Quality gates
| Component | Status | Notes |
|---|---|---|
| Core Deployment | β Complete | Fully functional with all features |
| HTTPS/SSL Support | β Complete | Auto-generated self-signed certificates |
| Health Checks | β Complete | Comprehensive validation |
| Uninstall Script | β Complete | Clean removal with data options |
| Helper Scripts | β Complete | Add hosts, test traps, SSL generation |
| Documentation | β Complete | README, QUICKSTART, SSL guide |
| RHEL 10 Testing | β Tested | Primary platform, fully supported |
| Ubuntu 22.04 | Secondary support | |
| Firewall Auto-detect | β Complete | firewalld/ufw/iptables/nftables |
| SELinux Support | β Complete | Enforcing mode with semanage |
| SNMPv3 Support | π Planned | Future enhancement |
π If this project helped you, please star it on GitHub! π