rmm2/README.md
cynfo3000 5d7a3cbcc1 SQLite durch PostgreSQL + TimescaleDB ersetzt
- Backend DB komplett auf PostgreSQL 17 + TimescaleDB 2.25.1 umgestellt
- pgx pure-Go Driver (kein CGO), modernc/sqlite entfernt
- Hypertable 'metrics' fuer Time-Series Daten
- Automatische Metrik-Extraktion bei jedem Heartbeat:
  CPU, RAM, Uptime, Disk, Network-Traffic, Gateway RTT/Loss
- Retention Policy: 90 Tage, Compression nach 7 Tagen
- Neue API-Endpoints: GET /metrics (raw) + GET /metrics/summary (aggregiert)
- time_bucket() Aggregation (5min, 1h, etc.)
- config.yaml: database-Block statt db_path
- docs/POSTGRES_SETUP.md: Installationsanleitung
- README aktualisiert
2026-02-28 12:48:14 +01:00

23 KiB

OPNsense RMM System

Remote Monitoring & Management fuer OPNsense Firewalls. Go-basierter Agent + Backend mit WebSocket-Kommunikation und Session-basierten TCP-Tunneln.

Architektur

┌────────────────┐   HTTPS/WSS    ┌────────────────┐   TCP Proxy     ┌────────────┐
│  OPNsense FW   │◄──────────────►│  RMM Backend   │◄───────────────│  Browser/  │
│  (FreeBSD)     │  :8443         │  (Linux)       │  :10000-20000  │  SSH/etc.  │
│                │                │                │                └────────────┘
│  rmm-agent     │  Heartbeat     │  REST API      │
│  - Collectors  │  WebSocket     │  WebSocket Hub │
│  - WS Client   │  Binary Msgs   │  Tunnel Mgr    │
│  - Tunnel Mgr  │                │  SQLite DB     │
└────────────────┘                └────────────────┘

Tunnel-Flow

Client ──► Backend:ProxyPort ──► WebSocket (Binary) ──► Agent ──► Zieldienst
           (TCP-Listener)        (Session-basiert)       (TCP)    (SSH/HTTPS/etc)
  • Jeder Tunnel oeffnet einen dynamischen Proxy-Port (10000-20000) auf dem Backend
  • Jede TCP-Verbindung am Proxy bekommt eine eigene Session
  • Der Agent oeffnet pro Session eine separate Ziel-Verbindung (Lazy Connect)
  • Mehrere gleichzeitige Verbindungen pro Tunnel moeglich
  • Tunnel bleiben offen wenn einzelne Sessions beendet werden

Agent-Faehigkeiten (Status: Implementiert)

Datensammlung (automatisch bei jedem Heartbeat, alle 60s)

Collector Daten Quelle
Hardware Hersteller, Modell, Seriennummer, BIOS kenv, sysctl
CPU Modell, Cores, Threads, Frequenz, Auslastung sysctl
Memory Total, Used, Free sysctl
Disks ZFS Datasets, Belegung, Mountpoints zfs list
Network Interfaces, IPs, Status, MAC, Statistiken ifconfig
Services Laufende Dienste, Status service -e, configctl
WireGuard Tunnel, Peers, Transfer, Handshake wg show
DHCP Aktive Leases (KEA/ISC/dnsmasq) Lease-Dateien, KEA JSON
Routing Routing-Tabelle netstat -rn
Gateways Gateway-Status, RTT, Loss configctl interface gateways status
Zertifikate Alle Certs + CAs, Ablaufdatum, Aussteller config.xml + PEM-Parsing
Plugins Installierte OPNsense-Plugins pkg info
Updates Pending Core + Package Updates opnsense-update -c, pkg upgrade -n

Remote-Commands (via WebSocket, on-demand)

Command API-Endpoint Beschreibung
exec POST /agents/{id}/exec Beliebigen Shell-Befehl ausfuehren
backup POST /agents/{id}/backup Config-Backup (/conf/config.xml) erstellen
update_check POST /agents/{id}/update-check Verfuegbare Updates pruefen
update POST /agents/{id}/update Normales Update (Core + Packages, opt. Reboot)
major_update POST /agents/{id}/major-update Major-Upgrade (2-Phasen: Base/Kernel → Reboot → Packages)
reboot POST /agents/{id}/reboot Reboot mit konfigurierbarer Verzoegerung
wg_add_peer POST /agents/{id}/wireguard/peers WireGuard-Peer anlegen (Keypair + Config)
wg_list_peers GET /agents/{id}/wireguard/peers Alle Peers einer WG-Instanz auflisten
wg_delete_peer DELETE /agents/{id}/wireguard/peers/{uuid} WireGuard-Peer loeschen
tunnel_connect POST /agents/{id}/tunnel TCP-Tunnel zu lokalem Dienst oeffnen
tunnel_disconnect DELETE /agents/{id}/tunnel/{tid} Tunnel schliessen

