Как настроить центральный менеджмент сервер для ИБП?

Цель и необходимость

Как только у Вас появился сервер, то сразу появляется вопрос в его поддержке. Один из основных вопросов связан с бесперебойной поставкой электричества к серверу. С этим вопросом помогает UPS (далее ИПБ), но есть проблема со штатным выключением сервера, так как в случае продолжительного отключения электричества вместе с ИПБ выключается и сервер (не в штатном режиме). В этом случае существует вероятность потери данных, сбоях в работе ОС и программ. Для решения этого вопроса будем использовать NUT + автоматизации.

Network UPS Tools (NUT) - это набор программных компонентов, предназначенный для мониторинга питания, таких как бесперебойные источники питания, блоки распределения питания, солнечные контроллеры и блоки питания серверов.

- wikipedia

Модели ИПБ

Поддерживаемые модели устройств в NUT можно увидеть тут. Нашел бюджетный вариант в списке и в магазине (ИБП DEXP MIX 850VA).

Proxmox

  1. Отключаем от USB ИПБ и выполняем: lsusb

  2. Подключаем ИПБ по USB и потом снова выполняем: lsusb. Таким образом, видим новое устройство. В моем случае это Fry's Electronics (неожиданно :)):

Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 002: ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 0001:0000 Fry's Electronics
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
  1. Смотрим детальную информацию, указав bus и device, и выполнив lsusb -v -s 1:3:

Bus 001 Device 003: ID 0001:0000 Fry's Electronics
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x0001 Fry's Electronics
  idProduct          0x0000
  bcdDevice            1.00
  iManufacturer           0
  iProduct                1
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0029
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      0
      iInterface              0
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     624
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
Device Status:     0x0000
  (Bus Powered)
  1. Устанавливаем nut: apt install nut -y.

  2. Проверяем видит ли nut наш ИПБ, выполняем nut-scanner -U:

Scanning USB bus.
[nutdev1]
        driver = "nutdrv_qx"
        port = "auto"
        vendorid = "0001"
        productid = "0000"
        bus = "001"
  1. Делаем backup конфигов nut:

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 /etc/nut/upssched-cmd /etc/nut/upssched-cmd.example
  1. Редактриуем /etc/nut/nut.conf, удаляем все и добавляем через nano /etc/nut/nut.conf:

MODE=netserver
  1. Редактируем ups.conf, удаляем все и добавляем через nano /etc/nut/ups.conf:

pollinterval = 15
maxretry = 3

offdelay = 120
ondelay = 240

[dexp]
   driver=blazer_usb
   port=auto
   desc="DEXP MIX 850VA"
   vendorid=0001
   productid=0000
   default.battery.voltage.high=2.27
   default.battery.voltage.low=1.72
   runtimecal=240,100,720,50
   chargetime=43200
   idleload=1%
   langid_fix=0x0409

и выполняем upsdrvctl stop && upsdrvctl start:

Network UPS Tools - UPS driver controller 2.8.0
Network UPS Tools - UPS driver controller 2.8.0
Network UPS Tools - Megatec/Q1 protocol USB driver 0.14 (2.8.0)
Please note that this driver is deprecated and will not receive
new development. If it works for managing your devices - fine,
but if you are running it to try setting up a new device, please
consider the newer nutdrv_qx instead, which should handle all 'Qx'
protocol variants for NUT. (Please also report if your device works
with this driver, but nutdrv_qx would not actually support it with
any subdriver!)

Supported UPS detected with megatec protocol
Vendor information read in 1 tries

Проверяем работу /lib/nut/blazer_usb -DDD -a dexp:

