1. Nut installation

Here I use Ubuntu Server 22.04 system, the installation can be done directly with one apt command:

1
apt install -y nut

2. Nut service components

Before configuring Nut, we need to understand the components of Nut and their roles. Nut mainly contains three core services:

  • nut-driver: This service is responsible for communicating with the UPS via a specific driver.
  • nut-server: This service uses nut-dirver to communicate with the UPS and to publish the UPS status via web services.
  • nut-monitor (nut-client): this service connects to the nut-server and provides specific responses based on the UPS status

Note: nut-client is actually a systemd softlink file, which is still essentially nut-monitor.

A simple diagram is drawn here to make it easier to understand:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
             ┌─────────────┐                  ┌────────────┐
       ┌──── │ nut-monitor │ ───────────────► │ nut-server │
       │     └─────────────┘                  └────────────┘
       │                                            │
       │                                            │
       ▼                                            ▼
 ┌─────────────┐                              ┌────────────┐
 │  upssched   │                              │ nut-driver │
 └─────────────┘                              └────────────┘

        │                                           │
        │                                           │
        │                                           │
        ▼                                           ▼
┌────────────────┐                            ┌─────────────┐
│  user scripts  │                            │     UPS     │
└────────────────┘                            └─────────────┘

3. Nut Basic Configuration

After Nut is installed, a configuration file is automatically created in the /etc/nut directory, and the next configuration task is to adjust the various configuration files in this directory.

3.1. nut.conf

This configuration mainly defines the operation mode of nut, there is only one configuration field MODE=xxxx, the optional values and meanings of this configuration are as follows:

  • none: Nut is not configured or uses an external system to start the Nut service, which can be interpreted as “do nothing”.
  • standalone: Standalone mode, usually used when there is only one UPS and only responsible for the local system (no network services).
  • netserver: similar to standalone mode, it starts driver, upsd and upsmon services, except that it can provide network services, and nut-monitor on other machines can connect to Nut Server via network.
  • netclient: client-only mode, only nut-monitor is started, used to connect to remote Nut services.

I’m using the full netserver schema to facilitate subsequent extensions.

1
MODE=netserver

3.2. ups.conf

This configuration file defines how the nut-driver connects to the physical UPS, and has the following configuration format.

1
2
3
[nutdev1]
    driver = "usbhid-ups"
    port = "auto"

nutdev1 is the name of the UPS, you can define it as you like; driver is used to define the driver to be used to connect to the UPS, normally it will be recognized if you use a USB connection like I wrote. If the same USB connection is not recognized, you can use the nut-scanner command to scan the UPS, which will print out a sample UPS configuration in the console after a successful scan.

Note that if you want Synology or QNAP to be able to connect to the UPS over the network, there are special requirements for the name of the UPS (Synology must be named ups, QNAP has not been tested and may be called qnapups); because both systems are written to death, including the user name and password, which are explained below.

In addition to the USB connection to the UPS, the Nut also supports a variety of drivers to connect to the UPS, such as the APC-specific driver, please refer to the official documentation for details on how to connect the Nut.

3.3. upsd.conf

This configuration file is used to control the network services of nut-server, such as listening port, maximum number of connections, certificate configuration, etc.; since I am using it on the intranet, I only need to configure the network listening, other parameters can be left as default.

1
LISTEN 0.0.0.0 3493

For a complete overview of what configurations are supported, please refer to the official documentation: UPSD.CONF(5)

3.4. upsd.users

The upsd.users configuration file is used to define the username and password for connecting to the nut-server over the network. The sample configuration is as follows.

1
2
3
4
5
6
[monuser]
    password = secret
    upsmon = master
[admin]
    password = 123456
    upsmon = master

The [xxxx] above represents the user name, the password is specified by the password field; there are also some special parameters:

  • actions: specifies which actions the user has access to, with optional values SET (change UPS variables), FSD (set UPS force shutdown flag); if you need both, you need to write actions twice.
  • instcmds: Immediate command to start the user, the value ALL means all, others can be seen by upscmd -l; also if you want to specify more than one, you need to write instcmds more than once.
  • upsmon: adds necessary actions to the upsmon process, optional values primary, secondary (not normally used)

Note: The version on Ubuntu Server 22.04 may not be as recent, and upsmon actually supports both master and slave parameters.

About Synology and QNAP users: If you expect both NAS to connect directly to Nut Server, you can confirm that Synology needs to ensure the existence of a user with the username monuser and password secret; QNAP I have not verified, but the result of online search is that you need to ensure the existence of a user with the username admin and password 123456.