Registrierte Agents

Agent-ID Name IP Rolle
6beb8dfd... OPN-PROD.intra.weidenhaupt.net 192.168.85.1 Produktion (READ-ONLY)
e92e87a6... OPN-REP.intra.weidenhaupt.net 192.168.85.33 Test/Replikation
1697d28e... OPN-TEST-UPDATE 192.168.85.19 Update-Tests

Komponenten

Agent (FreeBSD/OPNsense)

  • Collectors: Hardware, CPU, Memory, Disk, Network, Services, WireGuard, DHCP (KEA/ISC/dnsmasq), Routing, Gateways, Zertifikate, Plugins, Updates
  • WebSocket Client: Persistente Verbindung zum Backend, automatisches Reconnect mit Backoff
  • Command Handler: Remote-Befehlsausfuehrung, Tunnel-Connect/Disconnect
  • Tunnel Manager: Session-basierte TCP-Verbindungen zu lokalen Diensten

Backend (Linux)

  • REST API: Agent-Registrierung, Heartbeat, Systemdaten, Tunnel-Management
  • WebSocket Hub: Verwaltet Agent-Verbindungen, routet Commands und Binary-Messages
  • Tunnel Manager: Proxy-Listener, Session-Tracking, Ready-Handshake
  • SQLite DB: Persistente Agent- und Systemdaten

Build

make all       # Backend (linux/amd64) + Agent (freebsd/amd64)
make backend   # Nur Backend
make agent     # Nur Agent

Binaries in build/. Benoetigt Go 1.22+.

Konfiguration

Backend (config.yaml)

listen_addr: ":8443"
tls_cert: "certs/server.crt"   # Wird automatisch generiert
tls_key: "certs/server.key"
db_path: "rmm.db"
api_keys:
  - "dein-api-key-hier"

Agent (config.yaml)

backend_url: "https://backend-ip:8443"
api_key: "dein-api-key-hier"
interval_seconds: 60
agent_name: "opnsense-fw01"
insecure: true                  # Self-signed Certs akzeptieren

Deployment

Backend

# Build + Copy
make backend
scp build/rmm-backend user@backend:/pfad/rmm-backend

# Starten (als normaler User, kein root noetig)
cd /pfad && nohup ./rmm-backend config.yaml > rmm-backend.log 2>&1 &

Agent (OPNsense/FreeBSD)

# Build + Copy
make agent
scp build/rmm-agent root@opnsense:/usr/local/rmm/rmm-agent

# Starten via FreeBSD daemon
daemon -f -p /var/run/rmm-agent.pid -o /usr/local/rmm/rmm-agent.log \
  /usr/local/rmm/rmm-agent --config /usr/local/rmm/config.yaml --insecure

Wichtig: Agent-ID wird persistent in /usr/local/rmm/agent_id gespeichert.

API

Agent-Management

Methode Endpoint Beschreibung
POST /api/v1/agent/register Agent registrieren (mit optionaler agent_id)
POST /api/v1/agent/heartbeat Systemdaten senden
GET /api/v1/agents Alle Agents auflisten
GET /api/v1/agents/{id} Agent + Systemdaten abrufen
GET /api/v1/agents/{id}/system Nur Systemdaten
DELETE /api/v1/agents/{id} Agent loeschen

WebSocket

Methode Endpoint Beschreibung
GET /api/v1/agent/ws?agent_id=X&api_key=X WebSocket-Verbindung (Agent)
GET /api/v1/hub/status Hub-Status (connected agents, aktive Tunnel)

Updates & Reboot

Methode Endpoint Beschreibung
POST /api/v1/agents/{id}/update-check Verfuegbare Updates pruefen
POST /api/v1/agents/{id}/update Normales Update (Core + Packages)
POST /api/v1/agents/{id}/major-update Major-Upgrade auf Zielversion
POST /api/v1/agents/{id}/reboot Reboot ausfuehren

Metriken (TimescaleDB)

Methode Endpoint Beschreibung
GET /api/v1/agents/{id}/metrics Rohe Metriken abfragen (?metric=X&from=&to=&limit=N)
GET /api/v1/agents/{id}/metrics/summary Aggregierte Metriken (?metric=X&bucket=5+minutes&from=&to=)