Network UPS Tools - Megatec/Q1 protocol USB driver 0.14 (2.8.0)
   0.000000     [D3] do_global_args: var='pollinterval' val='15'
   0.000014     [D3] do_global_args: var='maxretry' val='3'
   0.000019     [D3] do_global_args: var='offdelay' val='120'
   0.000024     [D3] do_global_args: var='ondelay' val='240'
   0.000031     [D3] main_arg: var='desc' val='dexp'
   0.000036     [D3] main_arg: var='port' val='auto'
   0.000044     [D3] main_arg: var='driver' val='blazer_usb'
   0.000053     [D3] main_arg: var='default.battery.voltage.high' val='2.27'
   0.000060     [D3] main_arg: var='default.battery.voltage.low' val='1.72'
   0.000067     [D3] main_arg: var='runtimecal' val='240,100,720,50'
   0.000075     [D3] main_arg: var='langid_fix' val='0x0409'
   0.000082     [D3] main_arg: var='vendorid' val='0001'
   0.000090     [D3] main_arg: var='productid' val='0000'
   0.000097     [D3] main_arg: var='chargetime' val='43200'
   0.000105     [D3] main_arg: var='idleload' val='1%'
   0.000115     [D1] debug level is '3'
   0.000956     [D2] language ID workaround enabled (using '0x409')
   0.004633     [D2] Checking device 1 of 7 (1D6B/0003)
   0.004656     [D1] Failed to open device (1D6B/0003), skipping: Access denied (insufficient permissions)
   0.004663     [D2] Checking device 2 of 7 (1D6B/0104)
   0.004672     [D1] Failed to open device (1D6B/0104), skipping: Access denied (insufficient permissions)
   0.004678     [D2] Checking device 3 of 7 (1D6B/0002)
   0.004687     [D1] Failed to open device (1D6B/0002), skipping: Access denied (insufficient permissions)
   0.004692     [D2] Checking device 4 of 7 (1D6B/0003)
   0.004700     [D1] Failed to open device (1D6B/0003), skipping: Access denied (insufficient permissions)
   0.004705     [D2] Checking device 5 of 7 (0001/0000)
   0.006938     [D1] nut_libusb_open get iProduct failed, retrying...
   0.010937     [D1] nut_libusb_open get iProduct failed, retrying...
   0.014932     [D1] nut_libusb_open get iProduct failed, retrying...
   0.014939     [D2] - VendorID: 0001
   0.014944     [D2] - ProductID: 0000
   0.014949     [D2] - Manufacturer: unknown
   0.014955     [D2] - Product: unknown
   0.014960     [D2] - Serial Number: unknown
   0.014965     [D2] - Bus: 001
   0.014970     [D2] - Device: unknown
   0.014976     [D2] - Device release number: 0100
   0.014981     [D2] Trying to match device
   0.014986     [D3] match_function_regex: matching a device...
   0.015021     [D2] Device matches
   0.015026     [D2] Reading first configuration descriptor
   0.015034     [D3] libusb_kernel_driver_active() returned 0
   0.015051     [D2] Claimed interface 0 successfully
   0.015055     [D3] nut_usb_set_altinterface: skipped libusb_set_interface_alt_setting(udev, 0, 0)
   0.018941     Please note that this driver is deprecated and will not receive
