Proxmox
March 21

Настройка NUT + Proxmox + Synology

У меня в Proxmox развернут DSM (XPEnology). Я недавно переехал и сейчас тут периодические проблемы с электричеством, которые у меня ранее не возникали. Приобрел 1 из доступных ИБП - CyberPower UT850EIG c IEC розетками.

После прочтения двух статей была найдена интересная реализация, которую я успешно применил на своем сервере.

В целом, как показала практика, любой UPS с USB можно подружить с Proxmox и прокинуть в DSM как ИБП Synology, несмотря на отсутствие поддержки ИБП в списке моделей для Synology.

Суть реализации в настройке NUT сервера и клиента прямо на машине с Proxmox для контроля ИБП и поведения при изменении статуса батарей. Дополнительно же установим LXC контейнер с NUT клиентом и веб-сервером Apache для мониторинга состояния ИБП без использования консоли. В конце добавим ИБП в Synology.

Настройка NUT сервера и клиента на сервере с Proxmox

Заходим в консоль машины, на которой установлен Proxmox (в моем случае версии 8.3.0) и смотрим список usb устройств командой:

lsusb

Нам нужно найти наш ИБП и узнать его bus и device:

Теперь посмотрим детальную информацию, указав bus и device, в моем случае:

lsusb -v -s 3:5

где 3 - шина (bus), 5 - устройство (device)

Как видно, система распознает ИБП и можно приступать к установке nut:

apt install nut -y

Проверяем, видит ли nut наш ИБП:

nut-scanner -U

Перед правкой конфигов, на всякий случай, лучше сделать резервные копии всех этих файлов:

cp /etc/nut/nut.conf /etc/nut/nut.example.conf
cp /etc/nut/ups.conf /etc/nut/ups.example.conf
cp /etc/nut/upsd.conf /etc/nut/upsd.example.conf
cp /etc/nut/upsd.users /etc/nut/upsd.example.users
cp /etc/nut/upsmon.conf /etc/nut/upsmon.example.conf
cp /etc/nut/upssched.conf /etc/nut/upssched.example.conf
cp /bin/upssched-cmd /bin/upssched-cmd.example

Теперь перейдем к правке. Первый на очереди nut.conf:

nano /etc/nut/nut.conf

Удаляем все и добавляем:

MODE=netserver

Далее редактируем ups.conf:

nano /etc/nut/ups.conf

Удаляем все и добавляем:

# pollinterval и maxretry работают вместе для надежного мониторинга
# Определяет частоту опроса состояния ИБП (в секундах)
pollinterval = 15
# Количество попыток повторного подключения к ИБП при потере связи
# Если после 3 попыток связь не восстановится, система считает ИБП недоступным
maxretry = 3

# offdelay и ondelay образуют временную защиту для процессов выключения/включения
# Задержка перед фактическим выключением питания после команды на shutdown (в секундах)
# Это время дается системе на:
#     Корректное завершение работы всех служб
#     Сохранение данных
#     Выполнение процедур очистки
offdelay = 300
# Задержка перед включением питания после восстановления основного электропитания (в секундах)
# Это предотвращает:
#     Многократные циклы включения/выключения при нестабильном питании
#     Слишком быстрое включение до полной стабилизации напряжения
ondelay = 30

[ups]
   driver = usbhid-ups
   port = auto
   desc = "CyberPower UT850EG"
   vendorid = 0764
   productid = 0501
   serial = ""

Обратите внимание, что все данные по своему ИБП я брал из вывода команд, указанных выше. В квадратных скобках имя ups оставляем как есть для Synology.

Необходимо настроить файл ups.conf на сервере NUT, чтобы ИБП назывался «ups». Он не может называться как-то иначе. В противном случае Synology откажется подключаться.

Сохраняем файл и можем протестировать драйвер:

upsdrvctl start

Если что-то неверно распознается, проверьте список совместимого оборудования чтобы узнать, какой драйвер использовать.

Отредактируем upsd.conf:

nano /etc/nut/upsd.conf

Дадим указание серверу отвечать на запросы из всех сетей. Удаляем все и добавляем:

LISTEN 0.0.0.0 3493
LISTEN :: 3493

Далее редактируем upsd.users:

nano /etc/nut/upsd.users

Настроим администратора и пользователя. Удаляем все и добавляем:

