尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

群晖NAS非官方UPS接入:基于NUT实现断电保护与状态监控

群晖NAS非官方UPS接入:基于NUT实现断电保护与状态监控 1. 项目概述从一次断电事故说起去年夏天我经历了一次刻骨铭心的教训。一场突如其来的雷暴导致小区短暂停电虽然只有不到一分钟但我的群晖NAS网络附加存储却因此“罢工”一块硬盘出现了坏道导致一个存放家庭照片的存储卷降级。数据虽然没丢但那种心惊肉跳的感觉让我下定决心要彻底解决NAS的供电保护问题。于是一台不间断电源UPS被提上了日程。市面上支持群晖的UPS不少但要么价格昂贵要么功能单一。我手头恰好有一台老旧的APC BK650M2这是一款非常经典的入门级UPS性价比极高但它与群晖的“官方”兼容性仅限于通过USB连接实现最基本的断电关机功能。这意味着我无法在群晖的DSM管理界面里看到UPS的实时负载、电池电量、预计运行时间等关键信息更别提进行精细化的电源管理策略配置了。这显然不符合我这种喜欢“掌控一切”的极客风格。正是在这种背景下我开始了对“群晖UPS NUT接口开发”的探索。NUT全称Network UPS Tools是一个开源、跨平台的UPS监控与管理套件。它的强大之处在于通过一个统一的守护进程upsd和驱动层可以支持市面上成百上千种不同品牌、型号的UPS并将状态信息通过标准的网络协议如upsc命令暴露出来。我的目标很明确让这台“非官方”支持的APC UPS通过NUT在群晖上“重生”实现媲美甚至超越官方兼容UPS的监控与管理能力。这不仅是为了解决我自己的问题更是为所有拥有“非标”UPS、又希望深度集成到群晖生态中的用户探索一条可行的技术路径。2. 核心思路与技术选型解析要让NUT在群晖上跑起来首先得理解群晖DSM系统的本质。DSM是基于Linux的定制化操作系统但其内核和用户空间经过了深度裁剪和封装普通用户通过图形界面GUI能接触到的系统层面非常有限。直接使用apt-get或yum安装软件包是行不通的。因此我们的核心思路是在DSM的系统框架内以“非侵入”或“最小侵入”的方式部署并运行完整的NUT套件。这里有几个关键的技术选型考量2.1 部署方式套件 vs. Docker vs. 命令行套件.spk安装这是最“原生”的群晖方式通过群晖的套件中心安装。但为NUT开发一个正式的.spk套件需要向群晖提交申请、进行签名和上架流程复杂且对于个人开发者而言几乎不可能。此外不同型号的群晖ARM、x86需要分别编译维护成本极高。因此这条路首先被排除。Docker容器部署这是目前社区最流行、最灵活的方案。我们可以在Docker Hub上找到现成的NUT镜像如nut-server通过群晖的Docker套件一键部署。它的优势是隔离性好不污染宿主机环境升级和迁移都非常方便。但缺点同样明显UPS的USB设备需要映射到容器内这涉及到设备权限和持久化挂载的问题。更关键的是让DSM系统宿主感知到Docker容器内NUT服务发出的关机信号需要额外的脚本和配置增加了复杂度。命令行直接安装直接在DSM的Linux环境下通过包管理器的替代方案如ipkg/opkg或手动编译安装NUT。这种方式最“底层”能获得最好的性能和最直接的控制。DSM虽然移除了apt但其底层仍是Linux存在/lib、/usr等目录结构。通过社区维护的entware或synogear这类第三方软件仓库可以安装预编译的NUT包。这是我最终选择的方案。原因在于直接性NUT服务以原生进程运行在DSM上与系统集成度最高。控制力可以直接修改配置文件调试方便。可靠性不依赖额外的容器引擎服务生命周期更可控。2.2 NUT工作模式选择NUT支持多种工作模式对于单NAS场景最常用的是独立模式standalone和主从模式master/slave。独立模式一台机器既是UPS的监控服务器运行upsd也是需要被保护的客户端。配置简单适合单一设备。主从模式一台机器作为主服务器master连接并监控UPS其他机器slave通过网络从主服务器获取状态并执行相应命令。适合保护多台服务器。对于绝大多数家庭用户一台群晖NAS连接一台UPS独立模式完全够用配置也最简单。因此我们的探索将围绕独立模式展开。2.3 与DSM的集成策略这是整个项目的灵魂。仅仅运行NUT服务还不够必须让DSM系统知道“哦现在有UPS在保护我并且我应该在电池电量低时安全关机。”状态信息获取我们需要通过NUT的工具如upsc定期获取UPS状态电量、负载、状态等。触发DSM关机流程当NUT监测到电池电量低于阈值或市电中断时间过长时需要触发DSM的标准关机流程而不是简单地执行poweroff命令。DSM有自己的关机脚本和清理流程。状态可视化可选但重要理想情况下我们希望在DSM的控制面板中看到UPS信息。这通常需要修改Web界面难度极大。一个折中的、更可行的方案是通过计划任务或脚本将UPS状态信息写入一个文件然后通过DSM的Web Station搭建一个简单的状态监控页面或者集成到Home Assistant等智能家居平台中。基于以上分析我的技术路线确定为在DSM上通过第三方包管理器安装NUT配置为独立模式并编写自定义脚本桥接NUT事件与DSM系统关机命令。3. 实战部署在DSM上安装与配置NUT注意以下操作涉及SSH登录和命令行修改请确保你熟悉基本Linux操作并在操作前对重要数据进行备份。不同DSM版本和群晖机型可能存在差异请灵活调整。3.1 环境准备开启SSH与安装Entware开启SSH进入DSM控制面板 - 终端机和SNMP - 勾选“启动SSH功能”端口默认22。安装EntwareEntware是一个为嵌入式设备如路由器、NAS优化的软件仓库。我们使用社区提供的脚本来安装。通过SSH客户端如PuTTY、Termius以root用户登录你的群晖NAS。密码与你登录DSM Web界面时的管理员密码相同。执行以下命令一键安装Entware/bin/sh -c $(curl -kfsSL https://raw.githubusercontent.com/Entware/Entware/ng/master/generic.sh)安装完成后更新软件包列表opkg update。将Entware的路径添加到系统环境变量方便后续使用。编辑/root/.profile文件如果不存在就创建echo export PATH/opt/bin:/opt/sbin:$PATH /root/.profile source /root/.profile3.2 安装NUT软件包通过Entware安装NUT及其USB驱动支持opkg install nut nut-common nut-usb安装完成后主要的可执行文件和配置文件会位于/opt/sbin和/opt/etc/nut目录下。3.3 连接并识别UPS将你的UPS通过USB线连接到群晖NAS的USB端口。然后使用lsusb命令查看是否识别到设备lsusb你应该能看到类似Bus 001 Device 003: ID 051d:0002 American Power Conversion UPS的输出。记下ID本例为051d:0002这有助于后续确认驱动。3.4 配置NUT独立模式NUT的配置文件主要位于/opt/etc/nut/目录。我们需要修改三个核心文件。配置驱动 (nut.conf)此文件定义NUT的运行模式。vi /opt/etc/nut/nut.conf将其内容修改为MODEstandalone这表示我们运行在独立模式。配置UPS驱动 (ups.conf)此文件定义如何与你的UPS硬件通信。vi /opt/etc/nut/ups.conf添加你的UPS配置。以我的APC BK650M2为例使用usbhid-ups驱动[apc-ups] driver usbhid-ups port auto desc APC Back-UPS 650M2[apc-ups]给你的UPS实例起个名字后续会用到。driver驱动名。APC的USB UPS大多使用usbhid-ups。其他品牌如CyberPower可能用blazer_usb需要查阅NUT的硬件兼容列表。port设为auto让NUT自动发现USB设备。desc描述信息可选。配置守护进程 (upsd.conf)此文件定义upsd服务监听的网络设置。vi /opt/etc/nut/upsd.conf对于独立模式我们只需要监听本地即可LISTEN 127.0.0.1 34933493是NUT的默认端口。配置用户与权限 (upsd.users)定义可以访问upsd服务的用户。vi /opt/etc/nut/upsd.users添加一个用于本地监控和关机的用户[monuser] password your_secure_password_here upsmon master[monuser]用户名。password设置一个强密码。upsmon master表示此用户具有upsmon进程所需的“master”权限可以执行关机等命令。配置监控客户端 (upsmon.conf)upsmon是监控UPS状态并在必要时采取行动的客户端程序。vi /opt/etc/nut/upsmon.conf添加监控配置MONITOR apc-upslocalhost 1 monuser your_secure_password_here master NOTIFYCMD /opt/etc/nut/notifycmd.sh NOTIFYFLAG ONLINE SYSLOGWALL NOTIFYFLAG ONBATT SYSLOGWALLEXEC NOTIFYFLAG LOWBATT SYSLOGWALLEXEC NOTIFYFLAG FSD SYSLOGWALLEXEC NOTIFYFLAG COMMOK SYSLOGWALL NOTIFYFLAG COMMBAD SYSLOGWALLEXEC SHUTDOWNCMD /opt/sbin/upsmon-shutdown POWERDOWNFLAG /opt/etc/nut/upsmon.powerdownflagMONITOR定义监控哪个UPSapc-upslocalhost1表示一个电源后面是用户名密码和master角色。NOTIFYCMD指定一个自定义通知脚本的路径我们稍后创建。NOTIFYFLAG定义各种事件如在线、转电池、低电量、强制关机FSD触发时的行为写系统日志SYSLOG、发消息给所有用户WALL、执行命令EXEC。SHUTDOWNCMD这是最关键的一行它定义了当需要关机时执行的命令。我们不能直接用/sbin/poweroff必须调用DSM的关机流程。这里指向一个我们即将创建的自定义脚本。POWERDOWNFLAG指定一个标志文件路径用于防止重复关机。3.5 创建关键桥接脚本创建DSM安全关机脚本 (/opt/sbin/upsmon-shutdown)vi /opt/sbin/upsmon-shutdown输入以下内容#!/bin/sh # 记录关机日志 logger -t upsmon UPS requested DSM shutdown via upsmon-shutdown script. # 执行DSM的正常关机命令 /usr/syno/sbin/synopoweroff然后赋予执行权限chmod x /opt/sbin/upsmon-shutdown/usr/syno/sbin/synopoweroff是群晖DSM系统提供的标准关机命令它会执行完整的服务停止、缓存回写等流程比直接poweroff安全得多。创建事件通知脚本 (/opt/etc/nut/notifycmd.sh)这个脚本用于在发生特定事件时执行自定义操作比如发送邮件通知。vi /opt/etc/nut/notifycmd.sh输入一个基础模板#!/bin/sh # 参数说明: $1 事件类型 $2 UPS名称 logger -t upsmon-notify UPS Event: $1 for UPS $2 # 你可以在这里添加发送邮件、调用Webhook等逻辑 # 例如使用curl调用SendGrid API发邮件或者调用钉钉/企业微信机器人赋予执行权限chmod x /opt/etc/nut/notifycmd.sh3.6 启动NUT服务并设置开机自启首次启动与测试启动UPS驱动/opt/sbin/upsdrvctl start启动upsd守护进程/opt/sbin/upsd启动upsmon监控客户端/opt/sbin/upsmon可以使用ps aux | grep ups查看进程是否运行。测试查询UPS状态/opt/bin/upsc apc-upslocalhost如果配置正确你会看到一长串UPS的实时数据包括battery.charge: 100 battery.runtime: 1800 input.voltage: 220.0 output.voltage: 220.0 ups.status: OLOL表示在线On LineOB表示使用电池On Battery。模拟断电测试非常重要在确保所有重要数据已保存的前提下可以安全地拔掉UPS的市电插头。观察系统日志tail -f /var/log/messages你应该会看到upsmon检测到ONBATT事件并开始记录电池剩余时间和电量。重新插上市电观察是否恢复OL状态。暂时不要测试低电量关机等一切稳定后再进行。配置开机自启 为了让NUT在NAS重启后自动运行我们需要创建自启动脚本。在DSM中可以通过创建自定义rc脚本实现。vi /usr/local/etc/rc.d/S99nut.sh输入以下内容#!/bin/sh case $1 in start) echo Starting NUT services... /opt/sbin/upsdrvctl start sleep 2 /opt/sbin/upsd sleep 2 /opt/sbin/upsmon ;; stop) echo Stopping NUT services... /opt/sbin/upsmon -c stop sleep 2 /opt/sbin/upsd -c stop sleep 2 /opt/sbin/upsdrvctl stop ;; *) echo Usage: $0 {start|stop} exit 1 ;; esac exit 0赋予执行权限chmod x /usr/local/etc/rc.d/S99nut.sh现在你可以用/usr/local/etc/rc.d/S99nut.sh start和stop来管理服务并且下次NAS重启时NUT会自动启动。4. 高级集成与状态可视化方案基础功能实现后我们可以追求更优雅的集成。毕竟每次SSH敲命令查状态太不“群晖”了。4.1 创建Web状态监控页面我们可以利用群晖自带的Web Station套件创建一个简单的PHP页面来实时显示UPS状态。确保Web Station和PHP已安装在套件中心安装“Web Station”并启用PHP支持如PHP 7.4。在Web目录创建页面例如在/var/services/web/ups/目录下创建index.php。?php header(Content-Type: text/plain; charsetutf-8); // 执行upsc命令获取状态 $ups_name apc-upslocalhost; $command /opt/bin/upsc $ups_name 21; $output shell_exec($command); if ($output null) { echo 无法获取UPS状态。请检查NUT服务是否运行。\n; exit; } echo UPS 实时状态 \n; echo 更新时间: . date(Y-m-d H:i:s) . \n\n; echo $output; // 可以解析$output提取关键信息如battery.charge, ups.status用更美观的HTML展示 ?通过浏览器访问打开http://你的NAS地址/ups/就能看到一个纯文本的状态页。你可以进一步用HTML/CSS美化它做成一个仪表盘。4.2 集成到Home Assistant如果你使用Home Assistant进行智能家居管理将UPS状态接入其中能实现更强大的自动化比如电量低于20%时向手机发送紧急通知并自动暂停所有下载任务。在Home Assistant的configuration.yaml中添加NUT集成nut: - name: my_nas_ups host: 你的群晖NAS的IP地址 port: 3493 username: monuser password: your_secure_password_here resources: - ups.status - battery.charge - battery.runtime - input.voltage - output.voltage重启Home Assistant后你就能在实体列表中看到sensor.my_nas_ups_status等传感器并可以用于创建自动化。4.3 自定义DSM任务计划进行状态日志与告警利用DSM控制面板中的“任务计划”我们可以定期检查UPS状态并执行告警。创建一个“用户定义的脚本”计划任务比如每5分钟运行一次。脚本内容示例#!/bin/bash STATUS$(/opt/bin/upsc apc-upslocalhost ups.status 2/dev/null) CHARGE$(/opt/bin/upsc apc-upslocalhost battery.charge 2/dev/null) RUNTIME$(/opt/bin/upsc apc-upslocalhost battery.runtime 2/dev/null) if [ $STATUS OB ]; then # 正在使用电池 echo 警告NAS正在使用UPS电池供电当前电量 ${CHARGE}%预计运行时间 ${RUNTIME}秒。 | \ /usr/bin/php /volume1/homes/admin/send_mail.php UPS电池供电告警 fi if [ -n $CHARGE ] [ $CHARGE -lt 30 ]; then # 电池电量低于30% echo 紧急UPS电池电量低至 ${CHARGE}%请立即处理。 | \ /usr/bin/php /volume1/homes/admin/send_mail.php UPS电量低紧急告警 fi这个脚本会在市电断开状态为OB或电量过低时调用一个PHP脚本发送邮件。你需要事先配置好PHP的邮件发送功能如使用SMTP。5. 避坑指南与疑难问题排查在实际操作中我踩过不少坑。这里把常见问题和解决方案记录下来希望能帮你节省时间。5.1 驱动识别失败upsc命令无输出或报错现象执行upsc apc-upslocalhost后长时间无响应或提示Error: Driver not connected。排查检查USB连接与权限运行lsusb确认UPS已被系统识别。然后检查/dev下是否有相关的USB设备节点如/dev/usb/hiddev0。确保nut用户或root有访问权限。有时需要修改/opt/etc/nut/ups.conf中的port为具体设备路径如port /dev/usb/hiddev0。检查驱动是否匹配访问NUT官网的硬件兼容列表确认你的UPS型号对应的正确驱动名。APC的很多型号都用usbhid-ups但有些老型号可能需要apcsmart串口或apcupsd-ups通过apcupsd守护进程桥接。查看驱动日志启动驱动时加上调试参数/opt/sbin/upsdrvctl -D start观察终端输出看是否有权限错误或通信失败信息。尝试其他驱动对于某些国产或较新的UPSblazer_usb驱动可能兼容性更好。可以在ups.conf中将driver改为blazer_usb试试。5.2upsmon无法启动提示“Invalid password”或“Access denied”现象启动upsmon时失败系统日志/var/log/messages中有认证错误。排查核对用户名密码确保upsd.users文件中定义的用户名、密码与upsmon.conf中的MONITOR行完全一致包括大小写。检查文件权限确保/opt/etc/nut/目录下的配置文件特别是upsd.users权限正确upsd进程能够读取。通常nut用户需要读权限。可以运行chown -R nut:nut /opt/etc/nut/和chmod 640 /opt/etc/nut/*.conf试试。重启upsd修改upsd.users后需要重启upsd服务/opt/sbin/upsd -c stop然后/opt/sbin/upsd才能使新的用户配置生效。5.3 断电测试时NAS没有正常关机现象拔掉市电后UPS电池耗尽NAS直接硬关机。排查检查upsmon进程确保upsmon正在运行ps aux | grep upsmon。检查事件触发查看系统日志tail -f /var/log/messages拔电后是否出现了ONBATT和LOWBATT事件最终是否有FSDForced Shutdown事件。如果没有FSD可能是upsmon.conf中的NOTIFYFLAG配置或电池阈值设置有问题。检查SHUTDOWNCMD脚本这是最关键的一步。手动执行你的/opt/sbin/upsmon-shutdown脚本看是否能正常触发DSM关机。确保脚本有执行权限chmod x并且其中的/usr/syno/sbin/synopoweroff路径在你的DSM上确实存在。检查upsmon的权限upsmon需要以root权限运行才能执行关机命令。确保你的启动脚本如S99nut.sh是以root身份执行的。5.4 群晖系统更新后NUT服务失效现象DSM系统升级后NUT服务无法启动或USB设备无法识别。解决方案Entware环境恢复DSM大版本更新可能会重置系统环境。SSH登录后重新执行source /root/.profile加载Entware路径或重新运行Entware安装脚本的“修复”部分。驱动重新编译罕见极少数情况下内核更新可能导致预编译的驱动模块不兼容。此时需要尝试通过Entware重新安装NUTopkg upgrade nut nut-usb或者寻找针对新内核的社区编译版本。自启动脚本检查检查/usr/local/etc/rc.d/S99nut.sh是否还在权限是否正常。DSM更新有时会清理/usr/local/etc/rc.d/目录。5.5 如何安全地移除或卸载NUT如果你后续想改用官方支持的UPS或Docker方案需要干净地移除当前安装。停止服务/usr/local/etc/rc.d/S99nut.sh stop删除自启动脚本rm /usr/local/etc/rc.d/S99nut.sh通过Entware卸载opkg remove nut nut-common nut-usb可选清理配置目录rm -rf /opt/etc/nut/整个探索过程下来最大的体会是“自由”与“责任”并存。通过NUT我们打破了厂商锁定的壁垒让老设备焕发新生获得了极其丰富的监控和控制能力。但这也意味着所有的稳定性、安全性都需要自己来保障。从驱动调试、脚本编写到最后的断电模拟测试每一个环节都需要耐心和严谨。当最终在自制的小网页上看到UPS的实时参数或者在Home Assistant里收到低电量推送时那种成就感远非插上即用的官方方案所能比拟。这不仅仅是一个UPS的接入更是一次对自家数据中心基础设施的深度理解和掌控。对于爱折腾的NAS玩家来说这个过程本身就是最大的乐趣所在。
返回列表