折腾家里云(二): 配置UPS系统,入手伊顿Eaton 9PX3000IRT2U和9PXEBM72RT2U电池包,并配置NUT共享网络UPS
半夜经历了一次停电之后,觉得学校供电稳定性实在是令人担忧。本文主要讲解了NUT (Network UPS Tools) 的架构和FSD通知机制并配置UPS,给局域网下的所有设备都提供网络UPS关机通知。
UPS基本参数信息
| 类型 | 参数 | |
|---|---|---|
| 设备型号 | Eaton 9PX3000IRT2U | |
| 额定功率 | 3000VA | |
| 电源架构 | 在线式与互动式可切换 | |
| 电池容量 | 9PX3000IRT2U主机 | 6只12V9Ah 铅酸电池 |
| 9PXEBM72RT2U电池包 | 12只12V9Ah 铅酸电池 | |
| 总计72V27Ah, 1944Wh | ||
| 重量 | 9PX3000IRT2U主机 | 28kg |
| 9PXEBM72RT2U电池包 | 39.2kg | |
| 总计约67.2kg(含包装74kg) | ||
| 价格 | 海鲜市场 打包2000元 | 含所有电池换新 |
装机




配置UPS
连接与识别
我的 UPS 没有选装网络卡,所以用一根 USB type-B(打印机线)直接把 UPS 接到服务器上。
root@poweredge-r730:~# lsusbBus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 001 Device 002: ID 8087:800a Intel Corp. HubBus 001 Device 003: ID 413c:a001 Dell Computer Corp. HubBus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBus 002 Device 002: ID 8087:8002 Intel Corp. 8 channel internal hubBus 002 Device 003: ID 0463:ffff MGE UPS Systems UPS <---这个0463 是 MGE(后来被伊顿收购)的 USB Vendor ID,ffff 则是 UPS 类设备的通用 Product ID,伊顿/MGE 系的 UPS(9PX、5PX、5SC 等)基本都是这一对 ID。
为什么不用伊顿官方软件伊顿官方的 Intelligent Power Protector (IPP) 配置全走 Web 界面,对”一台 UPS 通过局域网通知多台设备”这种多机联动支持得很差。而 NUT 是 Linux 世界的标准做法:配置全是纯文本,天然支持一台 UPS 共享给整个局域网。
NUT 架构
NUT(Network UPS Tools)把”和 UPS 说话”和”要不要关机”这两件事拆成了两个独立的进程,中间用一套很简单的文本协议连接。
| 组件 | 作用 | 配置文件 |
|---|---|---|
驱动 usbhid-ups | 通过 USB HID 直接和 UPS 通信,把 UPS 的全部变量(电量、功率、状态……)暴露在一个 Unix socket 上 | ups.conf |
upsd | 数据服务器,聚合各个驱动的数据,监听 TCP 3493 对外提供服务 | upsd.conf、upsd.users |
upsmon | 监控 + 关机控制器,连到 upsd 判断”电还够不够”,不够就关机 | upsmon.conf |
| 命令行工具 | upsc / upsrw / upscmd / upsdrvctl / upssched | - |
nut.conf | 总开关:standalone / netserver / netclient | - |
┌──────────────┐ USB (HID) ┌────────────────┐│ Eaton 9PX │◀─────────────▶│ usbhid-ups │ ← 驱动└──────────────┘ └───────┬────────┘ │ /run/nut/usbhid-ups-eaton9px ▼ ┌─────────────┐ │ upsd │ ← 数据服务器 └──────┬──────┘ 127.0.0.1:3493 ──────────────┤────────────── 10.10.10.2:3493 │ TCP 3493(NUT 明文协议) ┌───────────────────────────────┼───────────────────────────────┐ ▼ ▼ ▼┌───────────────┐ ┌───────────────┐ ┌───────────────┐│ upsmon │ │ upsmon │ │ upsc / upsrw ││ (primary) │ │ (secondary) │ │ 查询工具 ││ R730 本机 │ │ fnOS NAS │ │ │└───────────────┘ └───────────────┘ └───────────────┘装包:
apt install nut nut-server nut-clientDebian 13 上装完会自动带上 systemd 集成:nut-driver-enumerator.path 会根据 ups.conf 自动生成 nut-driver@eaton9px.service,不需要手动启动驱动。
服务端配置(R730,MODE=netserver)
nut.conf 里的 MODE 决定这台机器扮演什么角色:
MODE=netserverstandalone:本机接 UPS、自己监控、自己关机(单机场景)netserver:本机接 UPS,并把数据用upsd共享给局域网(本例)netclient:本机不接 UPS,只连别人的upsd(后文的二级节点)
ups.conf —— 驱动配置
[eaton9px] driver = usbhid-ups port = auto vendorid = 0463 productid = ffff desc = "Eaton 9PX UPS (USB)" # UPS 收到断电指令后延迟 60 秒才切断输出(默认 20 秒),给服务器留更多关机时间 offdelay = 60 # 市电恢复后 90 秒再开启输出,尽量避免"刚关机就来电、来电又断电"的反复横跳 ondelay = 90方括号里的 eaton9px 就是这台 UPS 在 NUT 里的标识名,后面 upsc、upsmon.conf 里都要用它,名字随意但必须一致。
port = auto 让驱动自己扫 USB 总线,所以 vendorid/productid 是必须写的,否则同一台机器上插了多个 USB HID 设备时可能认错。
offdelay / ondelay 到底在管什么这两个值正常运行时完全不起作用,只在收到
killpower(断电指令)时才生效:
offdelay:收到断电指令后,UPS 再等多少秒才真正切断输出ondelay:切断输出后,如果市电已经恢复,UPS 等多少秒后重新给负载上电
upsd.conf —— 监听地址
默认 upsd 只监听 127.0.0.1,要让局域网里其它机器用上,必须显式加上本机在局域网中的地址:
LISTEN 127.0.0.1 3493LISTEN 10.10.10.2 3493upsd.users —— 用户与权限
每个要连上来的 upsmon 都需要一个账号。这里有个反直觉的点:权限不用手写 actions,直接写 upsmon primary / upsmon secondary 即可,NUT 会自动赋予当前版本所需的全部权限(手写容易漏,升级后还可能失效)。
# 本机 upsmon,是 primary,需要设置 FSD 的权限[upsmon] password = <你的密码> upsmon primary
# 二级节点(NAS),只需要能登录读取状态[fnos-upsmon] password = <你的密码> upsmon secondary
[cyan-fnos-upsmon] password = <你的密码> upsmon secondary两者最核心的差别:只有 primary 类型的用户有 FSD 权限,也就是只有它能把”强制关机”标志写进 upsd。二级节点只能被动接收。
upsmon.conf —— 监控与关机
MONITOR eaton9px@localhost 1 upsmon <密码> primary
MINSUPPLIES 1SHUTDOWNCMD "/sbin/shutdown -h +0"POLLFREQ 5POLLFREQALERT 5HOSTSYNC 180DEADTIME 15POWERDOWNFLAG "/etc/killpower"OFFDURATION 30RBWARNTIME 43200NOCOMMWARNTIME 300FINALDELAY 5MONITOR 那行的五个参数依次是:<UPS标识> <供电路数> <用户名> <密码> <角色>。
其中**供电路数(powervalue)**值得单独说:它表示”这台机器有几路电源来自这个 UPS”。R730 是单电源,所以填 1;带双电源的机器就要填 2。它和 MINSUPPLIES 配合构成关机判据——当”健康供电的路数 < MINSUPPLIES”时才会触发关机。
官方文档里还有一个特殊的用法:powervalue 填 0 表示”这台机器不从被监控的 UPS 取电,但仍想看它的状态”,这需要配合 MINSUPPLIES 0 使用(否则会因为”可用路数 0 < 1”反而触发关机),这就是所谓的只监控不关机模式。
其余参数:
| 参数 | 值 | 含义 |
|---|---|---|
MINSUPPLIES | 1 | 至少要有 1 路可靠供电,否则关机 |
SHUTDOWNCMD | /sbin/shutdown -h +0 | 真正执行的关机命令 |
POLLFREQ | 5 | 正常状态下每 5 秒拉一次状态 |
POLLFREQALERT | 5 | 电池供电时每 5 秒拉一次状态 |
HOSTSYNC | 180 | primary 置 FSD 后,等待 secondary 断开的最长时间 |
DEADTIME | 15 | 多久收不到状态就把 UPS 标记为 dead(必须是 POLLFREQ 的整数倍) |
POWERDOWNFLAG | /etc/killpower | 关机时创建的标志文件,见后文 |
OFFDURATION | 30 | 忽略”短暂 OFF 状态”的秒数,避免校准/切换瞬间被误判为断电 |
RBWARNTIME | 43200 | 多久提示一次”电池该换了” |
NOCOMMWARNTIME | 300 | 多久提示一次”联系不上 UPS” |
FINALDELAY | 5 | 发出关机通知后,等 5 秒再执行 SHUTDOWNCMD |
HOSTSYNC 不是越大越好
HOSTSYNC是 primary 等二级节点断开的时间,它和二级节点的FINALDELAY有耦合关系:如果二级节点的
FINALDELAY大于 primary 的HOSTSYNC,primary 会放弃等待该二级节点。而这段时间是拿电池换来的。默认的 15 秒对 NAS 关机来说太紧(fnOS 上还跑着 Docker),所以我改成了 180 秒,剩余电量完全撑得住。
让 UPS 在服务器关机后也断电
这一步是很多人会漏掉的:服务器关机了,但 UPS 还在放电。如果停电时间很长,电池会被彻底耗干;如果”关机后立刻来电”,服务器又会在电池剩一点点的时候启动,接着再停一次电——这就是所谓的 power race。
NUT 的解法是三级配合:
upsmon判定要关机时,创建POWERDOWNFLAG文件(本例是/etc/killpower)- 系统关机走到最后,systemd 会执行
/usr/lib/systemd/system-shutdown/nutshutdown - 该脚本先用
upsmon -K检查标志文件是否存在,存在就调用upsdrvctl shutdown命令 UPS 切断输出(延迟offdelay秒)
# 手动检查标志文件状态,正常运行时应当输出 "Power down flag is not set"upsmon -K之后只要市电恢复,UPS 会在 ondelay 秒后自动给负载上电,服务器再依靠 BIOS 的”上电自启”(R730 里是 AC Power Recovery)自动开机。
FSD:一次断电通知背后的完整流程
FSD 是 Forced Shutdown(强制关机),是 NUT 里最巧妙的一个设计。关键点在于:primary 并不是”挨个通知”二级节点的,而是把 FSD 标志写进 upsd,所有连上来的 upsmon 自己会看到。
在 upsd 看来,FSD 标志等价于”市电断电 + 电池低电量”,也就是 critical 状态。所以从二级节点的视角,“UPS 真的快没电了”和”primary 让我关机”是同一件事,走的是同一套逻辑:

几个容易踩的点:
- 只有
upsmon primary用户有 FSD 权限。 如果二级节点连上来的账号被误配成 primary(或反之),就会表现为”通知发出去了但没人关机”或”该等的没等”。 HOSTSYNC与FINALDELAY的配对(见上一节)。SHUTDOWNEXIT默认为 yes:二级节点一旦开始执行SHUTDOWNCMD,upsmon就会退出,从而断开与upsd的连接;primary 正是靠着”客户端一个个掉线”来判断二级节点是否已经进入关机流程。所以如果某台二级节点关机特别慢(比如 NAS 要停 Docker),要么调大 primary 的HOSTSYNC,要么用upssched让它更早开始关机。upsmon -c fsd会立刻走完整流程(包括让机器关机),演练时请慎用。
二级节点(fnOS / NAS)配置
二级节点不接 UPS,也不需要驱动,只要装 nut-client(提供 upsmon)即可:
apt install nut-clientMODE=netclient# 用户名密码要和 R730 上 /etc/nut/upsd.users 里的完全一致MONITOR eaton9px@10.10.10.2 1 fnos-upsmon <密码> secondary
MINSUPPLIES 1SHUTDOWNCMD "/sbin/shutdown -h +0"FINALDELAY 5NOTE
POWERDOWNFLAG在 secondary 上其实没有意义——二级节点没有驱动,无法命令 UPS 断电,nutshutdown会因为找不到upsdrvctl而跳过这一步。不配置它也没问题,只要保证SHUTDOWNCMD正确即可。
验证连通性:
# 在二级节点上列出能看到哪些 UPSupsc -l 10.10.10.2# 读取关键变量upsc eaton9px@10.10.10.2 ups.status battery.charge battery.runtime如果报 Access denied,八成是 upsd.users 里没有对应的用户名/密码,或者 upsd.conf 里少了一行 LISTEN。
日常使用:几个常用命令
upsc eaton9px # 打印全部 102 个变量upsc eaton9px ups.status battery.charge battery.runtime ups.loadupsc -l # 列出本机 upsd 能看到的 UPSupsrw -l eaton9px # 列出可写变量upscmd -l eaton9px # 列出支持的即时命令upscmd eaton9px beeper.mute # 静音(半夜停电时你会用到的)upscmd eaton9px test.battery.start.quick # 手动启动一次电池自检upsmon -c reload # 重载 upsmon.conf实测这台 9PX3000IRT2U 在 12% 负载(约 320W)下的状态:
$ upsc eaton9px | grep -E "ups.status|battery.charge:|battery.runtime:|ups.load|ups.realpower:"battery.charge: 100battery.runtime: 11803 # ≈ 3 小时 16 分ups.load: 12ups.realpower: 320ups.status: OL CHRGups.status 的常见组合
ups.status可能是多个 flag 的组合,用空格分隔,常见的有:
flag 含义 OLOn Line,市电在线 OBOn Battery,电池供电 LBLow Battery,低电量(触发关机的关键) CHRG/DISCHRG充电中 / 放电中 BYPASS旁路供电(有电但不受保护) FSD已收到强制关机指令 OVER过载 CAL电池校准中


