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.
  • apt como gestor de paquetes en tu sistema. Si usas otra distribución, deberás adaptar los comandos con apt a tu gestor de paquetes.
  • Poder ejecutar comandos como root (ya sea como usuario root directamente, o con sudo o doas). En mi caso lo haré como root (usando su).
  • 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

  1. NUT puede funcionar en diferentes modos: standalone (para un solo equipo), netserver (para servir información a otros equipos) y netclient (para recibir información de un servidor NUT).

  2. Las configuraciones de apagado automático son críticas. Asegúrate de probarlas en un entorno controlado antes de implementarlas en producción.

  3. 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, libupsclient6
  • nut-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.

NUT Scanner Output - Detección del SAI

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-ups para la mayoría de SAIs USB).
  • port: Puerto de conexión (auto para 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.

UPS Status - Información del SAI

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:

Notificaciones Telegram - Alertas del SAI

Notificaciones Telegram - Alertas del SAI

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).

Referencias