Network UPS Monitoring Tools (NUT) with PeaNUT and Nutify Dashboards on Ubuntu/Debian

Network UPS Monitoring Tools (NUT) with PeaNUT and Nutify Dashboards on Ubuntu/Debian

Keep your homelab protected. This guide walks you through installing NUT to monitor your UPS over the network, fixing the most common USB permissions pitfall, and deploying two excellent web dashboards — PeaNUT and Nutify — via Docker for a clean real-time view of your UPS status.

What Is NUT?

Network UPS Tools (NUT) is an open-source project that lets you monitor Uninterruptible Power Supplies (UPS) and take automatic actions — like gracefully shutting down servers — when power events occur. It works with hundreds of UPS models from APC, CyberPower, Eaton, and many others.

NUT has three main components:

  • Driver (usbhid-ups, etc.) — talks directly to the UPS hardware over USB or serial
  • Server (upsd) — exposes UPS data over the network
  • Monitor (upsmon) — watches UPS status and triggers shutdown commands

What Is PeaNUT?

PeaNUT is a lightweight, beautiful web dashboard for NUT built with Next.js. It gives you real-time UPS stats, charts, command execution, InfluxDB/Prometheus integration, and a built-in terminal to talk to the NUT server directly — all from your browser.

GitHub - Brandawg93/PeaNUT: A tiny dashboard for Network UPS Tools
A tiny dashboard for Network UPS Tools. Contribute to Brandawg93/PeaNUT development by creating an account on GitHub.

What Is Nutify?

Nutify is a more feature-rich UPS monitoring dashboard built with Python/Flask. Where PeaNUT is minimal and elegant, Nutify goes deeper — offering historical data stored in a SQLite database, detailed energy and battery reports, multi-channel notifications (email, Discord, Ntfy, webhooks), a multi-user authentication system with per-page permissions, and an interactive setup wizard. It can run as a full standalone NUT server or as a lightweight client connecting to an existing NUT server like the one we set up in this guide.

GitHub - DartSteven/Nutify: Modern web-based UPS monitoring system with real-time data visualization, alerts, and comprehensive reporting. Docker-ready with multi-architecture support.
Modern web-based UPS monitoring system with real-time data visualization, alerts, and comprehensive reporting. Docker-ready with multi-architecture support. - DartSteven/Nutify

Prerequisites

  • Ubuntu 22.04 / 24.04 (or any Debian-based distro)
  • A USB UPS device physically connected to your server
  • Docker and Docker Compose installed (for PeaNUT)
  • sudo access

Part 1 — Install and Configure NUT

Step 1: Install NUT

bash

sudo apt update
sudo apt install nut nut-client nut-server -y

Step 2: Find Your UPS USB IDs

Plug in your UPS and run:

bash

lsusb

Look for your UPS brand. Example output for an APC UPS:

Bus 002 Device 002: ID 051d:0002 American Power Conversion Uninterruptible Power Supply

Note the Vendor ID (051d) and Product ID (0002) — you'll need these.

Step 3: Configure the UPS Driver — /etc/nut/ups.conf

bash

sudo nano /etc/nut/ups.conf

Add your UPS definition. Adjust vendorid and productid to match your device:

ini

[ups]
    driver = usbhid-ups
    port = auto
    vendorid = 051d
    productid = 0002
    desc = "My UPS"
Tip: The section name [ups] is the identifier you'll reference throughout NUT config. You can name it anything — [garage-ups], [server-room], etc.

Step 4: Configure the NUT Server — /etc/nut/upsd.conf

bash

sudo nano /etc/nut/upsd.conf

Allow connections from localhost (and optionally your LAN):

ini

LISTEN 127.0.0.1 3493
# Uncomment the line below to allow LAN access (e.g. for remote clients):
# LISTEN 0.0.0.0 3493

Step 5: Set Up Users — /etc/nut/upsd.users

bash

sudo nano /etc/nut/upsd.users

ini

