██╗ ██╗ ██╗███╗ ███╗███████╗███╗ ██╗███╗ ██╗ ██████╗ ███╗ ██╗
██║ ██║ ██║████╗ ████║██╔════╝████╗ ██║████╗ ████║██╔═══██╗████╗ ██║
██║ ██║ ██║██╔████╔██║█████╗ ██╔██╗ ██║██╔████╔██║██║ ██║██╔██╗ ██║
██║ ██║ ██║██║╚██╔╝██║██╔══╝ ██║╚██╗██║██║╚██╔╝██║██║ ██║██║╚██╗██║
███████╗╚██████╔╝██║ ╚═╝ ██║███████╗██║ ╚████║██║ ╚═╝ ██║╚██████╔╝██║ ╚████║
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
Lightweight system monitoring with MQTT transport. Sets up as docker server 60 Seconds, add clients via one magic command in 10 seconds to start monitoring. No dashboard config, no hassle.
Console (central dashboard):
curl -sSL https://raw.githubusercontent.com/chriopter/lumenmon/main/console/install.sh | bash
## Supported Agent Systems
| OS | Components |
|----|------------|
| Debian/Ubuntu | **generic**: cpu, memory, disk, heartbeat, hostname |
| Proxmox VE | **generic** + **proxmox**: vms, containers, storage, ZFS |
┌─────────────┐ ┌─────────────┐
│ Agent │──────────────►│ Console │
├─────────────┤ MQTT/TLS ├─────────────┤
│ Collectors │──────────────►│ • MQTT 8884 │──► Web :8080
│ (see below) │ │ • SQLite │
└─────────────┘ │ • Flask │
(bare metal) └─────────────┘
(Docker)
| Rhythm | Interval | Metrics |
|---|---|---|
| PULSE | 1s | cpu, heartbeat |
| BREATHE | 60s | memory, disk |
| CYCLE | 5m | proxmox vms/containers/storage/zfs |
| REPORT | 1h | hostname, os, kernel, uptime |
Console (lumenmon):
lumenmon # Show status
lumenmon invite # Generate agent invite
lumenmon logs # View logs
lumenmon update # Update container
lumenmon uninstall # Remove everythingAgent (lumenmon-agent):
lumenmon-agent # Show status
lumenmon-agent register # Register with invite URL
lumenmon-agent start/stop # Control service
lumenmon-agent logs # View logs
lumenmon-agent uninstall # Remove agentConsole
Docker container running MQTT broker (Mosquitto), SQLite database, and web dashboard (Flask + Caddy).
Install: Downloads docker-compose.yml, pulls image from GitHub Container Registry, starts container.
Update: lumenmon update pulls latest image and restarts container. Data in ~/.lumenmon/console/data/ is preserved.
Uninstall: lumenmon uninstall stops container, removes image and all data.
Agent
Pure bash scripts that collect metrics and publish via mosquitto_pub over TLS. No Docker, no compiled binaries.
Supported Platforms:
| Platform | Install Path | Service |
|---|---|---|
| Debian/Ubuntu | /opt/lumenmon/ |
systemd |
| Proxmox VE | /opt/lumenmon/ |
systemd |
Requirements: mosquitto-clients (apt install mosquitto-clients)
Install:
- Downloads scripts to
/opt/lumenmon/ - Creates systemd service
lumenmon-agent.service - Creates CLI
/usr/local/bin/lumenmon-agent
Update: lumenmon-agent update fetches and checks out the latest release tag. Credentials preserved. The console dashboard shows "UPDATE AVAILABLE" when a newer version exists.
Uninstall: lumenmon-agent uninstall stops service/process, removes files.
Security
- TLS Pinning: Agents verify server certificate fingerprint on first connection
- Per-agent credentials: Each agent gets unique MQTT credentials
- Outbound only: Agents initiate connections, console cannot connect to agents
- Rate limiting: MQTT broker limits connections and message rates
Data Retention
Metrics older than 24h are auto-deleted every 5 minutes. The most recent value per metric is always preserved so offline agents keep showing their last known status.
Writing Custom Collectors
Collectors are bash scripts in agent/collectors/. Standard structure:
#!/bin/bash
# What this collector does.
# Data source and calculation details.
METRIC="generic_example"
TYPE="REAL" # REAL, INTEGER, or TEXT
MIN=0 # Optional: minimum valid value
MAX=100 # Optional: maximum valid value
source "$LUMENMON_HOME/core/mqtt/publish.sh"
while true; do
# IMPORTANT: Use LC_ALL=C for commands that produce localized output
value=$(LC_ALL=C some_command | parse_output)
publish_metric "$METRIC" "$value" "$TYPE" "$BREATHE" "$MIN" "$MAX"
[ "${LUMENMON_TEST_MODE:-}" = "1" ] && exit 0 # Support: lumenmon-agent status
sleep $BREATHE
doneLocale handling: Always use LC_ALL=C prefix for system commands to ensure consistent English output parsing:
# Good - forces English output
total=$(LC_ALL=C apt list --upgradable 2>/dev/null | grep -c "upgradable from")
usage=$(LC_ALL=C df -P / | tail -1 | awk '{print $5}' | tr -d '%')
# Bad - output varies by system locale
total=$(apt list --upgradable | grep -c "upgradable from") # Fails on German systemspublish_metric signature:
publish_metric "name" "value" "TYPE" interval [min] [max]Health Detection: Values outside min/max bounds show as failed in dashboard.
# Static bounds (percentages)
publish_metric "cpu" "$val" "REAL" "$PULSE" 0 100
# Dynamic bounds (ZFS: online must equal total drives)
publish_metric "zfs_online" "$online" "INTEGER" "$CYCLE" "$total" "$total"
# One-time metric (interval=0, never stale)
publish_metric "hostname" "$host" "TEXT" 0Categories:
| Directory | Prefix | Purpose |
|---|---|---|
collectors/generic/ |
generic_ |
Universal (CPU, memory, disk) |
collectors/proxmox/ |
proxmox_ |
Proxmox (VMs, containers, ZFS) |
Development
./dev/auto # Full reset and setup
./dev/add3 # Spawn 3 test agents
./dev/add-virtual # Virtual agent with ALL metrics (no Proxmox/ZFS needed)
./dev/release # Create new releaseThe virtual agent publishes fake data for all collectors (generic + proxmox + zfs) for testing widgets without real infrastructure.