[upsadmin]
# Administrative user
password = ********
# Allow changing values of certain variables in the UPS.
actions = SET
# Allow setting the "Forced Shutdown" flag in the UPS.
actions = FSD
# Allow all instant commands
instcmds = ALL
upsmon master

[upsuser]
# Normal user
password = ********
upsmon slave

[monuser]
# DSM user
password = secret
admin slave
Нужно создать пользователя на сервере NUT (в uspd.users) с именем «admin» и паролем «secret». Я безуспешно пытался подключить Synology к серверу NUT, используя менее очевидное имя пользователя и сложный пароль, но безрезультатно.

Замените звездочки на ваши пароли.

Редактируем upsmon.conf:

nano /etc/nut/upsmon.conf

Удаляем все и добавляем:

RUN_AS_USER root
MONITOR ups@localhost 1 upsadmin ******* master

MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h now"
NOTIFYCMD /usr/sbin/upssched
POLLFREQ 4
POLLFREQALERT 2
HOSTSYNC 15
DEADTIME 24
MAXAGE 24
POWERDOWNFLAG /etc/killpower

NOTIFYMSG ONLINE "UPS %s on line power"
NOTIFYMSG ONBATT "UPS %s on battery"
NOTIFYMSG LOWBATT "UPS %s battary is low"
NOTIFYMSG FSD "UPS %s: forced shutdown in progress"
NOTIFYMSG COMMOK "Communications with UPS %s established"
NOTIFYMSG COMMBAD "Communications with UPS %s lost"
NOTIFYMSG SHUTDOWN "Auto logout and shutdown proceeding"
NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced"
NOTIFYMSG NOCOMM "UPS %s is unavailable"
NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible"

NOTIFYFLAG ONLINE   SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT   SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT  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
NOTIFYFLAG NOCOMM   SYSLOG+WALL+EXEC
NOTIFYFLAG NOPARENT SYSLOG+WALL

RBWARNTIME 43200
NOCOMMWARNTIME 600

FINALDELAY 5

Не забудьте заменить звездочки на ваш пароль администратора во второй строчке.

Редактируем upssched.conf:

nano /etc/nut/upssched.conf

Удаляем все и добавляем:

CMDSCRIPT /bin/upssched-cmd
PIPEFN /etc/nut/upssched.pipe
LOCKFN /etc/nut/upssched.lock

AT ONBATT * START-TIMER shutdown_proxmox 100
AT ONLINE * CANCEL-TIMER shutdown_proxmox online
AT LOWBATT * EXECUTE shutdown_proxmox
AT COMMBAD * START-TIMER commbad 30
AT COMMOK * CANCEL-TIMER commbad commok
AT NOCOMM * EXECUTE commbad
AT SHUTDOWN * EXECUTE shutdown_proxmox
START-TIMER shutdown_proxmox 120 — запускает таймер на 2 минуты для выключения Proxmox после перехода на батарею.
CANCEL-TIMER shutdown_proxmox online — отменяет таймер, если питание восстановилось до истечения времени.
EXECUTE shutdown_proxmox — немедленно выполняет выключение при критическом уровне заряда батареи или других событиях.

Как это будет работать?

  1. Переход на батарею:
    • Когда ИБП переходит на батарею (ONBATT), запускается таймер на 2 минуты.
    • Если за это время питание не восстановится, через 2 минуты выполнится команда shutdown_proxmox.
  2. Восстановление питания:
    • Если питание восстановится до истечения 2 минут, таймер будет отменен, и система продолжит работу.
  3. Критический уровень батареи:
    • Если батарея разрядится до критического уровня, выполнится немедленное выключение.
  4. Потеря связи с ИБП:
    • Если связь с ИБП потеряна более чем на 30 секунд, система также выполнит выключение.

Нужно убедиться, что PIPEFN и LOCKFN указывают на существующую директорию. У меня ее не было, поэтому я ее создал.

mkdir /etc/nut/upssched/

Редактируем upssched-cmd:

nano /bin/upssched-cmd

Удаляем все и добавляем:

#!/bin/bash

case $1 in
    shutdown_proxmox)
        logger -t upssched-cmd "UPS on battery too long — shutting down Proxmox"
        /sbin/shutdown -h now
        ;;
    *)
        logger -t upssched-cmd "Unknown command from upssched: $1"
        ;;