[admin]
    password = your_admin_password
    actions = SET
    instcmds = ALL

[upsmon]
    password = your_monitor_password
    upsmon master
Security: Change both passwords to something strong.

Step 6: Configure the Monitor — /etc/nut/upsmon.conf

bash

sudo nano /etc/nut/upsmon.conf

ini

MONITOR [email protected] 1 upsmon your_monitor_password master
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
POLLFREQ 5
POLLFREQALERT 5
HOSTSYNC 15
DEADTIME 15
POWERDOWNFLAG /etc/killpower
RBWARNTIME 43200
NOCOMMWARNTIME 300
FINALDELAY 5

Step 7: Set NUT Mode — /etc/nut/nut.conf

bash

sudo nano /etc/nut/nut.conf

ini

MODE=standalone
Use standalone if the NUT server and client are on the same machine. Use netserver if other machines will connect to this NUT instance.

Part 2 — Fix the USB Permissions (Critical Step!)

This is the most common issue with NUT on Ubuntu/Debian. By default, the nut user does not have permission to access USB devices, causing the driver to fail with:

Failed to open device (051D/0002), skipping: Access denied (insufficient permissions)

Create a udev Rule

bash

sudo nano /etc/udev/rules.d/99-nut-ups.rules

Add this line (replace 051d and 0002 with your actual vendor/product IDs from lsusb):

SUBSYSTEM=="usb", ATTR{idVendor}=="051d", ATTR{idProduct}=="0002", MODE="0660", GROUP="nut"

Apply the Rule

bash

sudo udevadm control --reload-rules
sudo udevadm trigger

Verify It Worked

Find your UPS's USB path using lsusb (note the Bus and Device numbers):

Bus 002 Device 002: ID 051d:0002 American Power Conversion ...

Then check the device permissions:

bash

ls -la /dev/bus/usb/002/002

Expected output:

crw-rw---- 1 root nut 189, 129 Mar 27 23:04 /dev/bus/usb/002/002

The group should be nut with rw group permissions. ✅


Part 3 — Start NUT Services

bash

sudo systemctl restart [email protected]
sudo systemctl restart nut-server.service
sudo systemctl restart nut-monitor.service

Verify All Services Are Running

bash

systemctl list-units | grep nut

You should see:

ServiceStatus
[email protected]active (running)
nut-server.serviceactive (running)
nut-monitor.serviceactive (running)

Test It

bash

upsc ups

You should see a full dump of your UPS data:

battery.charge: 100
battery.runtime: 3270
input.voltage: 120.0
ups.load: 14
ups.status: OL
...

ups.status: OL means Online — your UPS is running on mains power and monitoring correctly. 🎉


Part 4 — Install PeaNUT Dashboard via Docker

PeaNUT connects to your NUT server and gives you a polished web interface with real-time graphs, status cards, and UPS command execution.

Option A: Docker Run (Quick Start)

bash

docker run -d \
  --name PeaNUT \
  --restart unless-stopped \
  -v /path/to/config:/config \
  -p 8080:8080 \
  -e WEB_PORT=8080 \
  brandawg93/peanut:latest

Create a docker-compose.yml:

yaml

services:
  peanut:
    image: brandawg93/peanut:latest
    container_name: PeaNUT
    restart: unless-stopped
    volumes:
      - ./config:/config
    ports:
      - 8080:8080
    environment:
      - WEB_PORT=8080
      # Optional authentication:
      # - WEB_USERNAME=admin
      # - WEB_PASSWORD=your_secure_password

Start it:

bash

docker compose up -d

Access PeaNUT

Open your browser and go to:

http://your-server-ip:8080

Connect PeaNUT to Your NUT Server

On first launch, PeaNUT will ask you for the NUT server details. Enter:

  • Host: your-server-ip (or 172.17.0.1 if NUT is on the Docker host)
  • Port: 3493
  • Username: upsmon (from your upsd.users)
  • Password: your monitor password