Metriken werden automatisch bei jedem Heartbeat geschrieben (alle 60s): cpu_usage, memory_used_percent, memory_used_bytes, memory_total_bytes, uptime_seconds, disk_used_percent, disk_used_bytes, interface_rx_bytes, interface_tx_bytes, gateway_rtt_ms, gateway_loss_percent

Retention: 90 Tage (Raw), Compression nach 7 Tagen.

Config-Backup

Methode Endpoint Beschreibung
POST /api/v1/agents/{id}/backup Backup jetzt ausloesen (via WebSocket)
GET /api/v1/agents/{id}/backups Alle Backups auflisten (?limit=N)
GET /api/v1/agents/{id}/backups/{id|latest} Backup herunterladen (?format=xml fuer Raw-XML)
DELETE /api/v1/agents/{id}/backups/{id} Einzelnes Backup loeschen
GET /api/v1/agents/{id}/backups/diff?a={id}&b={id} Zeilenweises Diff zwischen zwei Backups

Backups werden dedupliziert: gleicher SHA256-Hash = kein neuer Eintrag. Config-XML wird Base64-kodiert vom Agent zum Backend uebertragen und als Klartext in SQLite gespeichert.

Tunnel-Management

Methode Endpoint Beschreibung
POST /api/v1/agents/{id}/tunnel Tunnel oeffnen
GET /api/v1/agents/{id}/tunnels Aktive Tunnel auflisten
DELETE /api/v1/agents/{id}/tunnel/{tid} Tunnel schliessen
POST /api/v1/agents/{id}/exec Remote-Command ausfuehren

Tunnel-Beispiele

# SSH-Tunnel zur OPNsense
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \
  -d '{"target_host":"127.0.0.1","target_port":22}'

# Response: {"tunnel_id":"xxx","proxy_port":10000,...}
# Verbinden:
ssh -p 10000 root@192.168.85.13

# WebGUI-Tunnel (OPNsense auf Port 4444)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel \
  -d '{"target_host":"127.0.0.1","target_port":4444}'

# Response: {"tunnel_id":"xxx","proxy_port":10001,...}
# Im Browser: https://192.168.85.13:10001/

# Aktive Tunnel auflisten
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnels

# Tunnel schliessen
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/tunnel/TUNNEL_ID

Zugangsdaten

Backend:   https://192.168.85.13:8443
API-Key:   01532e5a7c9e70bf2757df77a2f5b9b9

Agent-IDs:
  6beb8dfd38ecf03eab6c0f21b4ac7bee  OPN-PROD.intra.weidenhaupt.net  (192.168.85.1, READ-ONLY)
  e92e87a684b20db15d8d2344583c5887  OPN-REP.intra.weidenhaupt.net   (192.168.85.33)
  1697d28e57bc126534afc282b5de8ee0  OPN-TEST-UPDATE                 (192.168.85.19)

Agent-Beispiele

# Alle Agents auflisten (ID, Name, IP, Version, letzter Heartbeat)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents

# Einzelner Agent mit Systemdaten
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887

# Nur Systemdaten (Hardware, CPU, RAM, Disks, Services, etc.)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/system

# Agent loeschen
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887

# Hub-Status (verbundene Agents, aktive Tunnel)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/hub/status

# Remote-Command ausfuehren
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/exec \
  -d '{"command":"uptime","timeout":30}'

WireGuard-Peer Management

Methode Endpoint Beschreibung
POST /api/v1/agents/{id}/wireguard/peers Neuen Peer anlegen
GET /api/v1/agents/{id}/wireguard/peers Alle Peers auflisten (?server_name=X)
DELETE /api/v1/agents/{id}/wireguard/peers/{uuid} Peer loeschen

Peer anlegen — Parameter:

Parameter Pflicht Default Beschreibung
name Ja Peer-Name (z.B. "VPN_MUELLER")
allowed_ips Nein 0.0.0.0/0 AllowedIPs fuer Client-Config
dns Nein DNS-Server fuer Client-Config
server_name Nein ALWAYSON_VPN Name der WG-Server-Instanz
endpoint Nein WAN-IP:Port Oeffentlicher Endpoint (Auto-Detect ueber Default-Route)

Ablauf beim Anlegen:

  1. Keypair wird auf der Firewall generiert (wg genkey/wg pubkey)
  2. Naechste freie IP aus dem Tunnel-Subnetz wird automatisch vergeben
  3. Peer wird in config.xml eingetragen und dem Server zugewiesen
  4. configctl wireguard configure laedt die Aenderung
  5. Response enthaelt die komplette Client-Config (ready for import)

Beispiele:

# Peer anlegen (erster Peer bekommt .2, zweiter .3, etc.)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \
  -d '{"name":"VPN_MUELLER","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}'

