How to Set Up a UPS on a Linux Server with NUT (Shut Down Cleanly in a Power Cut)

A sudden power cut mid-write is how databases corrupt, ZFS pools go degraded and SD cards die. A small UPS — a battery box the server plugs into — gives you ten or twenty minutes, and NUT (Network UPS Tools) uses that time properly: it watches the battery over USB, sends a notification when the mains fails, and shuts the server down cleanly before the battery is empty. Other machines on the network can watch the same UPS and do the same.
Quick reference
| Task | What |
|---|---|
| Buy | any APC, CyberPower, Eaton with a USB port; 500–1000 VA covers a mini PC plus router |
| Install | sudo apt install nut -y |
| Config | /etc/nut/ups.conf, upsd.users, upsmon.conf, nut.conf |
| Status | upsc myups |
| Test shutdown logic | sudo upsmon -c fsd (really shuts down!) |
| Other machines | MONITOR myups@192.168.1.50 1 monuser pass secondary |
1. Plug in and detect
Connect the UPS's USB cable to the server. Then:
sudo apt install nut -y
sudo nut-scanner -U
It prints a block like [nutdev1] driver = "usbhid-ups" port = "auto". That's your UPS. Almost every consumer UPS uses usbhid-ups.
2. Configure
sudo nano /etc/nut/nut.conf
MODE=standalone
(netserver if other machines will watch it — see step 6.)
sudo nano /etc/nut/ups.conf
[myups]
driver = usbhid-ups
port = auto
desc = "Server UPS"
sudo nano /etc/nut/upsd.users
[monuser]
password = a-password
upsmon primary
sudo nano /etc/nut/upsmon.conf
Find and set:
MONITOR myups@localhost 1 monuser a-password primary
SHUTDOWNCMD "/sbin/shutdown -h +0"
NOTIFYCMD /usr/sbin/upssched
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
sudo systemctl restart nut-server nut-monitor
sudo systemctl enable nut-server nut-monitor
3. Read it
upsc myups
A page of values: battery.charge: 100, battery.runtime: 1380 (seconds), ups.load: 18 (percent), ups.status: OL (online; OB on battery, LB low battery). upsc myups ups.status for just one.
4. What happens in a power cut
Mains fails → status goes OB → NUT logs it (and runs your notify script) → battery drains → UPS reports LB → upsmon runs SHUTDOWNCMD → the server shuts down cleanly → when the battery is nearly dead, NUT tells the UPS to cut power, so that when the mains returns the UPS powers back up and the server boots (set AC Power Recovery: On in the BIOS).
You don't wait for LB by choice; most UPSes signal it at about 20% charge. To shut down earlier, set override.battery.charge.low = 50 in ups.conf under the UPS block.
5. Get told
NUT calls upssched for events. Simplest: a script that pings ntfy (tutorial 93):
sudo nano /etc/nut/upssched.conf
CMDSCRIPT /etc/nut/notify.sh
AT ONBATT * EXECUTE onbatt
AT ONLINE * EXECUTE online
AT LOWBATT * EXECUTE lowbatt
sudo nano /etc/nut/notify.sh
#!/bin/bash
curl -s -H "Authorization: Bearer $NTFY_TOKEN" -H "Priority: high" -d "UPS: $1" https://ntfy.example.com/server
chmod +x. Pull the UPS's mains plug for ten seconds: phone buzzes "UPS: onbatt", then "UPS: online". That's the whole chain tested without a shutdown.
6. Other machines on the same UPS
A NAS, a Pi and the router can share one UPS. On the server, MODE=netserver and in upsd.conf add LISTEN 0.0.0.0 3493, then sudo ufw allow from 192.168.1.0/24 to any port 3493. On each other Linux machine, install nut-client and in its upsmon.conf:
MONITOR myups@192.168.1.50 1 monuser a-password secondary
They shut down on the same low-battery signal. Synology, TrueNAS and Home Assistant can all point at a NUT server too (Home Assistant shows charge and runtime as sensors).
Troubleshooting
upsc says "Data stale" or driver won't start. USB permission or the wrong driver. sudo upsdrvctl start prints why; lsusb should list the UPS.
Server doesn't power back on after the cut. BIOS AC Power Recovery is off, or the UPS didn't cut power at the end (some models need offdelay in ups.conf).
Shutdown happens too late and the UPS dies first. Raise override.battery.charge.low, or the battery is old — battery.runtime under a few minutes at full charge means replace it.
Notifications don't fire. NOTIFYFLAG ... EXEC missing, or the script isn't executable; journalctl -u nut-monitor.
Wrapping up
A USB UPS, four short config files, upsc to prove it reads. Pull the plug once to see the notification, trust the shutdown to NUT, and the next real power cut is a clean reboot instead of a corrupted disk.