esac
При получении команды shutdown_proxmox система логгирует сообщение и выполняет выключение командой /sbin/shutdown -h now.

Сохраняем, затем предоставляем права:

chmod +x /bin/upssched-cmd

Осталось перезагрузить систему, или, если нет такой возможности, перезагрузить сервисы командами:

systemctl restart nut-server
systemctl restart nut-client
systemctl restart nut-monitor
upsdrvctl stop
upsdrvctl start

После перезагрузки выполняем команду:

upsc ups@localhost

и смотрим, показана ли информация о нашем ИБП:

Проверяем, какие значения мы можем записывать

upscmd -l ups@localhost

В моем ИБП не оказалось возможности аппаратно записать значения минимального времени работы (200 секунд) и заряда (50%), но оставлю эти команды тут:

upsrw -s battery.runtime.low=200 ups@localhost
upsrw -s battery.charge.low=50 ups@localhost
После ввода каждой команды будет запрошен логин и пароль, используйте логин upsadmin и пароль, который вы указывали при редактировании /etc/nut/upsmon.conf и /etc/nut/upsd.users. После ввода команд система будет возвращать ОК, даже если изменения нельзя записать.
Перезагружаем сервисы/сервер.
Эти команды не настраивают автоматическое отключение хоста, а задаются критические значения для самого ИБП.
Так же, я заметил, что на моем ИБП нет возможности изменить параметр battery.charge.low. Рекомендую проверить изменения предыдущей командой, которая выводит ваши значения по ИБП.

Однако, можно программно записать значения в ups.conf, добавив мониторинг нагрузки через override:

nano /etc/nut/ups.conf
override.battery.charge.low = 50
override.battery.runtime.low = 200

Тогда содержимое ups.conf будет выглядеть так:

pollinterval = 15
maxretry = 3

offdelay = 300
ondelay = 30

[ups]
   driver = usbhid-ups
   port = auto
   desc = "CyberPower UT850EG"
   vendorid = 0764
   productid = 0501
   serial = ""
   override.battery.charge.low = 50
   override.battery.runtime.low = 200

После внесения изменений проверяем той же командой:

upsc ups@localhost

И видим, что конфиг применился.

Как это вообще все работает?

Да я сам не сразу понял.

Порядок приоритетов работы системы:

1. Сначала проверяются override параметры:

  • override.battery.charge.low (50%)
  • override.battery.runtime.low (200 секунд)

2. Потом срабатывают таймеры из upssched.conf:

  • AT ONBATT запускает таймер на 120 секунд
  • AT LOWBATT может прервать процесс раньше

3. В конце учитываются временные задержки:

  • offdelay (300 секунд) - должно быть ≥ времени таймера
  • ondelay (30 секунд)

Рекомендации по согласованию значений:

  1. override.battery.runtime.low ≤ offdelay
  2. таймер в AT ONBATT ≤ override.battery.runtime.low
  3. override.battery.charge.low < override.battery.runtime.low

Создание и настройка LXC контейнера для мониторинга ИБП

В принципе, на стороне сервера уже все настроено и сервер будет отключаться в соответствии с настройками NUT, но для удобства можно настроить веб страничку с данными об ИБП. Я это сделал в отдельном LXC контейнере.

Характеристики: 1 ядро, 128мб ОЗУ, 2гб диск, ubuntu 24.04, автозапуск контейнера при загрузке.

Первым делом, после запуска контейнера, заходим в его консоль и выполняем обновление:

apt update && apt upgrade -y

Затем ставим openssh-server.

apt install openssh-server -y

Далее изменим конфиг

nano /etc/ssh/sshd_config

Нужно раскомментировать или добавить следующие строчки:

PasswordAuthentication yes
PermitRootLogin yes

Сохраняем и перезапускаем openssh сервер:

systemctl restart ssh

Установим веб-сервер Apache, nut-cgi и nut клиент:

apt install apache2 nut-cgi nut-client -y

Сразу сделаем резервные копии всех редактируемых конфигов:

cp /etc/nut/nut.conf /etc/nut/nut.example.conf
cp /etc/nut/hosts.conf /etc/nut/hosts.example.conf
cp /etc/nut/upsset.conf /etc/nut/upsset.example.conf
cp /etc/nut/upsmon.conf /etc/nut/upsmon.example.conf

