UPS 断电后,怎么让 Homelab 自动关机
upsc ups@localhost 已经能读到 UPS 状态时,真正要先定下来的是“断电后等多久再关机”。
UPS 不是为了让机器一直硬撑,而是为了留出几分钟,让服务停止、数据落盘、虚拟机或容器有序退出。对 NAS、数据库、下载任务混跑的主机来说,这几分钟通常比额外续航更重要。
先定规则,再写脚本
自动关机最怕触发过早,也怕触发过晚。
如果市电只闪断几秒,马上关机会影响使用;如果一直等到电池接近耗尽,可能又来不及写盘。更实用的做法是先定一个简单规则:
- 检测到 UPS 进入电池供电状态
- 连续保持 60 到 180 秒后再检查一次
- 如果仍未恢复市电,执行关机流程
- 如果电量低于阈值,例如 30%,直接关机
这里的关键参数只有两个:
- 延迟时间:给短时停电留缓冲
- 电量阈值:避免拖到来不及安全退出
常见实现:NUT + 短脚本
NUT(Network UPS Tools)用于读取 UPS 状态。很多 USB UPS 可以接入,但不同型号的驱动名、变量名可能不同,配置前需要按设备实际输出确认;以下示例未验证适用于所有设备。
如果系统已经能读取 UPS 信息,脚本可以很短。下面这个例子只做一件事:当设备仍处于电池供电,且电量低于阈值时执行关机。
1 | |
OB 通常表示设备处于电池供电状态。这个脚本没有实现“等待 120 秒”的逻辑,更适合配合 systemd 定时器,或者由 NUT 事件机制触发。
比触发更重要的是关机顺序
只解决“何时执行 shutdown”还不够,真正容易出问题的是关机前先停谁。
一个更实用的顺序通常是:
先停写入频繁的服务
例如下载、同步、数据库、媒体索引。这类服务持续写盘,硬断电风险更高。
再停容器或虚拟机
容器可以用 docker stop,虚拟机则按实际平台处理。这里优先保证有序退出,不必为了极端完整的优雅流程把逻辑写得过重。
最后关宿主机
如果宿主机先关,内部服务会被直接中断。
可以把停服务流程拆成独立脚本,主脚本只负责触发:
1 | |
两个容易忽略的坑
1. 不要只看断电,也要处理恢复
有些环境会反复闪断。如果脚本每次检测到电池供电都重新计时,逻辑可能变乱。更稳妥的方式是:
- 进入电池模式时只触发一次
- 市电恢复时取消待执行任务
2. 不要假设所有 UPS 字段都存在
不同设备暴露的变量并不一致。有的能读到 battery.runtime,有的只能读到 battery.charge。脚本里应该提供默认值,并把失败情况写入日志,便于停电后核对流程是否真的执行。
一个够用的落地方案
如果不想一开始就做复杂编排,可以先用最小可用方案:
- UPS 通过 USB 接到主机
- 系统可以稳定读取 UPS 状态
- 断电持续 2 分钟后关机
- 电量低于 30% 时强制关机
- 关机前停掉最关键的 1 到 3 个服务
这已经能覆盖多数家用单机场景。先把单机安全关机跑通,再考虑通知、联动其他节点、统一编排。
一个边界:来电自动开机不由脚本决定
“断电后自动关机”和“来电后自动恢复”不是同一件事。
前者主要依赖系统和脚本;后者通常取决于 BIOS/UEFI 中的 AC Power Recovery 一类选项。脚本只能负责有序停机,不能决定主板在来电后是否自动开机,这一项需要到固件设置里确认。
可以先检查这三项
upsc是否能稳定读到状态- 关机前要停的服务是否已经列清楚
- 主板是否支持来电自启
如果还没开始配置,先把“必须先停的服务列表”写出来,通常比继续加长脚本更有用。