监控:把状态推到 Uptime Kuma
光有日志还不够,我需要”手机能收到告警”。upsmon 默认只会在 syslog 和终端 wall 里喊(NOTIFYFLAG 的默认行为),要自己写 NOTIFYCMD 才能推送到手机。所以写了个常驻脚本,把状态变化推到 Uptime Kuma 的 Push 监控:
[Unit]Description=NUT UPS status push to Uptime KumaWants=network-online.targetAfter=network-online.target nut-server.service
[Service]Type=simpleExecStart=/usr/local/bin/nut-ups-push.shRestart=alwaysRestartSec=15Environment="LOG_FILE="
[Install]WantedBy=multi-user.target脚本逻辑很简单:每 5 秒 upsc 一次,把状态归并成 online / battery / lowbatt / bypass / commbad 几种模式,模式一变就立即推送;一直正常时则每 10 分钟推一次心跳。推送内容带上当前功率、电池百分比和预计剩余时间:


实测记录
截至写这篇文章时,这套系统已经挡下了几次停电:
| 时间 | 事件 | 结果 |
|---|---|---|
| 2026-09-06 14:15 | 停电,转电池供电 | 75 分钟后恢复,未触发关机 |
| 2026-09-06 15:33 | 再次停电 | 5 秒后恢复 |
| 2026-09-22 20:10 | 停电,转电池供电 | 12 分钟后恢复 |

参考
- NUT 官网:networkupstools.org
- 官方手册:
man upsmon.conf、man upsd.conf、man upsd.users、man usbhid-ups - NUT 文档:Shutdown design / config-notes
以下是可爱的评论们:

输入用户名和邮箱后自动检查登录状态。登录后用户名和邮箱将被绑定, 只可以修改头像和主页链接。