Редактируем /etc/nut/nut.conf:

nano /etc/nut/nut.conf

Удаляем все и добавляем:

MODE=netclient

Далее редактируем /etc/nut/hosts.conf:

nano /etc/nut/hosts.conf

Удаляем все и добавляем:

MONITOR ups@xxx.xxx.xxx.xxx "CyberPower UT850IEG"

где xxx.xxx.xxx.xxx это ip адрес вашего сервера Proxmox

Редактируем/etc/nut/upsset.conf:

nano /etc/nut/upsset.conf

Удаляем все и добавляем:

I_HAVE_SECURED_MY_CGI_DIRECTORY

Редактируем /etc/nut/upsmon.conf:

nano /etc/nut/upsmon.conf

Добавляем вначале:

RUN_AS_USER root
MONITOR ups@xxx.xxx.xxx.xxx 1 upsuser ******* slave

где xxx.xxx.xxx.xxx это ip адрес вашего сервера Proxmox, а ******** это пароль юзера upsuser, настроенного на сервере с proxmox.

Далее вводим команду:

sudo a2enmod cgi

И перезапускаем веб сервер:

sudo systemctl restart apache2

Теперь можно перейти по адресу http://xxx.xxx.xxx.xxx/cgi-bin/nut/upsstats.cgi где xxx.xxx.xxx.xxx это ip вашего lxc контейнера и мониторить статус ИБП. В моем случае это выглядит так:

Добавление ИБП в Synology

Чтобы все работало, нужно настроить Synology с помощью IP-адреса сервера NUT.

1. Включить функцию UPS support.

2. Выбрать Тип ИБП - Сервер ИБП Synology.

3. Настроить время - совет, ниже, чем на самом хосте.

Указать IP адрес вашего Proxmox.

Напоминаю, что также необходимо было настроить файл ups.conf на сервере NUT, чтобы ИБП назывался «ups». Он не может называться как-то иначе. В противном случае Synology откажется подключаться.
Вам также нужно было создать пользователя на сервере NUT (в uspd.users) с именем «admin» и паролем «secret». Я безуспешно пытался подключить Synology к серверу NUT, используя менее очевидное имя пользователя и сложный пароль, но безрезультатно.

Это не такая серьёзная проблема с точки зрения безопасности, как может показаться, поскольку пользователь «admin» имеет доступ к ИБП только для чтения. Я подтвердил это с помощью:

upscmd -l ups@localhost

Очевидно, что мы не хотим, чтобы любой злоумышленник в сети L3 мог отключить ИБП с помощью простых учётных данных.

upscmd -u admin -p secret ups@localhost shutdown.stayoff

Созданная выше учётная запись суперпользователя может выполнять все эти опасные команды, но встроенная учётная запись Synology не может.

upd. 02.05.2025

Благодаря подписчику переработал конфиги и скрипт, а так же протестировал их работу.

Тестируем аварийное отключение

В самом DSM я выставил таймер на 40 секунд, а для Proxmox 120.

В первом тесте ИБП был без питания 26 секунд. Все системы продолжили работу.

Во втором тесте ИБП был без питания 86 секунд. DSM самостоятельно завершил работу и возобновил после подачи питания. Proxmox при этом считал 120 секунд и продолжил работу.

Третьим тестом будет полное отключение Proxmox спустя 120 секунд

По итогам тестов я выяснил, что аккумулятор в ИБП разряжается до критического состояния с заданными ему максимальными значениями, поэтому занизил их, так как для меня нет необходимости тащить систему на резервном питании, дожидаясь восстановления.
ИБП все же не продовый, а скорее для домашнего использования, чем и является мой хост.
Основной приоритет - безопасное завершение работы.

В 04:32:55 было отключение электричества

В 04:34:25 прошло 90 секунд и proxmox начал останавливать все процессы

В 04:38:41 все процессы были остановлены и система была отключена

Мои финальные параметры в конфигах с таймерами остались такими:

override.battery.runtime.low = 120
override.battery.charge.low = 30
AT ONBATT * START-TIMER shutdown_proxmox 90
offdelay = 300

А что получилось у вас? Делитесь в комментариях.

Мне помогли:

https://kvvhost.ru/2024/07/04/nut-proxmox/

https://blog.zanshindojo.org/nut/