Network UPS Tools (NUT) es un conjunto de herramientas de código abierto que nos permite monitorizar y gestionar dispositivos SAI (Sistema de Alimentación Ininterrumpida). Con NUT podemos automatizar el apagado seguro de nuestros sistemas en caso de fallo eléctrico, protegiendo así nuestros datos y hardware.
En este post te explico cómo instalar y configurar NUT en tu servidor, configurar clientes para que reciban notificaciones del estado del SAI e implementar notificaciones por Telegram.
Requisitos
- Un servidor con Debian (o distribuciones derivadas) de 64 bits.
- Un SAI conectado por USB al servidor.
aptcomo gestor de paquetes en tu sistema. Si usas otra distribución, deberás adaptar los comandos conapta tu gestor de paquetes.- Poder ejecutar comandos como
root(ya sea como usuariorootdirectamente, o consudoodoas). En mi caso lo haré comoroot(usandosu). - Comprobar que tu SAI es compatible con NUT en su lista de hardware compatible. Anota el driver recomendado para tu modelo ya que lo necesitaremos más adelante.
- (Opcional) Un bot de Telegram para recibir notificaciones.
Consideraciones a tener en cuenta
-
NUT puede funcionar en diferentes modos:
standalone(para un solo equipo),netserver(para servir información a otros equipos) ynetclient(para recibir información de un servidor NUT). -
Las configuraciones de apagado automático son críticas. Asegúrate de probarlas en un entorno controlado antes de implementarlas en producción.
-
Los valores de batería baja varían según el modelo de SAI. Ajusta los parámetros según las especificaciones del tuyo.
Instalación de NUT
Comenzamos instalando NUT en nuestro servidor. Abrimos una terminal y ejecutamos:
su -
apt install nut
Durante la instalación de nut, también se instalarán los siguientes paquetes:
libnspr4,libnss3,libnutscan2,libupsclient6nut-client,nut-server
Y se sugerirán paquetes adicionales como:
nut-monitor,nut-cgi,nut-i2c,nut-ipmi,nut-modbus,nut-snmp,nut-xml
Importante: A partir de aquí se asume que vamos a trabajar como usuario root. Si usas sudo o doas, añade el prefijo correspondiente a los comandos.
Detectar el SAI
Con NUT instalado, conectamos nuestro SAI por USB al servidor y verificamos que el sistema lo detecta:
lsusb
Para obtener información más detallada del SAI, usamos nut-scanner:
nut-scanner
# O específicamente para dispositivos USB
nut-scanner -U
La salida mostrará algo similar a esto:
Cannot load SNMP library (libnetsnmp.so.40) : file not found. SNMP search disabled.
Cannot load XML library (libneon.so.27) : file not found. XML search disabled.
Cannot load AVAHI library (libavahi-client.so.3) : file not found. AVAHI search disabled.
Cannot load IPMI library (libfreeipmi.so.17) : file not found. IPMI search disabled.
Scanning USB bus.
No start IP, skipping NUT bus (old connect method)
[nutdev1]
driver = "usbhid-ups"
port = "auto"
vendorid = "2E66"
productid = "0302"
product = "1500"
serial = "000000000000"
vendor = "1"
bus = "001"
device = "004"
busport = "002"
###NOTMATCHED-YET###bcdDevice = "0200"
# WARNING: all-same character "serial" with 12 copies of '0' (0x30) reported in some devices: nutdev1
Los avisos sobre librerías no encontradas son normales si no has instalado los paquetes opcionales correspondientes.
Configuración del servidor NUT
Configurar el dispositivo UPS
Editamos el fichero /etc/nut/ups.conf para agregar la configuración de nuestro SAI:
nano -cl /etc/nut/ups.conf
Al final del archivo, agregamos la configuración del SAI usando los datos obtenidos antes de nut-scanner:
[ups-homelab]
driver = usbhid-ups
port = auto
vendorid = 2E66
productid = 0302
product = 1500
vendor = 1
bus = 001
desc = "Salicru SPS 1500 Advanced T"
ignorelb
override.battery.charge.warning = 90
override.battery.charge.low = 60
override.battery.runtime.low = 60
Explicación de los parámetros:
[ups-homelab]: Nombre identificativo del SAI en NUT.driver: Driver a utilizar (usbhid-upspara la mayoría de SAIs USB).port: Puerto de conexión (autopara detección automática).vendorid,productid,product,vendor,bus: Identificadores del dispositivo USB.desc: Descripción del dispositivo.ignorelb: Ignorar la señal por defecto de batería baja del SAI (usaremos valores personalizados).override.battery.charge.warning: Carga de batería para emitir advertencia (90%).override.battery.charge.low: Carga de batería considerada baja (60%).override.battery.runtime.low: Tiempo de batería restante considerado bajo en segundos (60s).
Configurar el modo de operación
Editamos el fichero /etc/nut/nut.conf para configurar el modo de operación:
nano -cl /etc/nut/nut.conf
Cambiamos la línea MODE a:
MODE=netserver
Esto permitirá que otros equipos en la red puedan consultar el estado del SAI.
Enlace a la documentación del fichero nut.conf.
Configurar el servicio upsd
Editamos el fichero /etc/nut/upsd.conf para configurar la dirección y puerto en el que escuchará el servicio:
nano -cl /etc/nut/upsd.conf
Bajo los ejemplos de la directiva LISTEN, agregamos:
LISTEN 0.0.0.0 3493
Esto hará que upsd escuche en todas las interfaces de red en el puerto 3493.
Enlace a la documentación del fichero upsd.conf.
Configurar usuarios de administración
Editamos el fichero /etc/nut/upsd.users para definir los usuarios que podrán administrar NUT:
nano -cl /etc/nut/upsd.users
Agregamos dos usuarios: uno con permisos de administrador y otro como observador para los clientes:
[admin]
password = ADMIN_PASSWORD_HERE
actions = SET
actions = FSD
instcmds = all
upsmon primary
[observer]
password = OBSERVER_PASSWORD_HERE
upsmon secondary
Importante: Reemplaza ADMIN_PASSWORD_HERE y OBSERVER_PASSWORD_HERE con contraseñas seguras.
Explicación de los parámetros:
password: Contraseña del usuario.actions = SET: Permite modificar variables del SAI.actions = FSD: Permite forzar el apagado (Forced ShutDown).instcmds = all: Permite ejecutar todos los comandos instantáneos.upsmon primary: Usuario principal (gestiona el SAI directamente).upsmon secondary: Usuario secundario (solo monitoriza).
Enlace a la documentación del fichero upsd.users.
Configurar el monitor upsmon
Editamos el fichero /etc/nut/upsmon.conf:
nano -cl /etc/nut/upsmon.conf
Bajo la sección MONITOR, agregamos la configuración para conectar con nuestro SAI:
# MONITOR <system> <powervalue> <username> <password> ("primary"|"secondary")
MONITOR ups-homelab@localhost 1 admin ADMIN_PASSWORD_HERE primary
Explicación de los parámetros:
ups-homelab@localhost: Nombre del SAI y servidor (localhost porque está en el mismo equipo).1: Número de fuentes de alimentación (1 para un solo SAI).admin: Usuario de NUT a utilizar.ADMIN_PASSWORD_HERE: Contraseña del usuario.primary: Este equipo es el primario (gestiona el SAI directamente).
También modificamos el valor de FINALDELAY para configurar el tiempo de espera antes del apagado:
FINALDELAY 10
Esto hará que el sistema se apague 10 segundos después de recibir el aviso de batería baja.
Enlace a la documentación del fichero upsmon.conf.
Iniciar y verificar los servicios
Con la configuración completa, iniciamos los servicios de NUT:
systemctl start nut-server
systemctl status nut-server
systemctl start nut-monitor
systemctl status nut-monitor
Si todo va correctamente, ambos servicios deberían estar activos y en ejecución.
Verificar el estado del SAI
Comprobamos que nuestro SAI está correctamente configurado:
upsc ups-homelab
# Alternativas:
# upsc ups-homelab@localhost
# upsc ups-homelab@<SERVER_IP>
La salida mostrará información detallada del SAI:
Init SSL without certificate database
battery.charge: 100
battery.charge.low: 60
battery.charge.warning: 90
battery.runtime: 1860
battery.runtime.low: 60
battery.type: PbAcid
battery.voltage: 26.30
battery.voltage.nominal: 24
...
ups.serial: 000000000000
ups.status: OL
ups.vendorid: 2e66
El parámetro ups.status: OL (OnLine) indica que el SAI está recibiendo alimentación de la red eléctrica.
Habilitar servicios al inicio
Si todo funciona correctamente, habilitamos los servicios para que se inicien automáticamente al arrancar:
systemctl enable nut-server
systemctl enable nut-monitor
Configurar clientes NUT
Si tienes otros equipos en tu red que deben apagarse cuando el SAI tenga batería baja, configúralos como clientes de NUT.
Instalación en el cliente
En cada equipo cliente, instalamos nut-client:
su -
apt update
apt install nut-client
Por algún motivo, con la versión actual de NUT en Debian 13, instalando nut-client no se instalan todos los archivos necesarios para su correcto funcionamiento, por lo que también instalaremos nut-server (pero lo deshabilitamos inmediatamente, solo nos interesan los archivos que aporta):
apt install nut-server
systemctl disable --now nut-server
Configurar modo netclient
Editamos /etc/nut/nut.conf en el cliente:
nano -cl /etc/nut/nut.conf
Configuramos el modo de operación:
MODE=netclient
Enlace a la documentación del fichero nut.conf.
Verificar conectividad con el servidor
Antes de continuar, verificamos que el cliente puede conectarse al servidor NUT:
upsc ups-homelab@<SERVER_IP>
Si la conexión es exitosa, veremos la información del SAI.
Configurar monitorización en el cliente
Editamos /etc/nut/upsmon.conf en el cliente:
nano -cl /etc/nut/upsmon.conf
Agregamos la línea MONITOR con los datos del usuario observer:
# MONITOR <system> <powervalue> <username> <password> ("primary"|"secondary")
MONITOR ups-homelab@<SERVER_IP> 1 observer OBSERVER_PASSWORD_HERE secondary
Guardamos y salimos del editor.
Enlace a la documentación del fichero upsmon.conf.
Iniciar servicio en el cliente
Reiniciamos el servicio nut-client:
systemctl restart nut-client
systemctl status nut-client
Probar la configuración
Para verificar que el cliente recibe eventos del servidor, simulamos una pérdida de alimentación desconectando el SAI de la red eléctrica y monitorizamos los logs:
journalctl -f -u nut-monitor
Deberías ver mensajes como:
Sep 23 01:35:30 charlie nut-monitor[4665]: UPS ups-homelab@<SERVER_IP> on battery
Sep 23 01:35:30 charlie nut-monitor[5879]: Network UPS Tools upsmon 2.8.1
Si funciona correctamente, habilitamos e iniciamos el servicio:
systemctl enable --now nut-client
Apagar los clientes automáticamente al perder alimentación
Para maximizar el tiempo de batería disponible, podemos configurar los clientes para que inicien el apagado ordenado en cuanto el SAI pase a batería (ONBATT). Posteriormente, podremos encenderlos mediante Wake-on-LAN o manualmente.
Configurar notificaciones en el cliente
Editamos /etc/nut/upsmon.conf en el cliente:
nano -cl /etc/nut/upsmon.conf
Agregamos la configuración para ejecutar upssched:
NOTIFYCMD /usr/sbin/upssched
NOTIFYFLAG ONBATT EXEC
Enlace a la documentación del fichero upsmon.conf.
Configurar upssched
Editamos /etc/nut/upssched.conf:
nano -cl /etc/nut/upssched.conf
Agregamos las siguientes líneas:
CMDSCRIPT /usr/bin/upssched-cmd
PIPEFN /run/nut/upssched/upssched.pipe
LOCKFN /run/nut/upssched/upssched.lock
# Ejecutar el apagado en cuanto el SAI pase a batería
AT ONBATT * EXECUTE shutdown_onbatt
Enlace a la documentación del fichero upssched.conf.
Configurar permisos de sudo para el usuario nut
Instalamos sudo si no lo tenemos:
apt update
apt install sudo
Editamos la configuración de sudoers:
visudo
Agregamos al final del fichero:
# Permitir al usuario nut ejecutar el comando shutdown sin contraseña
nut ALL=(ALL) NOPASSWD: /sbin/shutdown
Crear script de apagado
Editamos o creamos el script /usr/bin/upssched-cmd:
nano -cl /usr/bin/upssched-cmd
Lo rellenamos con el siguiente contenido:
#!/usr/bin/env bash
case "$1" in
shutdown_onbatt)
logger -t nut-monitor "Received ONBATT from server: shutting down"
sudo /sbin/shutdown -h now
;;
*)
logger -t nut-monitor "upssched-cmd: unknown argument: $1"
;;
esac
Hacemos el script ejecutable:
chmod +x /usr/bin/upssched-cmd
Reiniciar servicio y probar
Reiniciamos el servicio:
systemctl restart nut-client
systemctl status nut-client
Para probar que funciona, podemos ejecutar manualmente:
/usr/bin/upssched-cmd shutdown_onbatt
Advertencia: Este comando apagará el sistema inmediatamente.
Bonus: Notificaciones por Telegram
Podemos configurar NUT para que envíe notificaciones del estado del SAI a través de Telegram.
Requisitos
- ID de tu cuenta de Telegram.
- Token de un bot de Telegram.
Configurar upssched en el servidor
Editamos /etc/nut/upsmon.conf en el servidor:
nano -cl /etc/nut/upsmon.conf
Configuramos las notificaciones:
NOTIFYCMD /usr/sbin/upssched
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
Enlace a la documentación del fichero upsmon.conf.
Configurar los eventos en upssched
Editamos /etc/nut/upssched.conf:
nano -cl /etc/nut/upssched.conf
Agregamos las siguientes líneas:
CMDSCRIPT /usr/bin/upssched-cmd
PIPEFN /run/nut/upssched/upssched.pipe
LOCKFN /run/nut/upssched/upssched.lock
# Eventos directos
AT ONLINE * EXECUTE ONLINE
AT ONBATT * EXECUTE ONBATT
AT LOWBATT * EXECUTE LOWBATT
AT FSD * EXECUTE FSD
AT COMMOK * EXECUTE COMMOK
AT COMMBAD * EXECUTE COMMBAD
AT SHUTDOWN * EXECUTE SHUTDOWN
AT REPLBATT * EXECUTE REPLBATT
AT NOCOMM * EXECUTE NOCOMM
Enlace a la documentación del fichero upssched.conf.
Crear script con notificaciones de Telegram
Editamos de nuevo el fichero /usr/bin/upssched-cmd en el servidor:
nano -cl /usr/bin/upssched-cmd
Reemplazamos su contenido con:
#!/usr/bin/env bash
ACTION="$1"
UPS="ups-homelab@localhost"
STATEFILE="/var/lib/nut/last_batt_notify"
PIDFILE="/var/lib/nut/checkbatt.pid"
BOT_TOKEN="<YOUR_BOT_TOKEN>"
CHAT_ID="<YOUR_CHAT_ID>"
INTERVAL=30
send_msg() {
local text="$1"
if [[ -n "$BOT_TOKEN" && -n "$CHAT_ID" ]]; then
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
--data-urlencode "text=${text}" >/dev/null || true
fi
}
# Recopilar información del SAI
get_status_info() {
CHARGE="$(upsc "$UPS" battery.charge 2>/dev/null || echo "N/A")"
STATUS="$(upsc "$UPS" ups.status 2>/dev/null || echo "N/A")"
RUNTIME="$(upsc "$UPS" battery.runtime 2>/dev/null || echo "")"
EXTRA=""
if [[ "$RUNTIME" =~ ^[0-9]+$ ]]; then
MIN_LEFT=$(( RUNTIME / 60 ))
EXTRA=" (~${MIN_LEFT} min left)"
fi
}
# Monitorización periódica de batería
check_loop() {
while true; do
get_status_info
CHARGE_INT="${CHARGE%.*}"
LAST="$(cat "$STATEFILE" 2>/dev/null || echo 999)"
if [[ "$CHARGE_INT" != "$LAST" && "$CHARGE" != "N/A" ]]; then
echo "$CHARGE_INT" > "$STATEFILE"
send_msg "🔋 Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
fi
# Salir si el SAI vuelve a la red
if [[ "$STATUS" == *"OL"* ]]; then
exit 0
fi
sleep "$INTERVAL"
done
}
case "$ACTION" in
ONBATT)
get_status_info
send_msg "⚡ Running on battery!
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
# Iniciar monitorización en segundo plano
if [[ ! -f "$PIDFILE" ]] || ! kill -0 "$(cat "$PIDFILE" 2>/dev/null)" 2>/dev/null; then
check_loop & echo $! > "$PIDFILE"
fi
;;
ONLINE)
get_status_info
send_msg "🔌 Power restored!
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
# Detener monitorización
if [[ -f "$PIDFILE" ]]; then
kill "$(cat "$PIDFILE")" 2>/dev/null || true
rm -f "$PIDFILE"
fi
;;
LOWBATT)
get_status_info
send_msg "❗ Battery low! System may shut down soon.
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
FSD)
get_status_info
send_msg "💀 Forced shutdown triggered.
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
COMMOK)
get_status_info
send_msg "📡 UPS communication restored.
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
COMMBAD)
get_status_info
send_msg "🚫 Lost communication with UPS!
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
SHUTDOWN)
get_status_info
send_msg "🛑 System shutdown initiated.
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
REPLBATT)
get_status_info
send_msg "🔧 UPS battery needs replacement!
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
;;
NOCOMM)
get_status_info
send_msg "❌ No communication with UPS.
Battery: ${CHARGE}%${EXTRA}
Status: ${STATUS}"
# Detener monitorización si está activa
if [[ -f "$PIDFILE" ]]; then
kill "$(cat "$PIDFILE")" 2>/dev/null || true
rm -f "$PIDFILE"
fi
;;
*)
send_msg "⚠️ Unknown UPS event: ${ACTION}"
;;
esac
Importante: Reemplaza <YOUR_BOT_TOKEN> y <YOUR_CHAT_ID> con tus credenciales de Telegram.
Hacemos el script ejecutable:
chmod +x /usr/bin/upssched-cmd
Reiniciar servicios
Reiniciamos todos los servicios de NUT:
systemctl restart nut-server
systemctl restart nut-monitor
systemctl restart nut-client
Y si queremos comprobar su estado:
systemctl status nut-server
systemctl status nut-monitor
systemctl status nut-client
Probar notificaciones
Para probar que las notificaciones funcionan, simplemente desenchufa el SAI de la red eléctrica.
Deberías recibir un mensaje en Telegram indicando que el SAI está funcionando con batería, y durante el tiempo que el servidor esté funcionando, irás recibiendo actualizaciones sobre el estado de la batería. Igualmente, cuando la alimentación se restaure o finalmente el sistema se apague, recibirás las notificaciones correspondientes:
Conclusión
Con NUT correctamente configurado, tus sistemas estarán protegidos contra fallos eléctricos. El servidor gestiona el apagado automático de múltiples clientes (y de sí mismo), y las notificaciones por Telegram te mantienen al tanto del estado del SAI en tiempo real.
Interfaz web para monitorizar tu SAI
Si quieres una interfaz gráfica para monitorizar tu SAI, echa un vistazo al post sobre PeaNUT, una interfaz web para NUT que te permite ver toda la información relevante de un vistazo.
Notas importantes
- Prueba siempre la configuración de apagado automático en un entorno controlado antes de implementarla en producción.
- Ajusta los valores de batería baja según las especificaciones y necesidades de tu SAI.
- El temporizador de monitorización periódica de batería en el script de Telegram puede no funcionar exactamente como se especifica (se ejecuta cada 30 segundos independientemente del valor configurado).