Skip to content

iOS, macOS, web, and science. Hacked.

  • Articles
  • About
  • Colophon

Search

CyberPower UPS NUT Tutorial

February 18, 2026 14 min read Homelab

Protect Your Homelab: Setting Up Network UPS Tools (NUT) Across Proxmox and Mac ๐Ÿ”‹

Ever had that sinking feeling when you realize your entire homelab just went down during a power outage? Yeah, me too. After one too many unexpected shutdowns (and the subsequent anxiety of checking if all my services came back up properly), I decided it was time to set up proper UPS monitoring with automatic graceful shutdowns. Let me walk you through how I configured Network UPS Tools (NUT) to protect both my Proxmox server and Mac over a Tailscale mesh network.

Why This Matters ๐ŸŽฏ

When the power goes out, your UPS keeps things running on battery – but that battery won’t last forever. Without proper monitoring, your servers will either:

  1. Run until the battery dies and everything crashes (bad!)
  2. Require manual intervention to shut down gracefully (impossible if you’re not home)

NUT solves this by monitoring your UPS and automatically shutting down your systems in the correct order when the battery gets low. Your Proxmox server and Mac will gracefully power down, preserving your data and avoiding corruption.

Key Considerations:

  • Master-slave architecture: One system connects directly to the UPS (master), others monitor via network (slaves)
  • Graceful shutdown ordering: Slaves shut down first, then the master
  • Secure communication: Authentication between systems
  • Network reliability: Tailscale provides consistent IPs even when traveling

What You’ll Need:

  • CyberPower UPS with USB connection
  • Proxmox server (or any Linux server)
  • Mac (or any macOS device)
  • Tailscale mesh network configured
  • Root/sudo access to both systems
  • About 30 minutes

Architecture Overview ๐Ÿ“

Here’s how the pieces fit together:

Proxmox Server (Master)

  • UPS connected via USB cable
  • Runs NUT server (upsd) to share UPS data
  • Monitors UPS status locally
  • Signals shutdown to Mac when battery is critical
  • Shuts down last (after slaves)

Mac (Slave)

  • Connects to Proxmox NUT server over Tailscale
  • Monitors UPS status remotely
  • Receives shutdown signal from Proxmox
  • Shuts down first to give Proxmox time to finish

Think of it like a coordinated evacuation plan – the Mac gets the signal to leave first, and the Proxmox server makes sure everyone’s out before turning off the lights.


Part 1: Configure Proxmox Server (NUT Master) ๐Ÿ–ฅ๏ธ

The Proxmox server is physically connected to the UPS, so it becomes our “master” that monitors the hardware directly and shares that information with other systems.

Step 1: Detect Your UPS

First, let’s make sure Proxmox can see your UPS:

sudo nut-scanner -q

You should see output showing your CyberPower UPS with details like this (for example, I use this UPS – no affiliate link is attached):

[nutdev1]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0764"
        productid = "0601"
        product = "CP850PFCLCDa"
        vendor = "CPS"

Pro Tip: Don’t worry about warning messages regarding SNMP, XML, or IPMI libraries – those are for enterprise network-attached UPS units. Your USB-connected UPS only needs the usbhid-ups driver.

Step 2: Install NUT

apt update
apt install nut

Step 3: Configure the UPS Driver

Create the UPS configuration file:

nano /etc/nut/ups.conf

Add this configuration (using your vendor/product IDs from the scanner):

maxretry = 3

[cyberpower]
    driver = usbhid-ups
    port = auto
    vendorid = 0764
    productid = 0601
    desc = "CyberPower UPS"

Note: The section name [cyberpower] is your UPS identifier – you’ll reference this in other configuration files.

Step 4: Set NUT to Network Server Mode

Edit the NUT configuration:

nano /etc/nut/nut.conf

Change the mode to allow network clients:

MODE=netserver

Step 5: Configure the UPS Daemon

Edit the daemon configuration:

nano /etc/nut/upsd.conf

Add these lines to listen on all interfaces:

# Listen on all interfaces (needed for Tailscale clients)
LISTEN 0.0.0.0 3493
LISTEN :: 3493

MAXAGE 15

Step 6: Create User Accounts

This is where authentication happens. Edit the users file:

nano /etc/nut/upsd.users

Add two users – one for monitoring (used by Mac) and one for admin:

[upsmon]
    password = your_secure_monitoring_password
    upsmon master

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

Security Note: Replace these with strong, unique passwords. Store them in your password manager or secrets management system. The upsmon password will be needed when configuring the Mac.

Step 7: Configure Local Monitoring

Edit the monitoring configuration:

nano /etc/nut/upsmon.conf

Add this configuration:

# Monitor the local UPS
MONITOR cyberpower@localhost 1 upsmon your_secure_monitoring_password master

