2026-05-07 20:22:12 +00:00
# @serve.zone/nupst
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
NUPST is a Network UPS Shutdown Tool for servers that need predictable behavior when power gets ugly. It monitors UPS devices through SNMP or NUT/UPSD, evaluates per-device and grouped power conditions, and runs ordered actions such as Proxmox guest shutdown, webhooks, scripts, and host shutdown.
2025-03-25 09:06:23 +00:00
2026-01-29 17:04:12 +00:00
## Issue Reporting and Security
2026-05-07 20:22:12 +00:00
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/ ](https://community.foss.global/ ). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/ ](https://code.foss.global/ ) account to submit Pull Requests directly.
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
## Why It Exists
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
Power-failure automation must be boring, explicit, and local-first. NUPST is built as a single compiled Deno binary that can sit on a Proxmox host or another Linux server, poll one or more UPS devices, and execute a controlled shutdown sequence before batteries are exhausted.
2025-03-25 13:15:48 +00:00
2026-05-07 20:22:12 +00:00
It is useful when you need:
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
- SNMP monitoring for network UPS units.
- NUT/UPSD monitoring for USB UPS units exposed by Network UPS Tools.
- Multiple UPS devices on one daemon.
- Redundant or non-redundant UPS groups.
- Proxmox VM/LXC shutdown before host shutdown.
- Webhook or script notifications.
- A small authenticated HTTP JSON status endpoint.
- Pause/resume for maintenance windows.
- Configuration migration from older NUPST formats.
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
## Installation
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
Install the released binary:
2025-03-25 11:31:24 +00:00
2025-10-20 12:52:26 +00:00
``` bash
curl -sSL https://code.foss.global/serve.zone/nupst/raw/branch/main/install.sh | sudo bash
2025-03-25 11:31:24 +00:00
```
2026-05-07 20:22:12 +00:00
Install through the npm package wrapper with pnpm:
2025-03-25 09:06:23 +00:00
``` bash
2026-05-07 20:22:12 +00:00
pnpm add --global @serve.zone/nupst
2025-10-20 12:52:26 +00:00
```
2025-03-25 11:31:24 +00:00
2026-05-07 20:22:12 +00:00
The installer places the binary under `/opt/nupst/nupst` , creates a symlink in `/usr/local/bin` or `/usr/bin` , and preserves existing `/etc/nupst/config.json` when upgrading.
2025-03-25 11:31:24 +00:00
2026-05-07 20:22:12 +00:00
## Quick Start
2025-03-25 11:31:24 +00:00
2026-05-07 20:22:12 +00:00
Create the first UPS config interactively:
2025-11-09 11:30:39 +00:00
``` bash
2026-05-07 20:22:12 +00:00
sudo nupst ups add
2025-11-09 11:30:39 +00:00
```
2026-05-07 20:22:12 +00:00
Test connectivity:
2025-03-25 09:06:23 +00:00
``` bash
2026-05-07 20:22:12 +00:00
nupst ups test --debug
2025-10-20 12:52:26 +00:00
```
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
Install and start the systemd service:
2025-10-18 13:33:46 +00:00
2025-10-20 12:52:26 +00:00
``` bash
2026-05-07 20:22:12 +00:00
sudo nupst service enable
sudo nupst service start
2025-03-25 09:06:23 +00:00
```
2026-05-07 20:22:12 +00:00
Inspect status and logs:
2025-10-18 13:33:46 +00:00
2025-10-20 12:52:26 +00:00
``` bash
2026-05-07 20:22:12 +00:00
nupst service status
nupst service logs
2025-10-20 12:52:26 +00:00
```
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
## CLI Reference
2025-10-18 13:33:46 +00:00
2025-10-20 12:52:26 +00:00
``` bash
2026-05-07 20:22:12 +00:00
nupst <command> [ subcommand] [ options]
2025-10-20 12:52:26 +00:00
```
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
Global options:
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
| Option | Purpose |
| --- | --- |
| `--version` , `-v` | Show version. |
| `--help` , `-h` | Show help. |
| `--debug` , `-d` | Enable detailed SNMP/UPSD logging. |
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Service commands:
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
| Command | Purpose |
| --- | --- |
| `service enable` | Install and enable the systemd service. Requires root. |
| `service disable` | Stop, disable, and remove the service. Requires root. |
| `service start` | Start `nupst.service` . |
| `service stop` | Stop `nupst.service` . |
| `service restart` | Restart the service. |
| `service status` | Show service and UPS state. |
| `service logs` | Follow live service logs. |
| `service start-daemon` | Run the daemon process directly. Used by systemd/testing. |
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Configuration commands:
2026-04-16 09:44:30 +00:00
2026-05-07 20:22:12 +00:00
| Command | Purpose |
| --- | --- |
| `ups add` | Add a UPS device interactively. |
| `ups edit [id]` | Edit a UPS device. |
| `ups remove <id>` | Remove a UPS device. Alias: `rm` . |
| `ups list` | List UPS devices. Alias: `ls` . |
| `ups test` | Test configured UPS connections. |
| `group add` | Create a UPS group. |
| `group edit <id>` | Edit a group. |
| `group remove <id>` | Remove a group. Alias: `rm` . |
| `group list` | List groups. Alias: `ls` . |
| `action add <target-id>` | Add an action to a UPS or group. |
| `action edit <target-id> <index>` | Edit an action by array index. |
| `action remove <target-id> <index>` | Remove an action. Alias: `rm` . |
| `action list [target-id]` | List actions globally or for one target. Alias: `ls` . |
| `feature httpServer` | Configure the optional JSON status endpoint. Aliases: `http-server` , `http` . |
| `config show` | Display the active configuration. |
| `pause [--duration <time>]` | Suppress actions while polling continues. |
| `resume` | Resume action execution. |
| `upgrade` | Upgrade NUPST from the latest release. Requires root. |
| `uninstall` | Remove NUPST. Requires root. |
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Pause durations support values such as `30m` , `2h` , and `1d` . The maximum pause duration is 24 hours.
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
## Configuration Model
2025-03-28 16:19:43 +00:00
2026-05-07 20:22:12 +00:00
NUPST stores configuration at:
2025-03-28 16:19:43 +00:00
2026-05-07 20:22:12 +00:00
``` text
/etc/nupst/config.json
2025-03-25 09:06:23 +00:00
```
2026-05-07 20:22:12 +00:00
The daemon loads and migrates this file at startup. It also watches for configuration changes and can reload normal config edits without a service restart.
2025-10-20 12:52:26 +00:00
2026-05-07 20:22:12 +00:00
Current normalized config version is `4.4` .
2026-04-14 18:47:37 +00:00
2026-05-07 20:22:12 +00:00
Minimal shape:
2025-03-25 09:06:23 +00:00
``` json
{
2026-04-16 09:44:30 +00:00
"version" : "4.4" ,
2025-03-28 16:19:43 +00:00
"checkInterval" : 30000 ,
2026-04-14 18:47:37 +00:00
"defaultShutdownDelay" : 5 ,
2025-03-28 16:19:43 +00:00
"upsDevices" : [
{
2025-10-20 12:52:26 +00:00
"id" : "ups-main" ,
2026-05-07 20:22:12 +00:00
"name" : "Main UPS" ,
2026-02-20 11:51:59 +00:00
"protocol" : "snmp" ,
2025-03-28 16:19:43 +00:00
"snmp" : {
"host" : "192.168.1.100" ,
"port" : 161 ,
2026-05-07 20:22:12 +00:00
"version" : 2 ,
2025-03-28 16:19:43 +00:00
"community" : "public" ,
"timeout" : 5000 ,
2026-05-07 20:22:12 +00:00
"upsModel" : "apc" ,
2026-03-30 06:46:28 +00:00
"runtimeUnit" : "ticks"
2025-03-28 16:19:43 +00:00
} ,
2026-05-07 20:22:12 +00:00
"groups" : [ "rack-a" ] ,
2025-10-20 12:52:26 +00:00
"actions" : [
2026-02-20 11:51:59 +00:00
{
"type" : "proxmox" ,
"triggerMode" : "onlyThresholds" ,
"thresholds" : { "battery" : 30 , "runtime" : 15 } ,
2026-04-02 08:29:16 +00:00
"proxmoxMode" : "auto" ,
2026-05-07 20:22:12 +00:00
"proxmoxHaPolicy" : "haStop"
2026-02-20 11:51:59 +00:00
} ,
2025-10-20 12:52:26 +00:00
{
"type" : "shutdown" ,
"triggerMode" : "onlyThresholds" ,
2026-02-20 11:51:59 +00:00
"thresholds" : { "battery" : 20 , "runtime" : 10 } ,
2025-10-20 12:52:26 +00:00
"shutdownDelay" : 5
}
2026-05-07 20:22:12 +00:00
]
2025-03-28 16:19:43 +00:00
}
] ,
"groups" : [
{
2026-05-07 20:22:12 +00:00
"id" : "rack-a" ,
"name" : "Rack A" ,
"mode" : "nonRedundant" ,
"actions" : [ ]
2025-03-28 16:19:43 +00:00
}
]
2025-03-25 09:06:23 +00:00
}
```
2026-05-07 20:22:12 +00:00
## Protocols
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
SNMP supports these UPS model profiles:
2026-04-16 09:44:30 +00:00
2026-05-07 20:22:12 +00:00
| Config value | Typical use |
| --- | --- |
| `cyberpower` | CyberPower devices. |
| `apc` | APC/PowerNet devices. |
| `eaton` | Eaton/Powerware devices. |
| `tripplite` | Tripp Lite devices. |
| `liebert` | Liebert/Vertiv devices. |
| `custom` | Custom OID mapping. |
2025-10-19 13:14:18 +00:00
2026-05-07 20:22:12 +00:00
SNMP versions `1` , `2` , and `3` are supported. SNMPv3 supports `noAuthNoPriv` , `authNoPriv` , and `authPriv` with MD5/SHA authentication and DES/AES privacy.
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
UPSD/NIS supports UPS devices exposed by NUT:
2025-10-18 13:33:46 +00:00
2025-10-20 12:52:26 +00:00
``` json
{
2026-05-07 20:22:12 +00:00
"protocol" : "upsd" ,
"upsd" : {
"host" : "127.0.0.1" ,
"port" : 3493 ,
"upsName" : "ups" ,
"timeout" : 5000 ,
"username" : "optional" ,
"password" : "optional"
}
2026-04-02 08:29:16 +00:00
}
```
2026-05-07 20:22:12 +00:00
## Action System
2025-03-28 16:19:43 +00:00
2026-05-07 20:22:12 +00:00
Actions are evaluated in array order. Put Proxmox shutdown actions before host shutdown actions so guests get time to stop cleanly.
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Action types:
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
| Type | Purpose |
| --- | --- |
| `shutdown` | Schedule host shutdown with an optional delay. |
| `webhook` | Send an HTTP GET or POST request. |
| `script` | Execute a script from `/etc/nupst/` . |
| `proxmox` | Shut down Proxmox VMs and LXC containers. |
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
Trigger modes:
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
| Mode | Behavior |
| --- | --- |
| `onlyPowerChanges` | Run only when status changes between online and battery states. |
| `onlyThresholds` | Run only when battery/runtime thresholds are newly violated. |
| `powerChangesAndThresholds` | Run on power changes or threshold violations. This is the default. |
| `anyChange` | Run on every poll/check. |
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Threshold-based actions are edge-triggered. They fire when the condition is entered, not on every poll while the condition remains true. If the condition clears and later re-enters, the action can fire again.
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
## Groups
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
Groups coordinate conditions across multiple UPS devices:
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
| Mode | Behavior |
| --- | --- |
| `redundant` | Threshold actions trigger only when all group members are on battery and below the action thresholds. |
| `nonRedundant` | Threshold actions trigger when any group member is on battery and below the action thresholds. |
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
For destructive threshold-based group actions such as `shutdown` and `proxmox` , NUPST suppresses execution while any required group member is `unreachable` . This avoids acting on incomplete data during network failures.
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
## Proxmox Integration
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
The Proxmox action supports three modes:
2026-04-16 09:44:30 +00:00
2026-05-07 20:22:12 +00:00
| Mode | Behavior |
| --- | --- |
| `auto` | Prefer local `qm` /`pct` CLI tools when available as root, otherwise use the API. |
| `cli` | Force local CLI mode. Requires root on a Proxmox host. |
| `api` | Force Proxmox REST API mode with token auth. |
2026-04-16 09:44:30 +00:00
2026-05-07 20:22:12 +00:00
Useful options:
2026-04-16 09:44:30 +00:00
2026-05-07 20:22:12 +00:00
| Option | Purpose |
| --- | --- |
| `proxmoxHost` | API host. Defaults to `localhost` . |
| `proxmoxPort` | API port. Defaults to `8006` . |
| `proxmoxNode` | Node name. Defaults to system hostname. |
| `proxmoxTokenId` | API token ID, for API mode. |
| `proxmoxTokenSecret` | API token secret, for API mode. |
| `proxmoxExcludeIds` | VM/CT IDs to skip. |
| `proxmoxStopTimeout` | Graceful stop timeout in seconds. Defaults to `120` . |
| `proxmoxForceStop` | Force-stop guests that do not shut down. Defaults to `true` . |
| `proxmoxInsecure` | Skip TLS verification in API mode. Defaults to `true` . |
| `proxmoxHaPolicy` | `none` or `haStop` for HA-managed resources. |
2026-04-16 02:54:16 +00:00
2026-05-07 20:22:12 +00:00
## HTTP Status API
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
Enable interactively:
2025-10-23 12:57:58 +00:00
2026-02-20 11:51:59 +00:00
``` bash
sudo nupst feature httpServer
```
2025-10-23 12:57:58 +00:00
2026-05-07 20:22:12 +00:00
When enabled, the endpoint returns cached daemon status and requires a bearer token or `token` query parameter.
2025-10-23 12:57:58 +00:00
2026-02-20 11:51:59 +00:00
``` bash
2026-05-07 20:22:12 +00:00
curl -H "Authorization: Bearer <token>" http://localhost:8080/ups-status
curl "http://localhost:8080/ups-status?token=<token>"
2026-02-20 11:51:59 +00:00
```
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
Response shape:
2025-03-25 09:06:23 +00:00
2026-02-20 11:51:59 +00:00
``` json
{
"upsDevices" : [
{
"id" : "ups-main" ,
2026-05-07 20:22:12 +00:00
"name" : "Main UPS" ,
2026-02-20 11:51:59 +00:00
"powerStatus" : "online" ,
"batteryCapacity" : 100 ,
"batteryRuntime" : 45 ,
"outputLoad" : 23 ,
"outputPower" : 115 ,
2026-05-07 20:22:12 +00:00
"outputVoltage" : 230 ,
"outputCurrent" : 0.5
2026-02-20 11:51:59 +00:00
}
] ,
"paused" : false
}
```
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
## Runtime Behavior
2026-03-30 06:46:28 +00:00
2026-05-07 20:22:12 +00:00
- Default polling interval is 30 seconds.
- UPS devices become `unreachable` after 3 consecutive polling failures.
- Failure counters are capped at 100.
- Shutdown delay defaults to 5 minutes unless overridden per action.
- Pause state is stored at `/etc/nupst/pause` .
- Normal monitoring talks to configured UPS, NUT, and Proxmox targets. Upgrade and release checks contact `code.foss.global` .
2025-10-19 13:14:18 +00:00
2026-05-07 20:22:12 +00:00
Installed system paths:
2025-10-19 13:05:51 +00:00
2026-05-07 20:22:12 +00:00
| Path | Purpose |
| --- | --- |
| `/opt/nupst/nupst` | Installed binary. |
| `/usr/local/bin/nupst` or `/usr/bin/nupst` | Symlink to the binary. |
| `/etc/nupst/config.json` | Main configuration. |
| `/etc/nupst/pause` | Pause state. |
| `/etc/systemd/system/nupst.service` | systemd unit. |
2025-10-19 13:05:51 +00:00
2026-05-07 20:22:12 +00:00
## Development
2025-10-19 13:14:18 +00:00
2026-02-20 11:51:59 +00:00
``` bash
2026-05-07 20:22:12 +00:00
deno task dev
2026-02-20 11:51:59 +00:00
deno task check
deno task lint
2026-05-07 20:22:12 +00:00
deno task fmt
deno task test
2025-10-20 12:52:26 +00:00
deno task compile
2025-10-18 13:33:46 +00:00
```
2026-05-07 20:22:12 +00:00
Package scripts are also available:
2025-10-18 13:33:46 +00:00
2026-05-07 20:22:12 +00:00
``` bash
pnpm build
pnpm test
pnpm run lint
pnpm run format
```
Source map:
| Path | Purpose |
| --- | --- |
| `mod.ts` | CLI entry point. |
| `ts/cli.ts` | Command parser and help output. |
| `ts/nupst.ts` | Main facade wiring protocol clients, daemon, systemd, and handlers. |
| `ts/daemon.ts` | Config loading, migration, polling loop, and action orchestration. |
| `ts/snmp/` | SNMP protocol implementation and OID sets. |
| `ts/upsd/` | NUT/UPSD client. |
| `ts/actions/` | Shutdown, webhook, script, and Proxmox actions. |
| `ts/cli/` | Interactive command handlers. |
| `ts/migrations/` | Config format migrations. |
| `ts/http-server.ts` | Optional authenticated JSON status endpoint. |
2025-10-18 13:33:46 +00:00
2025-03-25 11:36:11 +00:00
## License and Legal Information
2025-03-25 09:06:23 +00:00
2026-05-07 20:22:12 +00:00
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license ](./license ) file.
2025-03-25 11:36:11 +00:00
2026-05-07 20:22:12 +00:00
**Please note: ** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
2025-03-25 11:36:11 +00:00
### Trademarks
2026-05-07 20:22:12 +00:00
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
2026-01-29 17:04:12 +00:00
2026-05-07 20:22:12 +00:00
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
2025-03-25 11:36:11 +00:00
### Company Information
2026-05-07 20:22:12 +00:00
Task Venture Capital GmbH\
Registered at District Court Bremen HRB 35230 HB, Germany
2025-03-25 11:36:11 +00:00
2026-01-29 17:04:12 +00:00
For any legal inquiries or further information, please contact us via email at hello@task .vc.
2025-03-25 11:36:11 +00:00
2026-05-07 20:22:12 +00:00
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.