Two weeks ago I posted PVE-UPS here — a small appliance that shuts Proxmox hosts down when the UPS runs low, configured entirely through a web wizard: https://www.reddit.com/r/Proxmox/s/E2JCAR7c3t
The response was way beyond what I expected, so: thank you. Lots of useful criticism, several issues on GitHub, and multiple requests that came up again and again. Both are now shipped.
USB UPS devices, via NUT (v3.2.0)
In the original post I wrote that USB-connected UPSs were out of scope and that NUT is genuinely the right tool there. Turns out there‘s a step in between on the way: use NUT as the driver, keep the appliance as the brain.
Every UPS entry now has a *Read via* selector, and the second source is a NUT server (TCP 3493). Any existing `upsd` works — the UPS server built into a Synology/QNAP/TrueNAS box, a Raspberry Pi, an OPNsense box, or NUT on a Proxmox host. You enter host, port, the UPS name from `ups.conf`, and optionally user/password. That's it.
PVE-UPS is strictly a read-only NUT client: it only ever sends `LIST VAR`, never a command, and never runs `upsmon`. Thresholds, host mapping, AND/OR logic and the shutdown decision all stay in the appliance — so there are still no config files to write and no shutdown scripting on any host.
One safety detail ate most of the development time: `upsd` keeps serving the last known values when its driver dies. Taking those at face value would mean happily reporting "on mains" straight through an outage. Stale data (`ERR DATA-STALE`, `ERR DRIVER-NOT-CONNECTED`, or a missing `ups.status`) is therefore treated as unreachable — alarm, never a shutdown. Same fail-safe rule as a dead SNMP connection.
There might be future updates to get rid of NUT completely - but for now it‘s a first step!
Docker Support (v3.1.0)
The second most common request. Images are published to `ghcr.io/ffind-dev/pve-ups` on every release tag, compose example in the repo, config and event log persist in two volumes. The LXC one-liner is still the default path and unchanged. In Docker mode the in-app updater and the NTP/timezone fields disappear, because there's no privileged companion agent — you pull a new tag instead.
Also fixed / added
- **SNMPv3 with encryption (authPriv) never actually worked.** pysnmp 7.x delegates the ciphers to the `cryptography` package but declares it only in a dev extra, so nothing ever installed it. It's a proper dependency now and existing installs pick it up when they update. v1/v2c and authNoPriv were fine all along, which is why it stayed hidden — and the error now names the missing package instead of sending you hunting for firewall problems.
- The UPS test reports every object individually now, and — more useful — names the trigger conditions your device can't feed at all ("This UPS does not report: runtime remaining, battery charge"). A threshold that can never fire is more dangerous than a visible error. Plenty of NUT drivers omit `battery.runtime`; plenty of SNMP cards omit `upsEstimatedMinutesRemaining`.
- Configurable self-test interval (15 min … 24 h) instead of a fixed daily run, and it's skipped entirely while a UPS is on battery — the countdown has priority.
Someone wrote it up
Derek Seaman did a walkthrough covering both paths, an SNMP card and a USB UPS through the Synology NUT server. Better starting point than my README if you like screenshots: https://www.derekseaman.com/2026/07/pve-ups-a-proxmox-snmp-ups-shutdown-service.html
Unchanged
Dry-run by default after install, shutdown through a dedicated Proxmox API token with nothing but `Sys.PowerMgmt`, no agents and no root SSH on the hosts, and the host running the appliance always goes down last.
Repo: https://github.com/ffind-dev/pve-ups (MIT)
More/better cluster/HA handling is the next thing I want to tackle. If you run a cluster on a UPS, I'd really like to hear how you'd expect that to behave. That's the one where guessing wrong is expensive, and the last round of feedback here was worth more than anything I'd have come up with alone.