Intro:

We won’t call our infrastructure “safe” without running some 🔋’s! This is how I set a PowerWalker VI 1000 SCL UPS from BlueWalker for my homeserver running proxmox. Also I modified the default shutdown procedure and added gotify notifications. Enjoy this post 😊

Installation:

First we install the required package:

sudo apt install nut

ez.

Configuration:

UPS

Lots of configuration needs to be done. Lets go! First we define nut to run in standalone mode.

vim /etc/nut/nut.conf
MODE=standalone

Now we have to tell nut how it should use our UPS

vim /etc/nut/ups.conf
[powerwalker]
    driver = blazer_usb
    port = auto  
    desc = "PowerWalker UPS"

nah. We are not done yet with driver stuff..

root@pve:~# lsusb
Bus 001 Device 002: ID 0665:5161 Cypress Semiconductor USB to Serial

This gives us the Attributes for udev.rules. We need this stuff to set permissions right for our UPS. The importaint part is this: ID 0665:5161

ATTR{idVendor} ATTR{idProduct}
0665 5161

Now we can define our udev.rule:

vim /etc/udev/rules.d/90-nut-ups.rules
ACTION=="add", \
SUBSYSTEM=="usb", \
ATTR{idVendor}=="0665", ATTR{idProduct}=="5161", \
MODE="0660", GROUP="nut"

to apply the udev.rules do the following:

udevadm control --reload-rules
udevadm trigger

If your UPS wont pull the USB cable and/or reboot the server. You should get this response:

upsdrvctl start

Supported UPS detected with mustek protocol

UPSd our UPS-server

We only want access from our local maschine so:

vim /etc/nut/upsd.conf
ACL all 0.0.0.0/0
ACL localhost 127.0.0.1/32
ACCEPT localhost
REJECT all

add a user:

vim /etc/nut/upsd.users
[local_mon]
    password = SUPERPASSWORD
    allowfrom = localhost
    upsmon master
    instcmds = ALL

.. may adjust the password? Server is ready! ✌️

UPSMon our UPS-client

nothing to say here.

vim /etc/nut/upsmon.conf
MONITOR powerwalker@localhost 1 local_mon SUPERPASSWORD master
POWERDOWNFLAG /etc/killpower
SHUTDOWNCMD "/sbin/shutdown -h now"

Testing

systemctl start nut-server
systemctl start nut-client
systemctl status nut-server
systemctl status nut-client

both services should run without any problems. may restart or check the logs. 🤘

now you can do this:

root@pve:~# upsc powerwalker
Init SSL without certificate database
battery.charge: 100
battery.voltage: 27.50
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.type: ups
driver.name: blazer_usb
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.internal: 0.12
input.current.nominal: 5.0
input.frequency: 50.0
input.frequency.nominal: 50
input.voltage: 230.7
input.voltage.fault: 230.7
input.voltage.nominal: 230
output.voltage: 230.7
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.load: 0
ups.productid: 5161
ups.status: OL
ups.type: offline / line interactive
ups.vendorid: 0665

awsome! Here are all values from our UPS.

In my understanding these values are extracted directly from the ups-driver. You can add them in your ups.conf or override some if you want to disable the beeper:

upscmd -u local_mon -p SUPERSECRET powerwalker@localhost beeper.toggle

Run a battery test with (this turn’s your server off):

upscmd -u local_mon -p mypass powerwalker@localhost test.battery.start.quick

extra

I want my server to shutdown after 3min the power to USP turned off. So I modified /etc/nut/upscmon.conf and added:

NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYCMD "/etc/nut/notifycmd"

The NOTIFYCMD will trigger the /etc/nut/notifycmd script below:

root@pve:~# cat /etc/nut/notifycmd 
#!/bin/bash
#
# NUT NOTIFYCMD script

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin

trap "exit 0" SIGTERM

if [ "$NOTIFYTYPE" = "ONLINE" ]
then
        echo $0: power restored | wall
	/bin/curl "https://YOUR-GOTIFY-URL/message?token=YOURTOKEN" -F "title=UPS MESSAGE" -F "message=running back on power" -F "priority=5" &
        # Cause all instances of this script to exit.
        killall -s SIGTERM `basename $0`
fi

if [ "$NOTIFYTYPE" = "ONBATT" ]
then
        echo $0: 3 minutes till system powers down... | wall
	/bin/curl "https://YOUR-GOTIFY-URL/message?token=YOURTOKEN" -F "title=UPS MESSAGE" -F "message=shutdown server in 3min" -F "priority=5" &
        # Loop with one second interval to allow SIGTERM reception.
        let "n = 180"
        while [ $n -ne 0 ]
        do
                sleep 1
                let "n--"
        done
        echo $0: commencing shutdown | wall
	/bin/curl "https://YOUR-GOTIFY-URL/message?token=YOURTOKEN" -F "title=UPS MESSAGE" -F "message=shutting down" -F "priority=5" &
        upsmon -c fsd
fi


### back in shell
root@pve:~# chmod +x /etc/nut/notifycmd

Now restart everything with:

systemctl restart nut-driver
systemctl restart nut-server
systemctl restart nut-monitor
systemctl restart nut-client

When you pull the plug from the USP and power comes back you will get this notifications in gotify: gotify notification example

conlusion

Now I feel even safer.. 😴💕

Sources:

[1] blog.shadypixle.com

[2] homas-leister.de

[3] ups.conf

[4] srackham.wordpress.com