🔌⚡ ИБП + Proxmox: корректное автовыключение через NUT (10 минут ожидания)
В этой заметке я фиксирую рабочую конфигурацию для Proxmox (Debian) и ИБП ExeGate NEO Smart (USB), чтобы при пропадании сети сервер ждал 10 минут, а затем корректно выключался (вместо «аварийного обрыва питания»).
Цель: переживать краткие перебои и запуск генератора, но не разряжать батарею в ноль и не ловить «грязные» выключения. 💾✅
🧠 Логика работы (простая схема)
- ⚡ Пропало питание (ИБП перешёл в
OB— On Battery). - ⏳ Запускается таймер 600 секунд (10 минут).
- 🔁 Если питание вернулось (
ONLINE) — таймер отменяется. - 🛑 Если через 13 минут ИБП всё ещё на батарее (
OB) — сервер выполняет корректный poweroff.
🧩 Почему не «по проценту заряда»? Потому что у бюджетных ИБП оценки времени/заряда могут быть неточными, а таймер + проверка OB — предсказуемо и воспроизводимо.
📦 Что должно быть установлено
- 🧰 NUT (Network UPS Tools):
nut-serverиnut-monitor - 🧪 Для проверки:
upsc,journalctl - 🔐 sudo (для права выключать хост из notify-скрипта)
apt update
apt install -y nut sudo
🔎 Проверка, что ИБП корректно определяется по USB
Прежде чем настраивать NUT, имеет смысл убедиться, что операционная система вообще видит ИБП как USB-устройство. Это позволяет сразу отсечь проблемы с кабелем, портом или питанием.
1️⃣ Проверка через lsusb
Подключаем ИБП по USB и смотрим список USB-устройств:
lsusb
Пример вывода в рабочей конфигурации:
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0557:7000 ATEN International Co., Ltd Hub
Bus 001 Device 003: ID 0665:5161 Cypress Semiconductor USB to Serial
Bus 001 Device 004: ID 0557:2419 ATEN International Co., Ltd Virtual mouse/keyboard device
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
В данном случае ИБП определяется как устройство 0665:5161 (USB to Serial). Это нормально для многих line-interactive ИБП, использующих megatec-совместимый протокол.
⚠️ Если ИБП не появляется в lsusb — дальше идти бессмысленно: проверяем кабель, порт, питание ИБП и сам USB-контроллер.
2️⃣ Сканирование ИБП утилитой nut-scanner
Теперь проверяем, может ли NUT подобрать подходящий драйвер. Используем только USB-сканирование:
nut-scanner -U # Только USB-сканирование
Пример вывода:
Cannot load IPMI library (libfreeipmi.so.17) : file not found. IPMI search disabled.
Scanning USB bus.
[nutdev1]
driver = "nutdrv_qx"
port = "auto"
vendorid = "0665"
productid = "5161"
product = "USB to Serial"
vendor = "WCHCH544"
bus = "001"
device = "003"
busport = "011"
###NOTMATCHED-YET###bcdDevice = "0002"
Ключевые моменты:
- ✅ найдено USB-устройство с тем же
vendorid/productid, что и вlsusb - ✅ NUT предлагает драйвер
nutdrv_qx - ⚠️ пометка
NOTMATCHED-YET— это нормально для недорогих ИБП и не мешает работе
🧠 На практике, если nut-scanner уверенно находит устройство и предлагает драйвер — этого достаточно для корректной работы NUT.
3️⃣ Сканирование ИБП командой upsc ups@localhost
upsc ups@localhost
В норме вы увидите что-то вроде:
- ✅
ups.status: OL— питание от сети (On Line) - ✅
ups.status: OB— питание от батареи (On Battery) - 📊
ups.load: ...— нагрузка по мнению ИБП
🗂️ Итоговая конфигурация файлов NUT
1) /etc/nut/nut.conf 🧩
Режим standalone: монитор и сервер на одной машине.
MODE=standalone
2) /etc/nut/ups.conf 🔌
Пример (драйвер определяется по факту работы у вас; ниже — как было в рабочей конфигурации):
[ups]
driver = nutdrv_qx
port = auto
vendorid = 0665
productid = 5161
protocol = megatec
desc = "ExeGate NEO Smart LHB-1000 USB (Megatec)"
3) /etc/nut/upsd.users 🔐
⚠️ Пароль лучше без символа #, потому что он может ломать разбор строк в конфиге.
[madmentat]
password = XXX
upsmon master
Права на файл (чтобы убрать warning про world readable):
chmod 640 /etc/nut/upsd.users
chown root:nut /etc/nut/upsd.users
4) /etc/nut/upsmon.conf 👀
Минимальный понятный конфиг, плюс уведомления для таймера:
MONITOR ups@localhost 1 madmentat XXX master
POWERDOWNFLAG /etc/killpower
SHUTDOWNCMD "/sbin/shutdown -h now"
NOTIFYCMD /usr/local/sbin/nut-ob-timer.sh
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG ONLINE SYSLOG+EXEC
🧯 Права на выключение (sudoers) 🔐
На практике notify-скрипт запускается не всегда от root, поэтому выключение делаем через sudo без пароля для пользователя nut.
Файл:
/etc/sudoers.d/nut-shutdown
Содержимое (одна строка):
nut ALL=(root) NOPASSWD: /sbin/shutdown
Проверка синтаксиса:
visudo -cf /etc/sudoers.d/nut-shutdown
🧾 Финальная версия скрипта таймера (10 минут) ⏳
Скрипт реагирует на события ONBATT/ONLINE от upsmon. Он ставит таймер на 600 секунд (10 минут) и отменяет его, если питание вернулось.
Файл:
/usr/local/sbin/nut-ob-timer.sh
#!/bin/bash
# nut-ob-timer.sh — скрипт для graceful shutdown через заданное время на батарее
# Обновлённая версия с поддержкой отключения самого ИБП (touch /etc/killpower)
# Автор оригинала: madmentat.ru
# Доработки: добавление POWERDOWNFLAG для отключения UPS после shutdown
TIMER=600 # Время в секундах, после которого выключаем сервер (подстрой под свою батарею)
LOG_TAG="nut-ob-timer" # Тег для journalctl -t nut-ob-timer
UPS_NAME="ups" # Имя UPS из /etc/nut/ups.conf (у тебя [ups])
log() {
echo "$@" | logger -t "${LOG_TAG}"
}
# Проверка, что мы запущены из NOTIFYCMD в upsmon.conf
if [[ -z "$NOTIFYTYPE" ]]; then
log "ERROR: Script not called from upsmon (NOTIFYTYPE missing)"
exit 1
fi
log "Started: NOTIFYTYPE=$NOTIFYTYPE"
# Основная логика — только при переходе на батарею (ONBATT)
if [[ "$NOTIFYTYPE" == "ONBATT" ]]; then
log "UPS switched to battery. Starting ${TIMER}s timer."
sleep "$TIMER"
# Проверяем, всё ли ещё на батарее
if upsc "${UPS_NAME}@localhost" 2>/dev/null | grep -q '^ups.status: .*OB'; then
log "${TIMER}s elapsed and UPS still on battery (OB) — initiating graceful shutdown"
# КЛЮЧЕВАЯ СТРОКА: создаём флаг, чтобы upsmon отключил ИБП после shutdown
touch /etc/killpower
log "Created POWERDOWNFLAG /etc/killpower — UPS will power off outlets after system halt"
# Пробуем systemctl (systemd)
if command -v systemctl >/dev/null 2>&1; then
log "Executing: systemctl poweroff"
systemctl poweroff 2>&1 | while read -r line; do log "systemctl: $line"; done
rc=${PIPESTATUS[0]}
log "systemctl poweroff exit code: $rc"
else
rc=127
log "systemctl not found"
fi
# Если systemctl не сработал — fallback на sudo shutdown
if [[ "${rc:-1}" -ne 0 ]]; then
if command -v sudo >/dev/null 2>&1; then
log "Fallback: executing sudo /sbin/shutdown -h now"
sudo -n /sbin/shutdown -h now "CRITICAL: UPS on battery for ${TIMER}s" \
2>&1 | while read -r line; do log "sudo shutdown: $line"; done
else
log "ERROR: neither systemctl nor sudo available — cannot shutdown"
fi
fi
else
log "${TIMER}s elapsed but UPS no longer on battery (OB flag cleared) — cancelling shutdown"
fi
elif [[ "$NOTIFYTYPE" == "ONLINE" ]]; then
# Если сеть вернулась до истечения таймера — просто логируем
log "UPS returned to line power (ONLINE) — timer cancelled if running"
else
log "Ignored NOTIFYTYPE=$NOTIFYTYPE"
fi
exit 0
Права и применение:
chmod +x /usr/local/sbin/nut-ob-timer.sh
systemctl restart nut-server
systemctl restart nut-monitor
🧪 Проверка работы (быстрый тест) ✅
Чтобы не ждать 13 минут, можно временно поставить TIMER=30, выполнить тест, затем вернуть TIMER=780.
- 👀 Открыть лог в реальном времени:
journalctl -f -t nut-ob-timer - 🔌 Вытащить вилку ИБП из сети 220В (сервер остаётся подключён к ИБП).
- ✅ Убедиться, что появляется
ONBATTи таймер стартует. - 🔁 Вставить вилку обратно — увидеть
ONLINEи отмену таймера.
Также полезно:
upsc ups@localhost | egrep 'ups.status|ups.load|battery.voltage|input.voltage'
🧷 Важный нюанс: автозапуск после выключения 🔁
ИБП обычно не “нажимает кнопку питания” за вас. Чтобы сервер включался сам после возвращения сети, настройте BIOS/UEFI:
- ⚙️ Restore on AC Power Loss / AC Back / Power On after Power Failure → Power On или Last State
🧾 Команды для быстрой диагностики 🧰
- Статус служб:
systemctl status nut-server systemctl status nut-monitor - Журнал уведомлений таймера:
journalctl -t nut-ob-timer -n 200 --no-pager - Проверка прошлого выключения/перезагрузки:
journalctl -b -1 -n 300 --no-pager last -x | head -n 20
✅ Итог
Теперь сервер: ⚡ переживает короткие отключения, ⏳ ждёт 10 минут, 🛑 выключается корректно, 🔁 и может сам включиться при правильной настройке BIOS.
✍️ Примечание: если хочется уменьшить «долгое выключение», обычно это связано с таймаутами остановки ВМ/контейнеров или конкретным гостем, который не реагирует на shutdown. Это отдельная тема для следующей заметки. 🐢➡️🐇
P.S.
По поводу включения обратно - абосрамс💩... Сам ИБП этого не умеет. Стало быть, надо городить какую-то хитровыебанную систему с Wi-Fi розетками и микроконтроллерами... В принципе, хуле там даже думать. Микроконтроллер с Вайфаем есть, БП для него есть, надо только прикупить Wi-Fi реле, чтобы вырубать питание сервере насовсем, после чего он нормально стартанет. И еще надо будет прописать юнит systemd, который запустит уже имеющийся repair-скрипт для поднятия всех контейнеров и ВМ на хосте Proxmox. Говно-вопроса, короче...
...