new development. If it works for managing your devices - fine,
but if you are running it to try setting up a new device, please
consider the newer nutdrv_qx instead, which should handle all 'Qx'
protocol variants for NUT. (Please also report if your device works
with this driver, but nutdrv_qx would not actually support it with
any subdriver!)

   0.018955     [D2] Trying megatec protocol...
   0.018963     [D3] send: Q1
   0.023956     [D1] received 96 (96)
   0.023963     [D3] read: (228.0 000.0 228.0 020 50.1 13.5 29.0 00001000
   0.023987     [D2] Status read in 1 tries
   0.023993     Supported UPS detected with megatec protocol
   0.023998     [D3] send: F
   0.027950     [D1] received 46 (46)
   0.027957     [D3] read: #   .   .  12.00   .
   0.027967     [D2] Ratings read in 1 tries
   0.027972     [D3] send: I
   0.032940     [D1] received 80 (80)
   0.032948     [D3] read: #                           V3.8
   0.032956     Vendor information read in 1 tries
   0.032969     [D2] battery runtime exponent : 1.585
   0.032977     [D2] battery runtime nominal  : 240.0
   0.032981     [D2] battery runtime estimate : 240.0
   0.032986     [D2] battery charge time      : 43200
   0.032992     [D2] minimum load used (idle) : 0.010
   0.032999     [D3] send: Q1
   0.037961     [D1] received 96 (96)
   0.037969     [D3] read: (228.0 000.0 228.0 020 50.1 13.5 29.0 00001000
   0.038021     [D2] dstate_init: sock /run/nut/blazer_usb-dexp open on fd 9
   0.038033     [D3] send: Q1
   0.042937     [D1] received 96 (96)
   0.042943     [D3] read: (228.0 000.0 228.0 020 50.1 13.5 29.0 00001000
  15.047969     [D3] send: Q1
  15.051805     [D1] received 96 (96)
  15.051815     [D3] read: (228.0 000.0 228.0 021 50.3 13.5 29.0 00001000
  30.056076     [D3] send: Q1
  30.059683     [D1] received 96 (96)
  30.059692     [D3] read: (228.0 000.0 229.0 020 49.9 13.5 29.0 00001000
  1. Редактируем upsd.conf через nano /etc/nut/upsd.conf и вставляем:

LISTEN 0.0.0.0 3493
LISTEN :: 3493

Теперь сервер может отвечать на запросы из всех сетей.

  1. Редактируем 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

******** - заменяем на наши пароли.

  1. Редактируем upsmon.conf через nano /etc/nut/upsmon.conf. Удаляем все и вставляем:

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

MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h"
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

******* - заменяем на пароль upsadmin.

  1. Перезагружаем сервисы:

service nut-server restart
service nut-client restart
systemctl restart nut-monitor
upsdrvctl stop
upsdrvctl start
  1. Тестируем соединение upsc dexp@localhost:

Init SSL without certificate database
battery.charge: 100
battery.runtime: 2645
battery.voltage: 13.60
battery.voltage.high: 2.27
battery.voltage.low: 1.72
battery.voltage.nominal: 12.0
device.mfr:
device.model:
device.type: ups
driver.name: blazer_usb
driver.parameter.chargetime: 43200
driver.parameter.idleload: 1%
driver.parameter.langid_fix: 0x0409
driver.parameter.pollinterval: 15
driver.parameter.port: auto
driver.parameter.productid: 0000
driver.parameter.runtimecal: 240,100,720,50
driver.parameter.synchronous: auto
driver.parameter.vendorid: 0001
driver.version: 2.8.0
driver.version.internal: 0.14
driver.version.usb: libusb-1.0.26 (API: 0x1000109)
input.current.nominal: 0.0
input.frequency: 49.9
input.frequency.nominal: 0
input.voltage: 229.0
input.voltage.fault: 0.0
input.voltage.nominal: 0
output.voltage: 228.0
ups.beeper.status: disabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: V3.8
ups.load: 22
ups.mfr:
ups.model:
ups.productid: 0000
ups.status: OL
ups.temperature: 29.0
ups.type: offline / line interactive
ups.vendorid: 0001

Значение ups.status:

  • OL — система работает от сети;

  • OB — система работает от батареи;

  • LB — система работает от разряженной батареи.

Смотрим какие команды доступны upscmd -l dexp@localhost:

Instant commands supported on UPS [dexp]:

beeper.toggle - Toggle the UPS beeper
load.off - Turn off the load immediately
load.on - Turn on the load immediately
shutdown.return - Turn off the load and return when power is back
shutdown.stayoff - Turn off the load and remain off
shutdown.stop - Stop a shutdown in progress
test.battery.start - Start a battery test
test.battery.start.deep - Start a deep battery test
test.battery.start.quick - Start a quick battery test
test.battery.stop - Stop the battery test

Значение:

  • beeper.* - управляют сигналом ИБП в случае потери напряжения в сети

  • load.off - выключает ПК немедленно;

  • load.off.delay - задержка в секундах до выключения ПК;

  • shutdown.stop — команда прерывания процесса отключения ПК.

Для примера выключим сигнал ИБП, когда пропадает питание в сети:

upscmd -u upsmonitor -p UPSPASS dexp@localhost beeper.disable

Чтобы включить, заменяем beeper.disable на beeper.enable.

Для отключения самого сервера Proxmox нам потребуется новый пользователь, который имеет ограниченный набор прав. Создадим его :) Создаем роль homeassistant с правами auditor:

Создаем пользователя:

Чтобы добавить возможность управления питанием нам необходимо создать роль с правами Sys.PowerMgmt:

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

Homeassistant

Для мониторинга используем Homeaasistant, в частности устанавливаем интеграцию Network UPS Tools (NUT). |800 Здесь интересен объект «Dexp Заряд аккумулятора» (sensor.dexp_battery_charge), так как показывает на сколько % заряжен аккумулятор. По моим тестам ИПБ выключается при уровне 27%, поэтому для себя выделил границу 40%, ниже которой стоит отключать сервер.

Для выключения Proxmox в файл configuration.yaml добавляем следующий код:

shell_command:
  shutdown_proxmox: "curl 'https://<IP>:8006/api2/extjs/nodes/proxmox/status' -H 'Authorization: PVEAPIToken=<user>!<token_id>=<token>' -H 'Content-Type: application/x-www-form-urlencoded' --data 'command=shutdown' --insecure"

где:

  1. IP- ip-адрес Proxmox.

  2. user - пользователь, под которым будут выполняться команды, например, homeassistant@pve.

  3. token_id - id товена, например, homeassistant.

  4. token - значение нашего токена. Проверяем конфигурацию на наличие ошибок и исправляем их. Затем перезагружаем Homeassistant. Если всё верно сделали, то в разделе Developer mode, в сервисах можно будет найти новый элемент: shell_command.shutdown_proxmox.

Автоматизацию делаем следующим образом:

alias: server_turn_off
description: Выключение сервера, если заряд батареи опускается ниже x%
triggers:
  - type: battery_level
    device_id: afc1912c3576ace3ede796bc926d635c
    entity_id: 2579f34021ac5593a876c6915131e7cb
    domain: sensor
    trigger: device
    below: 40
conditions: []
actions:
  - action: shell_command.shutdown_proxmox
    metadata: {}
    data: {}
mode: single

Если коротко, то в случае снижения заряда батареи ниже 40% отправляем команду в Proxmox для выключения.

Автовключение

Для автоматизации включения ПК при появлении питания в сети включаем в BIOS данную функцию. У меня эта функция находится тут:

Итог

В итоге в случае отключения электричества наш сервер в рабочем порядке корректно завершит свою работу и выключится + всегда возможно ключить автовключение. Работу ИПБ мы также можем проконтролировать с помощью dashboard в Homeassistant.

Ссылки:

  1. Как установить Proxmox?

  2. Зачем нужен собственный сервер в 2025?