4. Nut monitoring configuration

Compared with the basic configuration, Nut core processing is how to do a good job of monitoring configuration; Nut for monitoring policy support is roughly two kinds:

    1. Configured directly by upsmon.conf, any events are directly handled by user-specified scripts, without advanced features such as timers.
    1. Configure the execution script as upssched in upsmon.conf, any event will be handled by upssched first, with the help of upssched some advanced features can be implemented, such as selective trigger shutdown, etc.

4.1. upsmon.conf

This configuration is used to configure how the nut-monitor monitors the UPS and defines what actions are to be taken in the event of a UPS event. The core configuration is explained in detail below.

4.1.1. MONITOR command

The MONITOR instruction is used to define the connection address of the UPS to be monitored, in the following format.

1
MONITOR <system> <powervalue> <username> <password> ("master"|"slave")
  • <system>: nut-server link address, formatted as “UPS name” + “@” + “nut-server address”, For example myups@192.168.1.2
  • <powervalue>: number of UPS, most of the time you only have one UPS, so just write 1
  • <username>/<password>: the username and password defined in upsd.users
  • master/slave: master means the system will be shut down last, allowing the slave to shut down first; slave means the system will be shut down immediately

Here is a sample of my configuration:

1
MONITOR ups@localhost 1 monuser secret master

4.1.2. SHUTDOWNCMD

The SHUTDOWNCMD command is used to define the shutdown command when the UPS is low on power or needs to be actively shut down. It is recommended to fill in the full path.

1
SHUTDOWNCMD "/usr/sbin/poweroff"

4.1.3. NOTIFYCMD

The NOTIFYCMD command is a very important command that configures the commands that the nut-monitor executes in case of a specific event (e.g. utility interruption, UPS low battery, etc.). Simply put, NOTIFYCMD defines the specific command to be executed, where you can directly configure a script of your own, which will be called whenever an event occurs in the UPS.

There are two ways to configure the NOTIFYCMD command, one is to configure it as your own script, which requires executable permissions, and within the script you can get the event type from the NOTIFY environment variable and process it yourself. This is a bit of a “simple and brutal” approach, and the degree of customization depends on how your script is written. Please test the variables you can use, as the names of the environment variables may vary from version to version.

Another way is to configure NOTIFYCMD to execute the built-in upssched command; upssched is a Nut-provided scheduler with specific policies; in short, it’s an abstraction based on common functions, and upssched has its own individual configuration that allows for an advanced “no shutdown if utility power is restored within 180s”. upssched is an advanced scheduler with a specific policy; in short, it is an abstraction based on common functions.

Here I choose to use the second way, because I am not really good at writing scripts.

1
NOTIFYCMD /usr/sbin/upssched

4.1.4. NOTIFYFLAG

The NOTIFYFLAG instruction is also a key configuration, and is used in conjunction with NOTIFYCMD; the NOTIFYFLAG instruction is responsible for specifying what actions should be triggered by a series of UPS events, the format of the instruction is as follows.

1
NOTIFYFLAG <notify type> <flag>[+<flag>][+<flag>] ...

Where <notify type> indicates the event type, the following types are available:

  • ONLINE: The UPS is online, i.e. it will be triggered when the utility power is restored.
  • ONBATT: The UPS is on battery power, i.e. the event will be triggered when the utility power is interrupted.
  • LOWBATT: Triggered when the UPS is low on power
  • FSD: UPS is being shut down (Forced Shutdown)
  • COMMOK: Triggered when connection with nut-server is successfully established
  • COMMBAD: Triggered when connection with nut-server fails (connection lost)
  • SHUTDOWN: Triggered when UPS sends a shutdown command
  • REPLBATT: triggered when the UPS needs to replace the battery
  • NOCOMM: Triggered when the connection to the UPS cannot be established (UPS is not ready)

For the flag flag there are usually four types, which are linked by a plus sign (+) for multiple combinations:

  • SYSLOG: prints syslog only
  • WALL: pops up a message on the terminal (/bin/wall)
  • EXEC: Calls the command specified by NOTIFYCMD, and passes the associated events
  • IGNORE: does nothing, ignores the event

If NOTIFYCMD uses custom scripts, please configure the events to be handled by the scripts according to your needs; if NOTIFYCMD is configured to use upssched, you can configure all events as EXEC, and then specifically filter them to be handled by upssched.