# Response:
# {
#   "status": "ok",
#   "data": {
#     "peer_uuid": "abc123...",
#     "name": "VPN_MUELLER",
#     "client_ip": "10.33.144.2",
#     "endpoint": "79.238.149.26:8080",
#     "client_config": "[Interface]\nPrivateKey = ...\nAddress = 10.33.144.2/32\n..."
#   }
# }

# Zweiten Peer anlegen (bekommt automatisch .3)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \
  -d '{"name":"VPN_SCHMIDT","allowed_ips":"0.0.0.0/0","dns":"10.172.100.210"}'

# Peer mit eigenem Endpoint (z.B. DynDNS)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers \
  -d '{"name":"VPN_EXTERN","allowed_ips":"0.0.0.0/0","endpoint":"vpn.kunde.de:8080"}'

# Alle Peers auflisten
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers

# Peers einer bestimmten Instanz auflisten
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers?server_name=ALWAYSON_VPN"

# Peer loeschen (UUID aus der List-Response)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X DELETE \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/wireguard/peers/89c10e2d-148e-11f1-a7af-7c5a1c6c7b73

Metriken-Beispiele

# CPU-Auslastung der letzten 24h
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=cpu_usage"

# RAM-Nutzung mit Zeitraum
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?metric=memory_used_percent&from=2026-02-28T00:00:00Z&to=2026-02-28T23:59:59Z"

# 5-Minuten-Durchschnitte der CPU
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=cpu_usage&bucket=5+minutes"

# Stuendliche RAM-Zusammenfassung
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics/summary?metric=memory_used_percent&bucket=1+hour"

# Alle Metriken eines Agents (alle Typen, letzte 100)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/metrics?limit=100"

Backup-Beispiele

# Backup ausloesen (Produktion .1)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backup

# Backup ausloesen (Test .33)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backup

# Alle Backups auflisten
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  https://192.168.85.13:8443/api/v1/agents/6beb8dfd38ecf03eab6c0f21b4ac7bee/backups

# Neuestes Backup als XML herunterladen
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/latest?format=xml" \
  -o config-backup.xml

# Diff zwischen Backup 1 und 3
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" \
  "https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/backups/diff?a=1&b=3"

Update-Beispiele

# Verfuegbare Updates pruefen
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update-check

# Normales Update (ohne Reboot)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update

# Normales Update mit Reboot
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/update \
  -d '{"reboot":true}'

# Major-Upgrade auf Version 26.7
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/major-update \
  -d '{"version":"26.7","reboot":true}'

# Reboot (5s Verzoegerung default)
curl -sk -H "X-API-Key: 01532e5a7c9e70bf2757df77a2f5b9b9" -X POST \
  https://192.168.85.13:8443/api/v1/agents/e92e87a684b20db15d8d2344583c5887/reboot

Update-Ablauf

Normales Update (Patches innerhalb der gleichen Version):

  1. opnsense-update — Core-Update herunterladen
  2. pkg upgrade -y — Paket-Updates installieren
  3. Nachpruefung: opnsense-update -c — Exit 1 = Reboot noetig

Response enthaelt reboot_required: true/false fuer das Frontend.

Major-Upgrade (z.B. 25.7 → 26.1):

  1. opnsense-update -r <version> -bkp — Repository wechseln + Base + Kernel + Packages herunterladen
  2. pkg-static update -f — Repository-Katalog forciert aktualisieren
  3. pkg-static upgrade -y — Alle Pakete auf neue Version installieren
  4. Reboot erforderlich (immer bei Major-Upgrade)

Major-Upgrades setzen reboot_required: true und reboot ist standardmaessig aktiviert.

WebSocket Commands (Backend → Agent)

// Remote-Befehl ausfuehren
{"type":"command","id":"cmd1","command":"exec","params":{"command":"uptime","timeout":30}}

// Update-Check (liefert core_update_available, pending_packages, reboot_required)
{"type":"command","id":"cmd2","command":"update_check"}

// Normales Update (reboot optional)
{"type":"command","id":"cmd3","command":"update","params":{"reboot":false}}

// Major-Update (reboot default true)
{"type":"command","id":"cmd4","command":"major_update","params":{"version":"26.1","reboot":true}}

// Reboot
{"type":"command","id":"cmd5","command":"reboot","params":{"delay":5}}

// Config-Backup (liest /conf/config.xml, liefert Base64 + SHA256 Hash)
{"type":"command","id":"cmd8","command":"backup","params":{}}