# Number of power supplies (1 for single UPS)
MINSUPPLIES 1

# Shutdown command
SHUTDOWNCMD "/sbin/shutdown -h +0"

# How long to wait for slaves before shutdown (seconds)
HOSTSYNC 15

# Time to wait before declaring battery low (seconds)
FINALDELAY 5

# Notifications
NOTIFYCMD /usr/sbin/upssched
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC
NOTIFYFLAG FSD SYSLOG+WALL+EXEC

Step 8: Fix USB Permissions

Here’s where I initially got stuck – the NUT driver needs permission to access the USB device. Create a udev rule:

nano /etc/udev/rules.d/52-nut-usbups.rules

Add this line (using your vendor and product IDs):

SUBSYSTEM=="usb", ATTR{idVendor}=="0764", ATTR{idProduct}=="0601", MODE="0660", GROUP="nut"

Reload udev rules:

udevadm control --reload-rules
udevadm trigger

Step 9: Set File Permissions

chown root:nut /etc/nut/*
chmod 640 /etc/nut/upsd.users /etc/nut/upsmon.conf

Step 10: Start NUT Services

# Start the driver
upsdrvctl start

# Start upsd (UPS daemon)
systemctl start nut-server
systemctl enable nut-server

# Start upsmon (monitoring daemon)
systemctl start nut-monitor
systemctl enable nut-monitor

# Verify everything is running
systemctl status nut-server nut-monitor

Step 11: Test UPS Communication

# List available UPS devices
upsc -l
# Should output: cyberpower

# Get detailed UPS status
upsc cyberpower

# Check current status
upsc cyberpower ups.status
# Should output: OL (Online) when on AC power

Step 12: Configure Firewall

Allow NUT traffic from your Tailscale network:

# Add firewall rule for Tailscale subnet
iptables -A INPUT -s 100.0.0.0/8 -p tcp --dport 3493 -j ACCEPT

# Make it persistent
apt install iptables-persistent
iptables-save > /etc/iptables/rules.v4

Step 13: Get Your Tailscale IP

You’ll need this for the Mac configuration:

ip addr show tailscale0 | grep "inet "

Note the IP address (something like 100.x.x.x) – this is what the Mac will connect to.

Pro Tip: Test network access by querying the UPS via Tailscale IP:

upsc cyberpower@YOUR_PROXMOX_TAILSCALE_IP ups.status

This should return OL if everything is configured correctly.


Part 2: Configure Mac (NUT Slave) ๐ŸŽ

Now that the Proxmox server is broadcasting UPS status, let’s configure the Mac to monitor it and shut down gracefully when needed.

Step 1: Install NUT via Homebrew

brew install nut

Step 2: Verify Installation Paths

NUT on macOS installs binaries in different locations:

# Find upsmon (in sbin)
ls -la /opt/homebrew/sbin/upsmon

# Find upsc (in bin)
ls -la /opt/homebrew/bin/upsc

Step 3: Test Connection to Proxmox

Before configuring anything, verify the Mac can reach the Proxmox UPS server:

/opt/homebrew/bin/upsc cyberpower@YOUR_PROXMOX_TAILSCALE_IP ups.status

This should return OL if the connection works. If you get an error:

  • Verify Tailscale is connected on both systems
  • Check the firewall rule on Proxmox
  • Confirm the Tailscale IP is correct

Step 4: Create Configuration Directory

sudo mkdir -p /opt/homebrew/etc/nut

Step 5: Configure upsmon

Create the monitoring configuration:

sudo nano /opt/homebrew/etc/nut/upsmon.conf

Add this configuration (replace YOUR_PROXMOX_TAILSCALE_IP with your actual Proxmox Tailscale IP):

# Monitor UPS on Proxmox server (slave mode)
MONITOR cyberpower@YOUR_PROXMOX_TAILSCALE_IP 1 upsmon your_secure_monitoring_password slave

# Minimum number of power supplies
MINSUPPLIES 1

# Shutdown command for macOS
SHUTDOWNCMD "/sbin/shutdown -h now"

# Polling frequency (seconds)
POLLFREQ 5
POLLFREQALERT 5

# Host sync time (seconds) - wait for master before shutting down
HOSTSYNC 15

# Dead time (assume UPS is gone after this many seconds)
DEADTIME 15

# Power down flag location
POWERDOWNFLAG /etc/killpower

# Run as root
RUN_AS_USER root

# Notifications
NOTIFYCMD /opt/homebrew/sbin/upssched
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG FSD SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC
NOTIFYFLAG NOCOMM SYSLOG+WALL+EXEC

Critical: Use the exact same password you set in Proxmox’s /etc/nut/upsd.users file for the upsmon user.

Step 6: Set Permissions

sudo chown root:wheel /opt/homebrew/etc/nut/upsmon.conf
sudo chmod 640 /opt/homebrew/etc/nut/upsmon.conf

Step 7: Test Manual Connection

Before setting up the service, test that upsmon can connect:

sudo /opt/homebrew/sbin/upsmon -D

You should see output like:

Network UPS Tools upsmon 2.8.4
UPS: cyberpower@YOUR_PROXMOX_IP (slave) (power value 1)
Using power down flag file /etc/killpower
[D1] Logged into UPS cyberpower@YOUR_PROXMOX_IP

The key line is “Logged into UPS” – this confirms authentication succeeded!

Press Ctrl+C to stop the test.

Troubleshooting: If you see authentication errors, double-check:

  • The password in upsmon.conf matches Proxmox
  • The Proxmox firewall allows connections
  • The Tailscale IP is correct

Step 8: Start as System Service

Here’s where Mac setup differs from Linux. Use Homebrew services to run as root:

# Start as system service (runs as root)
sudo brew services start nut

Verify it’s running:

sudo brew services list | grep nut

Should show:

nut     started     root    /Library/LaunchDaemons/homebrew.mxcl.nut.plist

Step 9: Verify Service is Running

# Check processes
ps aux | grep upsmon

You should see upsmon running as root (not your user account). Two processes are normal – upsmon uses a parent-child architecture.

Step 10: Verify Connection on Proxmox

Back on your Proxmox server, check that the Mac connected:

journalctl -u nut-server --since "5 minutes ago" | grep "YOUR_MAC_MINI_TAILSCALE_IP"

You should see:

User upsmon@YOUR_MAC_IP logged into UPS [cyberpower]

This confirms the Mac successfully authenticated and is monitoring the UPS!


Testing Your Setup ๐Ÿงช

Now for the fun part – let’s verify everything works without actually pulling the plug (yet).

Quick Status Checks

On Mac:

# Check UPS status
/opt/homebrew/bin/upsc cyberpower@YOUR_PROXMOX_IP ups.status

# Check battery charge
/opt/homebrew/bin/upsc cyberpower@YOUR_PROXMOX_IP battery.charge

# Check UPS load
/opt/homebrew/bin/upsc cyberpower@YOUR_PROXMOX_IP ups.load

On Proxmox:

# Get full UPS details
upsc cyberpower

# Check connected clients
journalctl -u nut-server --since "10 minutes ago" | grep "logged into"

Understanding the Shutdown Sequence

Here’s what happens when the power goes out:

  1. Power Failure Detected: UPS switches to battery, status changes from OL (Online) to OB (On Battery)
  2. Battery Monitoring: Both systems continue monitoring battery level
  3. Low Battery Threshold: When battery reaches critical level (typically 20%), Proxmox detects LOWBATT flag
  4. Forced Shutdown Signal: Proxmox sends FSD (Forced Shutdown) signal to all connected slaves
  5. Mac Shuts Down: Mac receives FSD and executes /sbin/shutdown -h now
  6. Proxmox Waits: Proxmox waits HOSTSYNC (15 seconds) for slaves to finish shutting down
  7. Proxmox Shuts Down: After delay plus FINALDELAY, Proxmox executes its own shutdown

Key Parameters Explained

  • MINSUPPLIES 1: Minimum power supplies required (you have 1 UPS protecting your systems)
  • HOSTSYNC 15: Wait 15 seconds for slave systems to shut down before master proceeds
  • master vs slave: Proxmox is master (directly connected to UPS), Mac is slave (network client)
  • POLLFREQ 5: Check UPS every 5 seconds when on AC power
  • POLLFREQALERT 5: Check UPS every 5 seconds when on battery (more frequent monitoring)

Safe Testing (Optional)

Warning: This will actually trigger shutdown procedures. Only do this when you’re ready and all work is saved!

On Proxmox, you can simulate a forced shutdown:

upsmon -c fsd

Both systems should begin their shutdown sequences. The Mac will shut down first, followed by Proxmox after the HOSTSYNC delay.


Troubleshooting Common Issues ๐Ÿ”ง

Issue: “Driver not connected” on Proxmox

Symptoms: upsdrvctl start fails with permission errors

Solution: This is the USB permissions issue. Verify the udev rule exists:

cat /etc/udev/rules.d/52-nut-usbups.rules

If missing, recreate it and reload:

echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="0764", ATTR{idProduct}=="0601", MODE="0660", GROUP="nut"' > /etc/udev/rules.d/52-nut-usbups.rules
udevadm control --reload-rules

Then physically unplug and replug the USB cable.

Issue: Mac Can’t Connect to Proxmox

Symptoms: upsc commands timeout or fail

Solution: Check these in order:

  1. Verify Tailscale is connected on both systems: tailscale status
  2. Test network connectivity: nc -zv YOUR_PROXMOX_IP 3493
  3. Check Proxmox firewall: iptables -L INPUT -n -v | grep 3493
  4. Verify upsd is listening: ss -tlnp | grep 3493

Issue: Authentication Failed

Symptoms: “Access denied” or authentication errors

Solution:

  1. Verify passwords match between Mac’s upsmon.conf and Proxmox’s upsd.users
  2. Check file permissions: ls -la /etc/nut/upsd.users
  3. Restart nut-server after password changes: systemctl restart nut-server

Issue: Mac Service Shows “error” Status

Symptoms: brew services list shows error for nut

Solution: The service needs to run as root:

brew services stop nut
sudo brew services start nut

Verify it’s running as root: ps aux | grep upsmon

Issue: Device Number Changes After Reboot

Symptoms: USB device appears at different /dev/bus/usb/ path after reboot

Solution: The udev rule automatically handles this by matching vendor/product IDs rather than device numbers. No action needed – it’s working as designed!


Pro Tips for Production Use ๐Ÿ’ก

1. Monitor Your Monitoring

Set up alerts to notify you if:

  • The UPS connection is lost
  • The UPS switches to battery
  • Battery charge drops below threshold

You can integrate NUT with your existing monitoring stack (Uptime Kuma, Prometheus, etc.) or use the built-in notification system.

2. Test Periodically

Every few months, do a controlled test:

  1. Save all work
  2. Unplug the UPS from wall power
  3. Watch the monitoring logs
  4. Verify both systems receive notifications
  5. Let it run for a few minutes, then plug back in

This validates your setup still works and gives you confidence in your protection.

3. Document Your Passwords

Store your NUT passwords in your password manager with notes about:

  • Which systems use which passwords
  • Configuration file locations
  • Tailscale IP addresses

Future you will thank present you when you need to add another system.

4. Consider Battery Replacement Alerts

Configure NUT to notify you when the UPS needs a battery replacement:

NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC

UPS batteries typically last 3-5 years, and this alert can save you from a nasty surprise during the next outage.

5. Adjust Thresholds for Your Runtime

The default low battery threshold might not suit your UPS capacity. Check your UPS runtime:

upsc cyberpower battery.runtime

This shows remaining runtime in seconds. Adjust your shutdown timing to give yourself margin – you don’t want to cut it too close!


Integration with Your Homelab ๐Ÿ 

Add to Your Dashboard

If you’re running Dashy, Heimdall, or Homer, add UPS monitoring to your dashboard. You can query NUT data via HTTP or create simple status indicators.

Backup Before Shutdown

Consider adding a pre-shutdown script that triggers one final backup before the system goes down. Edit the SHUTDOWNCMD in upsmon.conf to call a wrapper script that:

  1. Triggers emergency backups
  2. Sends notifications
  3. Then executes the actual shutdown

Container Considerations

If you’re running Docker containers or VMs, ensure they have graceful shutdown procedures. NUT’s shutdown is system-level, so containers should handle SIGTERM signals properly.


Final Thoughts ๐ŸŽ“

Setting up NUT might feel like overkill until the day your power goes out and everything shuts down gracefully while you’re away on vacation. That peace of mind is worth the hour of configuration time!

The beauty of this setup is that it’s expandable – need to add another system? Just configure it as another slave client. Running multiple UPS units? NUT can handle that too. The Tailscale integration means your systems can communicate reliably even if you’re traveling or your network topology changes.

Remember:

  • Test your setup periodically
  • Monitor the monitoring (meta, I know)
  • Keep those UPS batteries fresh
  • Document your configuration

Your homelab is now protected! No more holding your breath during storms or worrying about power blips corrupting your carefully curated services. Set it, test it, and forget it – until the next time the power flickers and you smile knowing everything’s handled. โšก๏ธ


Quick Reference Card:

Proxmox Commands:

  • Check UPS status: upsc cyberpower
  • View connected clients: journalctl -u nut-server | grep "logged into"
  • Restart services: systemctl restart nut-server nut-monitor

Mac Commands:

  • Check UPS status: /opt/homebrew/bin/upsc cyberpower@PROXMOX_IP
  • View service status: sudo brew services list | grep nut
  • Check logs: log show --predicate 'process == "upsmon"' --last 10m --info

Configuration Files:

  • Proxmox: /etc/nut/ directory
  • Mac: /opt/homebrew/etc/nut/ directory

Default Port: TCP 3493

Written by Michael Henry

Post navigation

Previous: Running Jupyter Notebooks With uv
Next: NFS Mac DAS To Proxmox Tutorial
Michael Henry

Michael Henry

ยฉ 2026 Digital Javelina, LLC