For example, if you only want the script configured by NOTIFYCMD to handle utility interrupt and recovery events, and to print syslog, you can configure it this way.

1
2
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC

Since my NOTIFYCMD is configured with upssched, I pass all events to upssched here.

1
2
3
4
5
6
7
8
9
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYFLAG FSD SYSLOG+EXEC
NOTIFYFLAG COMMOK SYSLOG+EXEC
NOTIFYFLAG COMMBAD SYSLOG+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+EXEC
NOTIFYFLAG REPLBATT SYSLOG+EXEC
NOTIFYFLAG NOPARENT SYSLOG+EXEC

4.1.5. Other configurations

In addition to the above core configuration, other configurations can be left as default if there are no special circumstances; for specific configurations, please refer to the official documentation: UPSMON.CONF(5)

4.2. upssched.conf

This configuration assumes that the NOTIFYCMD in the upsmon.conf configuration points to upssched, and that NOTIFYFLAG configures EXEC for the event in question; the main purpose of this configuration is to use some of upssched’s built-in high-level syntax to control how specific events are handled. The upssched.conf configuration contains two main parts: the header options and the tail rules.

4.2.1. option configuration

The header options configuration contains only three configurations:

  • CMDSCRIPT: This configuration should be located on the first line (recommended, actually just before the AT command), this command is used to define the event handling script; the script is usually written by the user, upssched will pass the specified parameters to this script and execute it according to the rules.
  • PIPEFN: pipeline file for inter-process communication, needs to be located before the AT instruction
  • LOCKFN: mutually exclusive lock file, used to prevent upsmon from scheduling multiple files at the same time, needs to be located before the AT instruction

For the CMDSCRIPT configuration script, here is a sample:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env bash

set -ex

exec >> /var/log/upssched-cmd.log 2>&1

# Functions mainly responsible for shutting down the system
function xpoweroff(){
    logger -t upssched-cmd 'Preparing to shut down XPEnology...'
    logger -t upssched-cmd 'Preparing to shut down TProxy Gateway...'
    logger -t upssched-cmd 'All necessary systems have been successfully shut down....'
}

# Determine the event triggered by upssched
case $1 in
    onbattwarn)
        logger -t upssched-cmd 'The UPS has switched to battery power, ready to safely shut down the system...'
        xpoweroff
        ;;
    ups-back-on-line)
        logger -t upssched-cmd 'Municipal power has been restored...'
        ;;
    lowbatt)
        logger -t upssched-cmd 'UPS power is low, shut down the system immediately...'
        xpoweroff
        ;;
    *)
        logger -t upssched-cmd "Unrecognized command: $1"
        ;;
esac

One thing to note is that the CMDSCRIPT configuration script is run as nut user by default, so you have to deal with the nut user permissions.

For PIPEFN and LOCKFN, the official recommendation is to create a separate directory called upssched and put the files in this directory; however, on some systems such as Ubuntu Server 22.04, /run/nut/ is tmpfs, and rebooting will cause directory loss and permission problems; so it is recommended to configure it directly without creating a separate directory.

1
2
3
CMDSCRIPT /opt/scripts/upssched-cmd.sh
PIPEFN /run/nut/upssched.pipe
LOCKFN /run/nut/upssched.lock

4.2.2. rule configuration

The advantage of using upssched is that there is a built-in rule engine, and we can configure complex rules with some simple syntax; the rule syntax of upssched is as follows.

1
AT notifytype upsname command 

The rules start with AT, notifytype specifies the type of event to follow; upsname specifies the name of the UPS, you can write * if there is only one or you don’t want to distinguish; command is used to specify the action to be performed, there are roughly three types of command:

  • START-TIMER: starts a timer
  • CANCEL-TIMER: cancels a timer
  • EXECUTE: Execute immediately

This part looks complex but is actually quite simple. For example, the following rule is implemented: when the utility is disconnected (when the UPS is powered by battery) a timer named onbattwarn is started, which after 180s executes the script defined by CMDSCRIPT and passes onbattwarn as the first parameter to the script; at the same time if the utility is restored within 180s of the timer (temporary flash-off), the script is the execution of the script is cancelled.

1
2
AT ONBATT * START-TIMER onbattwarn 180
AT ONLINE * CANCEL-TIMER onbattwarn

Of course, there are some events that need to be executed immediately, e.g., immediate notification of a utility outage.

1
2
# Immediately executes the script specified by `CMDSCRIPT`, and passes `onbattnoti` as an argument to the script.
AT ONBATT * EXECUTE onbattnoti