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

A UPS that shuts the server down cleanly: NUT: ten minutes of battery, used properly.

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

TaskWhat
Buyany APC, CyberPower, Eaton with a USB port; 500–1000 VA covers a mini PC plus router
Installsudo apt install nut -y
Config/etc/nut/ups.conf, upsd.users, upsmon.conf, nut.conf
Statusupsc myups
Test shutdown logicsudo upsmon -c fsd (really shuts down!)
Other machinesMONITOR 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.

Call us