// Tunnel-Session oeffnen (automatisch vom Backend gesendet)
{"type":"command","id":"cmd6","command":"tunnel_connect","params":{"session_id":"xxx","tunnel_id":"xxx","target_host":"127.0.0.1","target_port":22}}

// Tunnel-Session schliessen
{"type":"command","id":"cmd7","command":"tunnel_disconnect","params":{"session_id":"xxx"}}

Binary WebSocket Messages (Tunnel-Daten)

Format: [session_id_length:1][session_id][tcp_payload]

Tunnel-Daten werden als Binary WebSocket Messages uebertragen (kein Base64-Overhead).

Dateistruktur

rmm/
├── Makefile
├── README.md
├── agent/
│   ├── main.go                  # Entry, Registration, Heartbeat-Loop, WS-Start
│   ├── config/
│   │   └── config.go            # YAML Config Loader
│   ├── client/
│   │   └── client.go            # HTTP Client (Register, Heartbeat)
│   ├── collector/
│   │   ├── hardware.go          # Hersteller, Modell, BIOS
│   │   ├── cpu.go               # CPU-Modell, Cores, Usage
│   │   ├── memory.go            # RAM total/used/free
│   │   ├── disk.go              # ZFS Datasets, Belegung
│   │   ├── network.go           # Interfaces, IPs, Status
│   │   ├── services.go          # Laufende Dienste
│   │   ├── wireguard.go         # WG-Tunnel, Peers, Transfer
│   │   ├── dhcp.go              # KEA/ISC/dnsmasq Leases
│   │   ├── opnsense.go          # OPN-Version, FreeBSD, Hostname, Uptime
│   │   ├── routing.go           # Routing-Tabelle (netstat -rn)
│   │   ├── gateways.go          # Gateway-Status (configctl)
│   │   ├── certificates.go      # Zertifikate + CAs (config.xml + PEM)
│   │   ├── plugins.go           # Installierte Plugins (pkg info)
│   │   └── updates.go           # Pending Updates (core + packages)
│   └── ws/
│       ├── client.go            # WebSocket Client, Reconnect, Ping/Pong
│       ├── handler.go           # Command Handler (exec, backup, tunnel_connect/disconnect)
│       ├── wireguard.go        # WireGuard Peer Management (add/delete/list)
│       └── tunnel.go            # Session-basierter Tunnel Manager
├── backend/
│   ├── main.go                  # Entry, TLS, HTTP Server
│   ├── config/
│   │   └── config.go            # YAML Config Loader
│   ├── db/
│   │   └── postgres.go          # PostgreSQL + TimescaleDB (Agents, Backups, Metriken)
│   ├── models/
│   │   ├── agent.go             # Agent, Register/Heartbeat Structs
│   │   └── system.go            # SystemData, alle Collector-Structs
│   ├── api/
│   │   ├── handlers.go          # REST API Handler
│   │   ├── tunnel_proxy.go      # Tunnel + Exec + Update REST Endpoints
│   │   ├── backup.go            # Config-Backup Endpoints (trigger, list, download, diff)
│   │   ├── wireguard.go        # WireGuard Peer API Endpoints
│   │   ├── metrics.go           # Metriken-Abfrage Endpoints (raw + summary)
│   │   └── middleware.go        # API-Key Auth, Logging
│   └── ws/
│       ├── handler.go           # WebSocket Upgrade, Connection R/W Pumps
│       ├── hub.go               # Agent-Registry, Message Routing
│       └── tunnel.go            # Session-basierter Tunnel + Proxy Manager
└── build/                       # Kompilierte Binaries

Technische Details

  • PostgreSQL + TimescaleDB: Agent-Registry, Config-Backups, Time-Series Metriken (pgx Driver)
  • CGO-frei: Kein CGO noetig (pure-Go PostgreSQL Driver)
  • Cross-Compilation: Backend linux/amd64, Agent freebsd/amd64
  • TLS: Self-signed Zertifikate (automatisch generiert)
  • WebSocket: gorilla/websocket, Binary Messages fuer Tunnel-Daten
  • Persistente Agent-ID: Ueberlebt Agent- und Backend-Neustarts
  • FreeBSD-kompatibel: Volle Pfade (/usr/bin/netstat etc.), daemon statt nohup

Hinweise

  • Backend braucht kein root — laeuft als normaler User auf Port 8443
  • Agent braucht root auf OPNsense (fuer Hardware-/Service-Daten)
  • OPNsense WebGUI typischerweise auf Port 4444 (nicht 443)
  • FreeBSD csh hat kein $() — Agent verwendet /bin/sh -c fuer Commands
  • Beim Backend-Deploy: alte Prozesse killen bevor neuer startet (sonst "bind: address already in use")

Lizenz

Intern.