Linux server with UPS
Introduction
Having a server, it's a good practice to protect it from power supply failures. Solution for such case is to use UPS. Occasionally power down can last longer than UPS battery capacity and then it's recommended to gracefully shutdown server. In order to accomplish this, UPS needs to have some kind of connection with the server (common one is USB) and on the server dedicated software must be installed. Some UPS manufacturers have their own software, but if we have a less common model or an older UPS, than a good solution is to use open source software such as NUT (Network UPS Tools). Big advantage of NUT software is that we can use one software to manage UPS devices from different manufacturers. NUT software is in standard Debian repositories so it's easy to install and can be used on Proxmox hypervisor which is based on Debian. This way, we can have nice homelab hypervisor connected to UPS for protection against power supply issues. In this article I will be using UPS Socomec NPE-0650.
OS used: Debian 12
Software used: nut 2.8.0
Hardware used: UPS Socomec NPE-0650
Source
This article is based on information from Techno Tim blog post and NUT offcial documentation.
UPS model to choose
If you don't have UPS and want to buy one I would check NUT Hardware compatibility list and pick model with support level based on publicly available protocol or higher.
Packages installation
Install nut metapackage which will install nut-server and nut-client. NUT has client/server architecture where clients access UPS hardware through the server and is notified about power status changes.
# apt install nut
UPS scan
First we need to find UPS device connected to our host:
# lsusb
(...)
Bus 001 Device 002: ID 0665:5161 Cypress Semiconductor USB to Serial
(...)
# nut-scanner -U
Scanning USB bus.
[nutdev1]
driver = "nutdrv_qx"
port = "auto"
vendorid = "0665"
productid = "5161"
product = "USB to Serial"
vendor = "INNO TECH"
bus = "001"
nut-scanner -U - USB scan
Configuration
UPS configuration
Create UPS configuration at the end of /etc/nut/ups.conf file:
# vim /etc/nut/ups.conf
(...)
[npe650]
driver = nutdrv_qx
port = auto
desc = "Socomec NPE-0650"
vendorid = "0665"
productid = "5161"
[npe650]- your own name for UPSdriver,port,vendorid,productid- data copied from results ofnut-scannercommanddesc- your description
Mode configuration
Now we need to choose which parts of NUT are started. Should it work only for localhost, work as a server or work only as a client. We will choose option for localhost only which is called standalone.
# vim /etc/nut/nut.conf
(...)
MODE=standalone
(...)
Configuration of data server daemon upsd
By default upsd will only listen to localhost port 3493/TCP. If you want to connect to NUT server from other hosts this must be configured here. It is used for example in configuration where we have one dedicated machine like Raspberry Pi with many UPS devices connected and other hosts connect to get information about UPS statuses. In this tutorial we will use default configuration with allowed connection only from localhost. Add folowing line in the section with LISTEN:
# vim /etc/nut/upsd.conf
(...)
LISTEN 127.0.0.1 3493
(...)
Create NUT user
Create a upsd user for upsmon. Edit upsd.users and create a new section:
# vim /etc/nut/upsd.users
[monuser]
password = mypass
upsmon primary
[monuser]- set your user namepassword- set your password, if you use some of special characters there can be problems with password, first configuration ofnutrun with simple password then change it to desiredupsmon- adds the necessary actions forupsmonprocess to work. This is either set toprimaryorsecondary. If host is connected to UPS directly and can manage it using a NUT driver thenupsmonis theprimary.
Check upsd.users file permissions and ownership because it contains password. Should be as follows:
# ls -l /etc/nut/upsd.users
-rw-r----- 1 root nut 2319 Jan 25 2023 /etc/nut/upsd.users
Configuration of NUT client upsmon
Create MONITOR line with name of UPS to which we connect:
# vim /etc/nut/upsmon.conf
(...)
MONITOR npe650@localhost 1 monuser mypass primary
(...)
<upsname>@<hostname>- UPS name fromups.confto which we connect1- power value, it is the sum of all UPS devices that supply power to the system hostingupsmon. Can be also set to0withsecondarywhich means monitoring only and does not shut down when the UPS does.monuser- username fromupsd.usersmypass- password fromupsd.usersprimary- primary setting fromupsd.users
Check upsmon.conf file permissions and ownership because it contains password (otherwise attacker knowing this password can invoke shutdown). Should be as follows:
# ls -l /etc/nut/upsmon.conf
-rw-r----- 1 root nut 19786 Jan 25 2023 /etc/nut/upsmon.conf
Run NUT
- Reboot system to apply configuration files changes.
- When system is up again check status of service - service should be
active (running):
# systemctl status nut-monitor
There can be errors like these below but I don't think it causes any problems (here is some info in NUT GitHub issue):
fopen /run/nut/upsmon.pid: No such file or directory
Could not find PID file to see if previous upsmon instance is already running!
Checking UPS data
Check UPS data with upsc <upsname>@<hostname> command.
# upsc npe650@localhost
battery.voltage: 13.70
device.type: ups
driver.name: nutdrv_qx
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.productid: 5161
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0665
driver.version: 2.8.0
driver.version.data: Q1 0.07
driver.version.internal: 0.32
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.frequency: 50.0
input.voltage: 226.5
input.voltage.fault: 224.4
output.voltage: 224.4
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.load: 14
ups.productid: 5161
ups.status: OL
ups.temperature: 25.0
ups.type: offline / line interactive
ups.vendorid: 0665
As you can see Socomec NPE-0650 shows very little detail. Most important will be:
ups.delay.shutdown- interval to wait after shutdown with delay command in secondsups.delay.start- interval to wait before (re)starting the load in secondsups.load- load on UPS in %ups.status- show UPS status:OL- onlineOL CHRG- chargingOB- on batteryOB LB- low batteryFSD- system shutdown
ups.temperature- UPS temperature in °C
Better UPS will have more parameters like shown below (that is why don't be to cheap on UPS):
battery.charge- shows current battery charge in %battery.charge.low- shows battery charge in % when UPS is signaling low battery and by defaultupsmonwill initiate shutdown procedurebattery.runtime- shows current runtime on battery in secondsbattery.runtime.low- shows predicted runtime when low battery in secondsups.timer.shutdown- time before the load will be shutdown in secondsups.timer.start- time before the load will be started in seconds
Tuning automatic shutdown
NUT will initiate shutdown when ups.status reaches state OB LB. For my Socomec UPS this left to little juice in battery to properly shutdown system. If you have similar situation you can invoke shutdown command earlier by overriding parameters for low battery state. Details for commands can be found in specific driver manual page. Here is manual for nutdrv_qx.
# vim /etc/nut/ups.conf
[npe650]
driver = nutdrv_qx
port = auto
desc = "Socomec NPE-0650"
vendorid = "0665"
productid = "5161"
# override parameters
ignorelb
override.battery.voltage.high = 12.30
override.battery.voltage.low = 10.60
override.battery.charge.low = 50
ignorelb- NUT driver ignores a low battery condition flag that is reported by the UPS and will use following conditionbattery.charge < battery.charge.lowoverride.battery.voltage.high- max charged battery voltage (after 12 to 24h) that UPS shows when switching to batteryoverride.battery.voltage.low- low battery voltage when UPS automatically shutdowns (generally it's a state when UPS beeps rapidly)override.battery.charge.low- percent of battery charge below which NUT will initiate shutdown
Note
override.battery.voltage.high and override.battery.voltage.low for nutdrv_qx driver will show battery.charge and battery.charge.low values. These values are estimated and are not reliable under load.
Restart NUT service for changes to take effect:
# systemctl restart nut-monitor
Test UPS
Simulating power failure
To simulate power failure call forced shutdown flag FSD. Shutdown procedure will be initiated and it is possible to time how long it takes for hosts to shutdown.
# upsmon -c fsd
Real life test
- Watch UPS status with watch command:
# watch -d upsc npe650@localhost
-d - highlight differences between updates of watch command
- Swich off UPS power
- UPS will work on battery
- Watch for file
/etc/killpower. It is created byupsmonwhen shutdown sequence is initiated:
# watch -d ls -l /etc/killpower
- After some time status will be low battery
- Shutdown procedure will start
- System will switch off
- UPS will switch off
Info
By default when shutdown sequence is completed the UPS will switch off. It will switch on after return of mains AC power and delay time specified in ups.delay.start (for my Socomec it is 180 seconds which is 3 minutes). So don't be surprised during testing that when you switch on AC power and your UPS doesn't start immediately but after certain time.