Note: If PeaNUT is running as a Docker container and NUT is on the same host, use host.docker.internal (on Docker Desktop) or the host's Docker bridge IP (typically 172.17.0.1) — not 127.0.0.1, as that would refer to inside the container.

Part 5 — Optional Configuration

Enable Authentication

Set these environment variables in your Docker Compose file to require login:

yaml

environment:
  - WEB_USERNAME=admin
  - WEB_PASSWORD=your_secure_password

NUT Server Accessible From LAN (Remote Clients)

If you want other machines to connect to this NUT server, update /etc/nut/upsd.conf:

ini

LISTEN 0.0.0.0 3493

And open the firewall port:

bash

sudo ufw allow 3493/tcp

Reverse Proxy with Nginx

To serve PeaNUT at a subdomain, add a proxy in your Nginx config:

nginx

server {
    listen 80;
    server_name peanut.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Homepage Widget Integration

If you use Homepage, add this to your services config:

yaml

widget:
  type: peanut
  url: http://your-peanut-ip:8080
  key: ups

Troubleshooting

Driver stuck on "activating" / never starts

Run the driver manually in debug mode to see the raw error:

bash

sudo /lib/nut/usbhid-ups -DDD -u root -a ups

"Can't connect to UPS" in upsd logs

The driver isn't running or crashed. Check:

bash

sudo systemctl status [email protected]

UPS not detected by lsusb

Check the physical USB cable and port. Try a different USB port. Some UPS models require the data cable (not just power) to be connected.

PeaNUT shows "connection refused"

Make sure upsd is listening on the correct interface. Check /etc/nut/upsd.conf and verify port 3493 is open if connecting from another machine.


Summary

StepWhat You Did
Installed NUTapt install nut nut-client nut-server
Configured driver/etc/nut/ups.conf with vendor/product ID
Fixed USB permissionsudev rule granting nut group access
Started servicesnut-driver@ups, nut-server, nut-monitor
Verified UPS dataupsc ups returns live stats
Deployed PeaNUTDocker container on port 8080

Your UPS is now fully monitored. If power fails, NUT will detect it and can gracefully shut down your servers before the battery runs out — protecting your homelab from data corruption and hardware damage.



Part 6 — Install Nutify Dashboard via Docker

Nutify is an alternative (or complementary) dashboard with a heavier feature set — detailed reports, energy monitoring, multi-user auth, notifications via email/Discord/Ntfy/webhooks, and historical data persistence in SQLite. It includes its own built-in NUT server, but can also run in CLIENT mode to connect to an existing NUT server like the one we set up in Parts 1–3.

Architecture Note: SERVER vs CLIENT Mode

Nutify supports two deployment modes:

  • SERVER (Standalone): Nutify manages NUT internally — the UPS is plugged directly into the Nutify container host. Skip the NUT installation from Parts 1–3 in this case.
  • CLIENT (Netclient): Nutify connects to an external NUT server. Use this if you already have NUT running (as we do in this guide). The setup wizard will ask for your NUT server's IP and port 3493.

Step 1: Pull the Correct Image for Your Architecture

ArchitectureDocker Image Tag
AMD64 / x86-64 (standard PC/server)dartsteven/nutify:amd64-latest
ARM64 (Raspberry Pi 4+, Apple Silicon)dartsteven/nutify:arm64-latest

Step 2: Create the Docker Compose File

Create a directory and docker-compose.yaml:

bash

mkdir -p ~/nutify && cd ~/nutify
nano docker-compose.yaml

yaml

services:
  nutify:
    image: dartsteven/nutify:amd64-latest   # Change to arm64-latest if on ARM
    container_name: Nutify
    privileged: true
    cap_add:
      - SYS_ADMIN
      - SYS_RAWIO
      - MKNOD
    devices:
      - /dev/bus/usb:/dev/bus/usb:rwm
    device_cgroup_rules:
      - 'c 189:* rwm'
    volumes:
      - ./Nutify/logs:/app/nutify/logs
      - ./Nutify/instance:/app/nutify/instance
      - ./Nutify/ssl:/app/ssl
      - ./Nutify/etc/nut:/etc/nut
      - /dev:/dev:rw
      - /run/udev:/run/udev:ro
    environment:
      - SECRET_KEY=change_this_to_a_random_string   # Used for password encryption
      - UDEV=1                                        # Improves USB detection
    ports:
      - 5050:5050    # Nutify web UI
      - 3494:3493    # NUT port (use 3494 if 3493 is already taken by your NUT install)
      - 443:443      # Optional HTTPS
    restart: always
    user: root
Important: If you already have NUT running on port 3493 on this host (from Parts 1–3), map Nutify's internal 3493 to a different host port like 3494 to avoid conflicts, as shown above.

Start it:

bash

docker compose up -d

Step 3: Run the Setup Wizard

Open your browser and go to:

http://your-server-ip:5050

You'll be greeted by Nutify's setup wizard. Work through the steps:

  1. Timezone — select your local timezone
  2. Operating Mode:
    • Choose CLIENT if connecting to your existing NUT server (recommended if you followed Parts 1–3)
    • Choose SERVER if Nutify will manage the UPS directly
  3. UPS Name — give your UPS an identifier (e.g., ups)
  4. Connection Details:
    • If CLIENT mode: enter your NUT server's IP and port 3493
    • Username: upsmon (from your upsd.users)
    • Password: your monitor password
  5. Save & Restart — Nutify will restart and load the main dashboard

Step 4: Explore the Dashboard

Once connected, Nutify's dashboard gives you:

  • Real-time stats — voltage, load, battery charge and runtime
  • Energy page — power consumption analysis over time
  • Battery page — battery health and charge history
  • Reports — scheduled and on-demand UPS reports
  • Events — log of all power events
  • Notifications — configure email, Discord, Ntfy, or webhooks for alerts
  • Dark/Light theme toggle

Optional: Enable Authentication

In Nutify v0.1.7+, multi-user authentication is built in. Navigate to Settings → Users in the web UI to create admin and read-only accounts, and control which users can access which pages and configuration areas.


PeaNUT vs Nutify — Which Should You Use?

Both dashboards connect to your NUT server and display UPS data beautifully. Here's how they compare:

FeaturePeaNUTNutify
Language/StackNext.js (TypeScript)Python / Flask
SetupMinimal — just point at NUT serverSetup wizard — more guided
Data storageNone (live only)SQLite (historical data)
ChartsReal-timeReal-time + historical
Energy reports
Notifications✅ Email, Discord, Ntfy, Webhooks
Multi-user authBasic (env var)✅ Full per-page permissions
InfluxDB/Prometheus
Homepage widget
Terminal access
Resource usageVery lightModerate
Best forMinimalists, Grafana usersFeature-seekers, alert-heavy setups

Short answer: Run PeaNUT if you want something light and integrate with Grafana/Prometheus. Run Nutify if you want built-in reporting, notifications, and historical data without external tools. They can both run simultaneously pointing at the same NUT server — pick whichever suits your workflow.


Final Summary

StepWhat You Did
Installed NUTapt install nut nut-client nut-server
Configured driver/etc/nut/ups.conf with vendor/product ID
Fixed USB permissionsudev rule granting nut group access
Started servicesnut-driver@ups, nut-server, nut-monitor
Verified UPS dataupsc ups returns live stats
Deployed PeaNUTDocker container on port 8080
Deployed NutifyDocker container on port 5050

Your UPS is now fully monitored with two dashboards to choose from. If power fails, NUT will detect it and gracefully shut down your servers before the battery runs out — protecting your homelab from data corruption and hardware damage.


Guide written based on a real-world setup using an APC UPS on Ubuntu 24.04 with NUT 2.8.1, PeaNUT v5.22.0, and Nutify v0.1.7.

ссс