# Setup nut and netdata on Ubuntu In this document, I will explain how to setup `nut` (Network UPS Tools) on Ubuntu __18.04__ and __20.04__. > It is basically the next chapter of my previous gist, [Upgrade nut on Ubuntu 18.04](https://gist.github.com/Jiab77/d015f8a9630c0fb3548bcdf17d29f69f). I'll only document `USB` connected __UPS__ and not the other supported connection modes. ## Install required dependencies ### Nut ``` sudo apt install nut ``` ### Netdata ``` bash <(curl -Ss https://my-netdata.io/kickstart.sh) all --dont-wait --disable-telemetry ``` ## Must read I'd seriously recommend you to take the time to explore this [book](http://rogerprice.org/NUT/ConfigExamples.A5.pdf) written by [Roger Price](http://rogerprice.org/NUT/) that contains tons of useful information about how to implement and configure [nut](https://github.com/networkupstools/nut). ## Detect connected UPS Here is how you can detect your connected UPS. I'll mainly focus on the `USB` connection and not the other connection modes. ```bash # Scan all available devices (default) $ nut-scanner # Scan USB devices only $ nut-scanner -U # Scan USB devices only but print in ups.conf format $ nut-scanner -UN ``` Use the following commands to add the details about the connected UPS in the `/etc/nut/ups.conf` file: ```bash # Add some spacing and UPS details echo -e "\n# Detected UPS from USB" | sudo tee -a /etc/nut/ups.conf # Add detected UPS details nut-scanner -UNq 2>/dev/null | sudo tee -a /etc/nut/ups.conf # Check the result sudo cat /etc/nut/ups.conf ``` You should get something similar: ```ini # Detected UPS from USB [nutdev1] driver = "usbhid-ups" port = "auto" vendorid = "051D" productid = "0002" bus = "001" ``` You can now change `[nutdev1]` by something more representative to your UPS and also add the `desc` field. You'll need `sudo` to edit the config files. ```bash # Edit the config file sudo nano /etc/nut/ups.conf ``` Then change the previously generated config that way: ```ini # Detected UPS from USB [APCBU1400] driver = "usbhid-ups" port = "auto" desc = "APC Back-UPS 1400VA / 700w" vendorid = "051D" productid = "0002" bus = "001" ``` ## Create monitoring connection Once the UPS defined in the `/etc/nut/ups.conf` file, we must define the monitoring user that will used to read the data from the UPS and define the actions according to them. The created user is not related to the standard UNIX users, it will only exist in the `nut` context. Here is how to create it: ```bash # Install password generator sudo apt install pwgen # Generate strong password (but avoid using special chars) export NUT_RAND_PW=$(pwgen -snc -B 128 | awk '{ print $1 }') # Create monitoring user dynamicaly echo -e "\n[monitor]\n\tpassword = ${NUT_RAND_PW}\n\tupsmon master\n" | sudo tee -a /etc/nut/upsd.users # Generate connection string # You will have to copy it in the 'upsmon.conf' file later echo -e "\nMONITOR APCBU1400@localhost 1 monitor $NUT_RAND_PW master\n" # Remove generated password from environment unset NUT_RAND_PW ``` You should get something similar: ``` $ export NUT_RAND_PW=$(pwgen -snc -B 128 | awk '{ print $1 }') $ echo -e "\n[monitor]\n\tpassword = ${NUT_RAND_PW}\n\tupsmon master\n" | sudo tee -a /etc/nut/upsd.users [monitor] password = [REDACTED] upsmon master $ echo -e "\nMONITOR APCBU1400@localhost 1 monitor $NUT_RAND_PW master\n" MONITOR APCBU1400@localhost 1 monitor [REDACTED] master $ unset NUT_RAND_PW ``` Now we have to add the generated connection string into the `/etc/nut/upsmon.conf` file: ``` sudo nano /etc/nut/upsmon.conf ``` after the examples of the __MONITOR__ section: ```bash # Examples: # # MONITOR myups@bigserver 1 monmaster blah master # MONITOR su700@server.example.com 1 upsmon secretpass slave # MONITOR myups@localhost 1 upsmon pass master (or slave) MONITOR APCBU1400@localhost 1 monitor [REDACTED] master # -------------------------------------------------------------------------- ``` ## Improve UPS commands scheduling script By default the `/bin/upssched-cmd` script is pretty basic and does not contains enough commands: ```bash #! /bin/sh # # This script should be called by upssched via the CMDSCRIPT directive. # # Here is a quick example to show how to handle a bunch of possible # timer names with the help of the case structure. # # This script may be replaced with another program without harm. # # The first argument passed to your CMDSCRIPT is the name of the timer # from your AT lines. case $1 in upsgone) logger -t upssched-cmd "The UPS has been gone for awhile" ;; *) logger -t upssched-cmd "Unrecognized command: $1" ;; esac ``` Now, create a copy of the original script: ```bash # Create a copy sudo cp -v /bin/upssched-cmd /bin/upssched-cmd.bak # Edit the current version sudo nano /bin/upssched-cmd ``` And change the script to that: ```bash #! /bin/sh # # This script should be called by upssched via the CMDSCRIPT directive. # # Here is a quick example to show how to handle a bunch of possible # timer names with the help of the case structure. # # This script may be replaced with another program without harm. # # The first argument passed to your CMDSCRIPT is the name of the timer # from your AT lines. # Dynamic name assignment UPS=$( upsc -l 2>/dev/null ) # Or manual name assignement # UPS="YOUR-UPS-DEFINED-NAME-IN-UPS.CONF" STATUS=$( upsc $UPS ups.status ) CHARGE=$( upsc $UPS battery.charge ) CHMSG="[$STATUS]:$CHARGE%" case $1 in online) MSG="$UPS, $CHMSG - power supply has been restored." ;; onbatt) MSG="$UPS, $CHMSG - power failure - save your work!" ;; lowbatt) MSG="$UPS, $CHMSG - shutdown now!" ;; upsgone) MSG="The UPS $UPS has been gone for awhile" ;; *) MSG="$UPS, $CHMSG - Unrecognized command: $1" ;; esac logger -i -t upssched-cmd $MSG # Comment out the line below for workstations # notify-send-all "$MSG" ``` ## Configure commands scheduling Now that we have improved the existing commands scheduling scripts, we have to edit the `/etc/nut/upssched.conf` file and change or set some values: ```bash # Define PIPE file sudo sed -e 's|# PIPEFN /run/|PIPEFN /run/|' -i /etc/nut/upssched.conf # Define Lock file sudo sed -e 's|# LOCKFN /run/|LOCKFN /run/|' -i /etc/nut/upssched.conf # Add commands defined in the scripts echo -e "\n# Custom commands" | sudo tee -a /etc/nut/upssched.conf echo -e "AT ONLINE $(upsc -l 2>/dev/null)@localhost EXECUTE online\nAT ONBATT $(upsc -l 2>/dev/null)@localhost EXECUTE onbatt\nAT LOWBATT $(upsc -l 2>/dev/null)@localhost EXECUTE lowbatt" | sudo tee -a /etc/nut/upssched.conf # Comment out this line if it didn't worked with the 'upsc' command above # echo -e "AT ONLINE APCBU1400@localhost EXECUTE online\nAT ONBATT APCBU1400@localhost EXECUTE onbatt\nAT LOWBATT APCBU1400@localhost EXECUTE lowbatt" | sudo tee -a /etc/nut/upssched.conf # Check the result sudo nano /etc/nut/upssched.conf ``` ## Start nut services Now that we have defined the UPS in the `/etc/nut/ups.conf` file and the monitoring user in the `/etc/nut/upsd.users` then finally set the monitoring connection in `/etc/nut/upsmon.conf`, we must now change the running mode which is by default set to `none` and would not let `systemd` services to run correctly. We'll set it to the `standalone` mode for now. ```bash # Change the running mode sudo sed -e 's/MODE=none/MODE=standalone/' -i /etc/nut/nut.conf # Check the result sudo nano /etc/nut/nut.conf ``` You can now restart all the `nut` related `systemd` services: ``` for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do sudo systemctl restart $S ; done ``` Wait few seconds to let them start then check their status: ``` for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do systemctl status $S -l ; done ``` You should see something similar: ``` $ for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do systemctl status $S -l ; done ● nut-monitor.service - Network UPS Tools - power device monitor and shutdown controller Loaded: loaded (/lib/systemd/system/nut-monitor.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 8s ago Process: 8731 ExecStart=/sbin/upsmon (code=exited, status=0/SUCCESS) Main PID: 8733 (upsmon) Tasks: 2 (limit: 4915) Memory: 3.0M CGroup: /system.slice/nut-monitor.service ├─8732 /lib/nut/upsmon └─8733 /lib/nut/upsmon jui 02 07:49:48 [REDACTED] upsmon[8731]: Using power down flag file /etc/killpower jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Can't open PID file /run/nut/upsmon.pid (yet?) jui 02 07:49:48 [REDACTED] upsmon[8732]: Startup successful jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Supervising process 8733 which is not our child jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device monitor and shutdown contro jui 02 07:49:48 [REDACTED] upsmon[8733]: Login on UPS [APCBU1400@localhost] failed - got [ERR ACCESS-DENIED jui 02 07:49:53 [REDACTED] upsmon[8733]: Poll UPS [APCBU1400@localhost] failed - Write error: Broken pipe jui 02 07:49:53 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost lost jui 02 07:49:58 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost established jui 02 07:49:58 [REDACTED] upsmon[8733]: UPS APCBU1400@localhost on line power ● nut-driver.service - Network UPS Tools - power device driver controller Loaded: loaded (/lib/systemd/system/nut-driver.service; static; vendor preset: enabled) Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 16s ago Process: 8704 ExecStart=/sbin/upsdrvctl start (code=exited, status=0/SUCCESS) Main PID: 8725 (usbhid-ups) Tasks: 1 (limit: 4915) Memory: 1.1M CGroup: /system.slice/nut-driver.service └─8725 /lib/nut/usbhid-ups -a APCBU1400 jui 02 07:49:48 [REDACTED] systemd[1]: Starting Network UPS Tools - power device driver controller... jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Using subdriver: APC HID 0.96 jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Network UPS Tools - Generic HID driver 0.41 (2.7.4) jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: USB communication driver 0.33 jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Network UPS Tools - UPS driver controller 2.7.4 jui 02 07:49:48 [REDACTED] usbhid-ups[8725]: Startup successful jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device driver controller. ● nut-monitor.service - Network UPS Tools - power device monitor and shutdown controller Loaded: loaded (/lib/systemd/system/nut-monitor.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 16s ago Process: 8731 ExecStart=/sbin/upsmon (code=exited, status=0/SUCCESS) Main PID: 8733 (upsmon) Tasks: 2 (limit: 4915) Memory: 3.0M CGroup: /system.slice/nut-monitor.service ├─8732 /lib/nut/upsmon └─8733 /lib/nut/upsmon jui 02 07:49:48 [REDACTED] upsmon[8731]: Using power down flag file /etc/killpower jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Can't open PID file /run/nut/upsmon.pid (yet?) jui 02 07:49:48 [REDACTED] upsmon[8732]: Startup successful jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Supervising process 8733 which is not our child jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device monitor and shutdown contro jui 02 07:49:48 [REDACTED] upsmon[8733]: Login on UPS [APCBU1400@localhost] failed - got [ERR ACCESS-DENIED jui 02 07:49:53 [REDACTED] upsmon[8733]: Poll UPS [APCBU1400@localhost] failed - Write error: Broken pipe jui 02 07:49:53 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost lost jui 02 07:49:58 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost established jui 02 07:49:58 [REDACTED] upsmon[8733]: UPS APCBU1400@localhost on line power ● nut-server.service - Network UPS Tools - power devices information server Loaded: loaded (/lib/systemd/system/nut-server.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2021-07-02 07:49:52 CEST; 1min 16s ago Process: 8787 ExecStart=/sbin/upsd (code=exited, status=0/SUCCESS) Main PID: 8800 (upsd) Tasks: 1 (limit: 4915) Memory: 1.1M CGroup: /system.slice/nut-server.service └─8800 /lib/nut/upsd jui 02 07:49:52 [REDACTED] upsd[8787]: fopen /run/nut/upsd.pid: No such file or directory jui 02 07:49:52 [REDACTED] upsd[8787]: listening on 127.0.0.1 port 3493 jui 02 07:49:52 [REDACTED] upsd[8787]: listening on ::1 port 3493 jui 02 07:49:52 [REDACTED] upsd[8787]: listening on 127.0.0.1 port 3493 jui 02 07:49:52 [REDACTED] upsd[8787]: listening on ::1 port 3493 jui 02 07:49:52 [REDACTED] upsd[8787]: Connected to UPS [APCBU1400]: usbhid-ups-APCBU1400 jui 02 07:49:52 [REDACTED] upsd[8787]: Connected to UPS [APCBU1400]: usbhid-ups-APCBU1400 jui 02 07:49:52 [REDACTED] upsd[8800]: Startup successful jui 02 07:49:52 [REDACTED] systemd[1]: Started Network UPS Tools - power devices information server. jui 02 07:49:58 [REDACTED] upsd[8800]: User monitor@::1 logged into UPS [APCBU1400] ``` If yes, then you can read the data available from your UPS that way: ```bash # Use 'upsc -l' to get the name of the UPS # Then pass it as self argument to read the UPS data upsc $(upsc -l 2>/dev/null) 2>/dev/null ``` It should output something similar but with different values according to your UPS: ``` $ upsc $(upsc -l 2>/dev/null) 2>/dev/null battery.charge: 100 battery.charge.low: 10 battery.charge.warning: 50 battery.date: 2001/09/25 battery.mfr.date: 2020/09/17 battery.runtime: 2604 battery.runtime.low: 120 battery.type: PbAc battery.voltage: 27.3 battery.voltage.nominal: 24.0 device.mfr: American Power Conversion device.model: Back-UPS XS 1400U device.serial: [REDACTED] device.type: ups driver.name: usbhid-ups driver.parameter.bus: 001 driver.parameter.pollfreq: 30 driver.parameter.pollinterval: 2 driver.parameter.port: auto driver.parameter.productid: 0002 driver.parameter.synchronous: no driver.parameter.vendorid: 051D driver.version: 2.7.4 driver.version.data: APC HID 0.96 driver.version.internal: 0.41 input.sensitivity: medium input.transfer.high: 280 input.transfer.low: 155 input.voltage: 234.0 input.voltage.nominal: 230 ups.beeper.status: enabled ups.delay.shutdown: 20 ups.firmware: 926.T2 .I ups.firmware.aux: T2 ups.load: 14 ups.mfr: American Power Conversion ups.mfr.date: 2020/09/17 ups.model: Back-UPS XS 1400U ups.productid: 0002 ups.realpower.nominal: 700 ups.serial: [REDACTED] ups.status: OL ups.test.result: No test initiated ups.timer.reboot: 0 ups.timer.shutdown: -1 ups.vendorid: 051d ``` ## Configure Netdata You can now configure __Netdata__ and add the name of your UPS in the configuration file: ```bash # Go to the netdata config folder cd /etc/netdata # Run the editing script sudo ./edit-config charts.d/nut.conf ``` You don't really need to change anything as normally the defaults are good enough to simply having to restart the service and nothing more: ``` sudo systemctl restart netdata ; systemctl status netdata -l ``` Now you can navigate to <http://localhost:19999> and search for the __UPS__ section on the right, you should see something like that:  ## References * <https://github.com/networkupstools/nut> * <https://wiki.archlinux.org/title/Network_UPS_Tools> * <https://manpages.ubuntu.com/manpages/focal/en/man8/nut-scanner.8.html> * <http://rogerprice.org/NUT/> * <http://rogerprice.org/NUT/ConfigExamples.A5.pdf> * <https://learn.netdata.cloud/docs/agent/collectors/charts.d.plugin/nut>