Zum Inhalt

NUT (USV-Monitoring)

Ueberwacht die CyberPower OR650ERM1U USV und triggert eine geordnete Abschaltkette fuer alle Rack-Geraete, wenn die Batterie zur Neige geht. NUT Project

Zugriff

Port 3493 (nur intern auf Host)
Netzwerk Host-Netzwerk (via Port-Mapping)
Traefik Nein (interner Dienst)

Container

Container Image Funktion
nut-upsd instantlinux/nut-upsd:latest upsd-Daemon, spricht via usbhid-ups mit der USV

Der upsmon- und upssched-Client laeuft als System-Service auf dem NUC-Host (nicht im Container), damit Shutdowns das Host-System direkt erreichen.

Architektur

  CyberPower OR650ERM1U (USB)
           │ usbhid-ups (VendorID 0764)
  ┌────────▼─────────┐
  │ nut-upsd (Docker)│  :3493
  └────────┬─────────┘
           │ MONITOR serverups@localhost
  ┌────────▼─────────┐
  │ upsmon  (Host)   │──── NOTIFYCMD ───► upssched (Host)
  └──────────────────┘                        │
                                              │ AT ONBATT / LOWBATT
                                        shutdown-chain.sh
                ┌─────────────────────────────┼─────────────────────────┐
                ▼                             ▼                         ▼
          UNAS Pro (NAS)              UDM Pro (Router)           NUC (localhost)
          ssh unas-pro                ssh udm-pro                shutdown -h now

Konfigurationsbesonderheiten

  • Primary-Modus: Der NUC steuert die USV (MONITOR serverups@localhost:3493 1 upsmon <pw> primary)
  • Low-Battery-Schwelle: override.battery.runtime.low = 300 in ups.conf — LOWBATT feuert bei < 5 Minuten Restlaufzeit
  • Shutdown-Trigger: Primaer LOWBATT (Runtime < 5 min). Safety-Net: onbatt-shutdown-Timer nach 15 min ONBATT
  • Geordnete Abschaltkette (scripts/shutdown-chain.sh): UNAS Pro → UDM Pro → NUC in dieser Reihenfolge. NUC zuletzt, da lokal
  • SSH-Schluessel: /root/.ssh/config auf dem NUC enthaelt Hosts unas-pro und udm-pro mit Key-basiertem Login. Siehe SSH_SETUP.md im Repo
  • ntfy-Benachrichtigungen: Alle USV-Events (ONBATT, ONLINE, LOWBATT) gehen an homelab-critical Topic auf ntfy.homelab-external.robinwerner.net
  • USB-Durchreichung: Container benoetigt /dev/bus/usb und die VendorID 0764 (CyberPower)

Wichtige Pfade

Pfad Zweck
/etc/nut/upsmon.conf upsmon-Konfiguration (Host)
/etc/nut/upssched.conf Timer-Definitionen (Host)
/opt/rpi-docker-compose/nut/scripts/ shutdown-chain.sh, upssched-cmd.sh, ups-textfile-collector.sh
/var/log/nut/shutdown-chain.log Shutdown-Protokoll
/etc/killpower Power-Down-Flag (von upsmon gesetzt)
/mnt/ssd/container-data/monitoring-stack/textfile Ablage der .prom-Dateien

Pfad korrigiert (07.09.2026)

Hier stand bis heute /opt/containers/homeserver/nut/scripts/. Dieses Verzeichnis existiert auf dem NUC nicht — der Deploy-Checkout liegt unter /opt/rpi-docker-compose/. Am laufenden System geprüft.

USV-Metriken (Prometheus)

scripts/ups-textfile-collector.sh ruft alle 30 s upsc serverups@localhost:3493 auf und legt die Werte als .prom-Datei ab; der node-exporter liest das Verzeichnis read-only ein. Präfix nuc_ups_, analog zu aiserver_gpu_ auf dem AI-Server. Einrichtung: Runbook USV-Metriken.

Metrik Bedeutung
nuc_ups_scrape_success 0/1 — upsc scheitert genau dann, wenn der Treiber stale ist
nuc_ups_last_success_timestamp_seconds letzte erfolgreiche Lesung (bleibt im Fehlerfall stehen)
nuc_ups_on_line / _on_battery / _low_battery Flags aus ups.status
nuc_ups_replace_battery / _overload Flags aus ups.status
nuc_ups_battery_charge_percent / _runtime_seconds / _voltage_volts Batteriewerte
nuc_ups_input_voltage_volts / _output_voltage_volts Netz- und Ausgangsspannung
nuc_ups_load_percent / _realpower_watts Last (Ruhewert ~31 %, 113 W von 360 W)
nuc_ups_status_info{status="OL"} roher ups.status-String als Label

Der eigentliche Zweck ist nuc_ups_scrape_success: Bis dahin wusste Prometheus über die USV nur, ob der Container existiert. Ladung, Restlaufzeit und Netzstatus — die Werte, die im Ernstfall zählen — wurden gar nicht erfasst, und die Stale-Ereignisse des Treibers waren nur durch Zählen im Journal sichtbar. Ein Ereignis dauert rund 20 s, bei 30-s-Takt werden einzelne verpasst; die Rate über Stunden ist die Aussage, nicht das Einzelereignis.

Alarmregeln: siehe Alerting.

Timer-Logik (upssched.conf)

Event Aktion
ONBATT Sofortige ntfy-Benachrichtigung + Start Timer onbatt-shutdown (900s = 15 min)
ONLINE Timer canceln + ntfy "Power returned"
LOWBATT Sofortiger Shutdown ueber lowbatt-shutdown (Primaer-Trigger)

Setup (Kurz)

Das Host-Setup (upsmon/upssched auf dem NUC) wird vom Script scripts/setup-host.sh im Repo provisioniert. Details dort und in CLAUDE.md.

cd /opt/containers/homeserver/nut

# Container starten (spricht mit der USV via USB)
docker compose up -d

# Host-Seite einrichten (upsmon, upssched, systemd-Unit)
sudo ./scripts/setup-host.sh

Troubleshooting

  • upsc serverups@localhost zeigt den aktuellen USV-Status (Runtime, Battery, Load)
  • journalctl -u nut-monitor -f zeigt upsmon-Events live
  • Test-Shutdown: upsmon -c fsd triggert einen Forced Shutdown (Vorsicht: fuehrt den Chain aus!)
  • Logs: /var/log/nut/shutdown-chain.log protokolliert jede Kette mit Zeitstempeln