Howdy!
I’ve got a walking pad under my desk. Great for the step count, terrible for my homelab’s blood pressure. Every time I turn the thing on, the motor throws a tantrum through the mains and my monitor flickers, my USB peripherals disconnect and reconnect like they’re having second thoughts about our relationship, and my audio interface starts doing its best impression of a 2003 dial-up handshake. I dug out some knowledge from the good old days, back when the risk wasn’t dropping a database in production but getting lightly shocked, and the diagnosis was easy: just annoying electrical noise, dirty current bleeding off a motor. The cure? Decoupling. Funny enough, that’s also the cure for half my problems at work these days.
What I needed was something to decouple my setup from that mess: give the electronics some breathing room, and ideally handle a graceful shutdown if the noise ever escalated into an actual outage. And decoupling electronics, it turns out, isn’t that different from decoupling a stack: a database tucked away in its own subnet, a backend running in a container somewhere far away, a frontend sitting behind CloudFront. Same reasoning, different tools. So I picked up a small UPS with a proper pure sine wave output. It solved the flickering overnight. No more haunted USB ports. Just quiet, boring, stable power, which is exactly the kind of boring I want from my infrastructure.
That solved one problem and immediately created another: something needed to watch the UPS. And sitting on a shelf, three feet away, gathering dust since I last used it for some now-forgotten project, was a Raspberry Pi. It had been unemployed for the better part of a year. Every crew needs a reluctant leader with a complicated past.
The Stack
I put together a small Docker stack for it:
version: "3.8"
services:
nut:
image: instantlinux/nut-upsd
container_name: nut
restart: always
devices:
- "/dev/bus/usb:/dev/bus/usb"
ports:
- "${NUT_PORT}:3493"
volumes:
- /srv/probe-data/nut:/etc/nut
environment:
- TZ=${TZ}
peanut:
image: brandawg93/peanut:latest
container_name: PeaNUT
restart: unless-stopped
ports:
- 8080:8080
environment:
- WEB_PORT=8080
depends_on:
- nut
wolnut:
image: hardwarehaven/wolnut:latest
container_name: wolnut
network_mode: host
restart: unless-stopped
volumes:
- /srv/probe-data/wolnut:/config
depends_on:
- nut
Three services. Sounds like a lot for “check if the power is on,” but this is my ragtag crew of misfits, each one with exactly one skill and a questionable name, assembled to protect the uptime. Nobody asked them to. They’re doing it anyway.
Step 1: NUT, the Butler Who Actually Reads the Mail
Network UPS Tools is the part doing the real work. It talks to the UPS over USB and keeps notes: charge level, runtime remaining, input voltage, and whether the outside world has decided to take the power away for a while. Without it, your homelab has no idea a UPS is even in the room. It’s just a battery-shaped ornament. With it, someone is finally reading the mail before the house catches fire.
Step 2: PeaNUT, Because Nobody Wants to Read Logs Before Coffee
NUT on its own talks in plain text, which is fine if you enjoy squinting at a terminal at 7am. PeaNUT gives it a small web dashboard instead: charge, load, voltage, all the numbers a UPS produces, laid out somewhere you can actually glance at. Point a browser at http://<pi-ip>:8080 and there it is. Same butler, now with a phone instead of a clipboard.
Step 3: Wolnut, for When the Lights Come Back On
This is the part I actually built the stack for. A UPS that only logs outages is half a solution. Wolnut watches for the power coming back and sends a Wake-on-LAN packet to bring the rest of the cluster back up on its own. Power drops, NUT notices, the affected machines shut down cleanly instead of getting yanked off mid-write. Power returns, Wolnut taps them on the shoulder, and everything’s back before I’ve noticed anything happened.
One catch: your target machines need Wake-on-LAN actually enabled, usually buried somewhere in BIOS or the NIC driver settings. Skip that step and Wolnut just sits there quietly, waiting to wake up a machine that was never listening.
There’s a second wrinkle, and this one’s on me: the Pi running Wolnut can’t itself be woken over LAN. So if the power ever drops long enough to take the Pi down with it, nothing wakes the thing that’s supposed to wake everything else. A tidy little deadlock, currently unresolved, filed under problems for future Marco to deal with.
Step 4: All of It Is Free
Worth pausing on this. NUT has been maintained since the late nineties, quietly outliving several UPS software companies that charged you a license fee to look at a battery percentage. PeaNUT and Wolnut are both small projects built by people who wanted a nicer UI or a specific feature and then shared it instead of keeping it to themselves. None of it cost me anything but an afternoon and a docker-compose file.
Wrapping Up
So that’s the setup: a Pi that spent a year unemployed is now leading a small crew of oddly named containers, watching my power supply, telling me about it in a dashboard I can read half asleep, and waking my cluster back up when the lights come back on. They will not save the galaxy. The uptime, though, is in good hands.
Happy building ⚒