LinuxmonitoringTested on real hardware

NUT: One-UPS Network Shutdown (Server + Client)

Wire one UPS to shut down a whole homelab: NUT server on the machine with the USB cable, NUT clients on every other machine, safe automatic shutdown on low battery.

Distrosdebian, ubuntu, proxmox
Shellbash
Updated
Script
bash
# ═══════════════════════════════════════════════════════════════
# NUT — one UPS, safe shutdown of every machine on it.
# PART A: run on the machine wired to the UPS by USB (the primary).
# PART B: run on each OTHER machine on that same UPS (a secondary).
# Change the placeholders first — see the ## Notes section below.
# ═══════════════════════════════════════════════════════════════

# ─── PART A — THE PRIMARY (the box with the UPS USB cable) ──────
apt update && apt install -y nut-server nut-client

# 1. Find the UPS — prints a ready ups.conf block (usually usbhid-ups)
nut-scanner -U

# 2. This machine owns the UPS and serves it to the network
echo "MODE=netserver" > /etc/nut/nut.conf

# 3. Define the UPS (adjust driver/port if nut-scanner said otherwise)
cat > /etc/nut/ups.conf <<'EOF'
[myups]
    driver = usbhid-ups
    port = auto
    desc = "Homelab UPS"
EOF

# 4. Listen on localhost + this box's LAN IP.
#    Do NOT combine 0.0.0.0 with 127.0.0.1 (overlap = localhost only).
cat > /etc/nut/upsd.conf <<'EOF'
LISTEN 127.0.0.1 3493
LISTEN 10.0.0.10 3493
EOF

# 5. The account every upsmon (this one + the secondaries) logs in with
cat > /etc/nut/upsd.users <<'EOF'
[monuser]
    password = CHANGE_ME
    upsmon primary
EOF

# 6. Shutdown policy for the primary
cat > /etc/nut/upsmon.conf <<'EOF'
MONITOR myups@localhost 1 monuser CHANGE_ME primary
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
POWERDOWNFLAG /run/nut/killpower
EOF

# 7. Lock down the files (they hold passwords), then start + verify
chown root:nut /etc/nut/*.conf /etc/nut/upsd.users
chmod 640 /etc/nut/*.conf /etc/nut/upsd.users
systemctl restart nut-server nut-monitor
upsc myups ups.status        # expect: OL

# ─── PART B — EACH SECONDARY (other machines on the same UPS) ───
apt update && apt install -y nut-client
echo "MODE=netclient" > /etc/nut/nut.conf

cat > /etc/nut/upsmon.conf <<'EOF'
MONITOR myups@10.0.0.10 1 monuser CHANGE_ME secondary
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
EOF
chown root:nut /etc/nut/upsmon.conf
chmod 640 /etc/nut/upsmon.conf
systemctl restart nut-monitor
upsc myups@10.0.0.10 ups.status   # expect: OL (read over the network)

What this does

Sets up Network UPS Tools so a single UPS — wired by USB to one “primary” machine — cleanly shuts down that machine and every other “secondary” machine on the same UPS when the battery runs low. Part A configures the primary (the UPS driver, the upsd network server, and the upsmon monitor). Part B configures each secondary, which only watches the primary over the network. The full walkthrough with the shutdown sequence explained is in One UPS, Whole Homelab: Safe Auto-Shutdown with NUT.

Prerequisites

  • A UPS with a data port (USB on most consumer units), plugged into the primary machine.
  • Root on each machine; Debian, Ubuntu, or a Proxmox host.
  • The primary’s static LAN IP, and a list of the other machines running on the same UPS.

Notes

  • Make these values your own before you run this. myups — any name you like for the UPS. 10.0.0.10 — the primary’s real LAN IP (it appears in upsd.conf and in every secondary’s MONITOR line). monuser / CHANGE_ME — the monitor account and a strong password you keep in your own secret store, never pasted into a note. The driver/port in ups.conf — change them only if nut-scanner reported something other than usbhid-ups. If a value looks specific to one machine, it’s a placeholder to change, not a literal to copy.
  • Verified end to end on Debian 13 / NUT 2.8.1 — driver → upsdupsc, network login with authentication, and the on-battery → low-battery → shutdown sequence (secondaries first, primary last, POWERDOWNFLAG dropped) — using NUT’s dummy-ups simulation driver in place of a physical UPS. Substitute your real UPS at the ups.conf driver line.
  • upsd listens on localhost only until you add the LISTEN line — the number-one reason a secondary reports Connection refused.
  • Only one UPS daemon per machine. If apcupsd is installed it will fight NUT for the USB device — disable one.
  • On Debian the monitor service is nut-monitor (nut-client is an alias for it).
  • Test the real trigger with upsmon -c fsd — it runs the actual forced-shutdown path and powers the machine off, so only do it on a box you can afford to reboot. Watch journalctl -u nut-monitor -f while it runs.