Ir al contenido
  1. Posts/

Ntfy: notificaciones push self-hosted para tu homelab

Durante mucho tiempo usé Telegram para las notificaciones del homelab. Tenía un bot que me mandaba mensajes cuando terminaba un backup, cuando se caía un servicio, o cuando algún script de automatización fallaba. Funcionaba bien, pero dependía de la API de Telegram, necesitaba mantener el token del bot, y ocasionalmente Telegram tenía algún problema de conectividad que retrasaba las alertas.

Descubrí Ntfy buscando una alternativa y me quedé con él en dos días. La idea es tan simple que al principio no me lo creía: un servidor HTTP que actúa de broker de mensajes. Publicas en un topic con un POST, y cualquier cliente suscrito a ese topic recibe la notificación. Sin cuentas, sin OAuth, sin configuración compleja.

La aplicación móvil existe para Android e iOS. El servidor puedes auto-alojarlo o usar el servicio público de ntfy.sh si no quieres montar nada. Yo lo tengo en mi servidor porque así controlo quién puede publicar y suscribirse.

Cómo funciona por dentro
#

Ntfy usa topics para organizar las notificaciones. Un topic es simplemente un nombre en la URL, como mis-backups o alertas-homelab. No hay registro de topics: si publicas en uno que no existe, se crea automáticamente. Si te suscribes a uno, recibirás todo lo que se publique ahí.

Publicar una notificación es una petición HTTP:

1
curl -d "El backup de ayer terminó bien" ntfy.mi-servidor.local/backups

Eso es todo. La aplicación del móvil suscrita a ntfy.mi-servidor.local/backups recibirá esa notificación con título “backups” y el texto que enviaste.

Puedes enriquecer las notificaciones con headers adicionales:

1
2
3
4
5
6
curl \
  -H "Title: Backup completado" \
  -H "Priority: high" \
  -H "Tags: white_check_mark" \
  -d "Backup de documentos: 4.2 GB, 14 minutos" \
  ntfy.mi-servidor.local/backups

Las tags son nombres de emojis de Unicode. Ntfy convierte white_check_mark en el emoji ✅ que aparece en la notificación. Hay una lista en la documentación oficial con todos los nombres de emojis que puedes usar.

La prioridad puede ser min, low, default, high, o urgent. Con urgent, la notificación en el móvil suena con tono de alerta y no sigue el perfil de silencio.

Instalación con Docker Compose
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: "3"
services:
  ntfy:
    image: binwiederhier/ntfy
    container_name: ntfy
    command:
      - serve
    environment:
      - TZ=Europe/Madrid
    volumes:
      - ./ntfy/cache:/var/cache/ntfy
      - ./ntfy/etc:/etc/ntfy
    ports:
      - "80:80"
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "wget -q --tries=1 http://localhost/v1/health -O - | grep -Eo '\"healthy\":true'"]
      interval: 60s
      timeout: 10s
      retries: 3

Si quieres exponer Ntfy a internet con HTTPS, lo más sencillo es ponerlo detrás de un reverse proxy como Nginx Proxy Manager o Traefik. Ntfy también puede gestionar los certificados TLS él solo si le apuntas un dominio, usando Let’s Encrypt, pero el enfoque del reverse proxy es más consistente con el resto del homelab.

Para configuración adicional, crea el fichero /etc/ntfy/server.yml (que en Docker va en ./ntfy/etc/server.yml):

1
2
3
4
5
6
base-url: "https://ntfy.tu-dominio.com"
cache-file: /var/cache/ntfy/cache.db
cache-duration: 12h
attachment-cache-dir: /var/cache/ntfy/attachments
attachment-total-size: 5G
attachment-file-size: 15M

El base-url es importante si quieres que los clientes móviles reciban notificaciones cuando la app está cerrada. Ntfy usa Firebase Cloud Messaging (FCM) para eso en Android, que requiere que el servidor pueda comunicarse con los servidores de Google. Si prefieres evitar FCM, en Android puedes usar la versión de F-Droid de la app que funciona sin Google Services con notificaciones por polling.

Autenticación y control de acceso
#

Por defecto Ntfy es completamente abierto: cualquiera que conozca tu URL puede publicar y suscribirse a cualquier topic. Si lo expones a internet sin autenticación, alguien podría descubrir tus topics y llenarlos de basura.

Para protegerlo, Ntfy tiene un sistema de usuarios y permisos. En el fichero de configuración:

1
2
auth-file: /var/cache/ntfy/user.db
auth-default-access: deny-all

Con deny-all, nadie puede acceder sin usuario y contraseña. Luego creas usuarios y les asignas permisos:

1
2
3
4
5
# Dentro del contenedor
docker exec -it ntfy ntfy user add --role=admin admin
docker exec -it ntfy ntfy user add publicador
docker exec -it ntfy ntfy access publicador backups rw
docker exec -it ntfy ntfy access publicador alertas rw

En los scripts que publican notificaciones, añades las credenciales:

1
2
3
4
curl -u publicador:contraseña \
  -H "Title: Backup completado" \
  -d "4.2 GB en 14 minutos" \
  https://ntfy.tu-dominio.com/backups

En la app del móvil, cuando suscribes al topic, te pide usuario y contraseña del servidor. Puedes tener un usuario de solo lectura para el móvil y un usuario con escritura para los scripts.

Casos de uso reales
#

Fin de backups: El caso más obvio. En mis scripts de Restic tengo al final:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
if [ $? -eq 0 ]; then
  curl -s -u $NTFY_USER:$NTFY_PASS \
    -H "Title: Backup OK" \
    -H "Tags: white_check_mark" \
    -d "$(date +%Y-%m-%d): $SIZE en $TIME" \
    https://ntfy.tu-dominio.com/backups
else
  curl -s -u $NTFY_USER:$NTFY_PASS \
    -H "Title: Backup FALLIDO" \
    -H "Priority: urgent" \
    -H "Tags: x" \
    -d "Revisar logs en $HOSTNAME" \
    https://ntfy.tu-dominio.com/backups
fi

Si el backup va bien, recibo una notificación silenciosa. Si falla, recibo una alerta urgente que rompe el silencio del móvil.

Alertas de Uptime Kuma: Uptime Kuma tiene integración nativa con Ntfy. En la configuración de notificaciones de Uptime Kuma, añades el tipo “Ntfy”, pones la URL de tu servidor, el topic, y las credenciales. Cada vez que un servicio se cae o se recupera, recibes la notificación en el móvil.

Antes usaba Telegram para esto. La diferencia práctica es pequeña, pero tener todo en el mismo broker me simplifica la gestión. Un servicio, una app en el móvil, todos los topics.

Scripts de actualización: Tengo un script que comprueba si hay actualizaciones para los contenedores Docker. Al terminar de actualizar, manda un resumen con qué se actualizó:

1
2
3
4
5
6
UPDATES=$(docker pull ghcr.io/ajnart/homarr:latest 2>&1 | grep "Status:")
curl -s -u $NTFY_USER:$NTFY_PASS \
  -H "Title: Actualizaciones aplicadas" \
  -H "Tags: arrows_counterclockwise" \
  -d "$UPDATES" \
  https://ntfy.tu-dominio.com/actualizaciones

Alertas de temperatura: Si tienes scripts que monitorizan temperaturas de hardware, puedes mandar una alerta cuando algo sube de lo normal:

1
2
3
4
5
6
7
8
TEMP=$(cat /sys/class/thermal/thermal_zone0/temp)
TEMP_C=$((TEMP/1000))
if [ $TEMP_C -gt 75 ]; then
  curl -s -H "Priority: high" \
    -H "Title: Temperatura alta" \
    -d "CPU a ${TEMP_C}°C" \
    https://ntfy.tu-dominio.com/hardware
fi

Notificaciones de impresor 3D: OctoPrint tiene plugin de Ntfy. Al terminar de imprimir, al cancelar por error, o al quedar sin filamento, te llega la notificación directamente. Cuando tengo impresiones largas y no quiero estar pendiente del OctoPrint, esto es de mucha ayuda.

Eventos de Home Assistant: Home Assistant puede enviar notificaciones a Ntfy a través de la integración de REST. Configurado como un servicio de notificación en configuration.yaml, puedes usarlo en cualquier automatización:

1
2
3
4
5
6
7
8
9
notify:
  - name: ntfy_homelab
    platform: rest
    resource: https://ntfy.tu-dominio.com/hogar
    method: POST_JSON
    headers:
      Authorization: Basic dXN1YXJpbzpjb250cmFzZW5h
    message_param_name: message
    title_param_name: title

La app del móvil
#

La aplicación oficial de Ntfy para Android e iOS es bastante básica en diseño pero funciona bien. Añades el servidor (por defecto apunta a ntfy.sh, el servicio público, cambia a tu servidor propio), pones las credenciales si tienes autenticación activada, y te suscribes a los topics que quieras.

Las notificaciones llegan incluso con la app cerrada. En Android, si tienes Google Play Services, las notificaciones van por FCM y llegan al momento. Si usas la versión de F-Droid sin Google Services, las notificaciones van por polling (cada pocos minutos revisa el servidor). El polling tiene más latencia pero no depende de infraestructura de Google.

En el cliente web, ntfy.tu-dominio.com ya tiene una interfaz completa para ver los mensajes recibidos y para probar publicar desde el navegador. Es útil para depurar cuando estás configurando un nuevo script.

Ntfy vs Gotify
#

Gotify es la otra alternativa popular para notificaciones push self-hosted. La diferencia principal está en el modelo: Gotify usa aplicaciones con tokens para enviar, mientras Ntfy usa topics abiertos con autenticación opcional.

Gotify tiene interfaz web más completa y el historial de mensajes es más prominente en la UI. Ntfy es más sencillo de integrar porque cualquier cosa que pueda hacer una petición HTTP puede publicar sin necesidad de gestionar tokens de aplicación.

En la práctica, los dos hacen lo mismo. Yo empecé con Gotify y cambié a Ntfy porque prefiero el modelo de topics. Para integraciones desde scripts de shell, el curl simple de Ntfy es más directo.

Ntfy vs Telegram bot
#

La comparativa más común es esta. Telegram tiene la ventaja de que ya lo tienes instalado en el móvil y funciona muy bien. El bot de Telegram para homelab lleva años siendo el estándar de facto.

Las razones por las que preferí cambiar a Ntfy:

No necesito dependencia de la infraestructura de Telegram. Si Telegram tiene problemas o decide cambiar su API, mis alertas dejan de funcionar.

El formato de los mensajes de Ntfy es más consistente para notificaciones de sistema. Telegram es un chat, tiene un formato más conversacional que no siempre encaja bien con mensajes automáticos de scripts.

Ntfy tiene prioridades nativas. Puedo configurar que las alertas urgentes rompan el modo silencio y el resto lleguen silenciosamente, sin necesitar lógica adicional.

La contrapartida: con Telegram no necesito montar nada. Si ya tienes un bot de Telegram funcionando y estás contento con él, no hay razón fuerte para cambiar. Ntfy vale la pena si estás empezando de cero o si tienes muchas fuentes de notificaciones y quieres centralizarlas en una sola app.

Acciones en las notificaciones
#

Ntfy soporta acciones directamente en las notificaciones push. Puedes añadir botones que ejecuten una petición HTTP cuando los pulsas desde el móvil.

Un ejemplo práctico: una notificación de alerta de temperatura con un botón para reiniciar el servicio que consume demasiada CPU:

1
2
3
4
5
6
curl -u $NTFY_USER:$NTFY_PASS \
  -H "Title: Servicio en loop" \
  -H "Priority: high" \
  -H "Actions: http, Reiniciar, https://mi-servidor.local/api/restart/servicio, method=POST" \
  -d "El contenedor X lleva 2h con CPU al 100%" \
  https://ntfy.tu-dominio.com/alertas

Cuando llega la notificación al móvil, aparece un botón “Reiniciar”. Al pulsarlo, el móvil hace un POST a la URL que configuraste. Si tienes una API o un webhook que acepta ese POST, el servicio se reinicia sin que tengas que abrir ninguna app ni conectarte al servidor.

Para esto necesitas que la URL de la acción sea accesible desde fuera de tu red local, o tenerla en Tailscale. Pero cuando funciona, es bastante potente para gestión de incidencias desde el móvil.

Rendimiento y recursos
#

Ntfy es ligero. En mi servidor, el proceso consume entre 10 y 20 MB de RAM en reposo. Con varios clientes conectados y tráfico constante, no he visto que pase de 50 MB.

La base de datos de caché es SQLite, lo que significa que escala bien para uso personal y de homelab pero no está diseñado para millones de mensajes. Para lo que lo usamos en casa, es más que suficiente.

El tiempo de retención de mensajes se configura con cache-duration. Por defecto guarda los mensajes 12 horas, lo que significa que si el móvil no está conectado durante ese tiempo y luego se conecta, recibirá los mensajes acumulados. Puedes aumentarlo si necesitas más ventana.

El resultado en mi homelab
#

Tengo Ntfy corriendo con unos 15 topics activos: backups, actualizaciones, Uptime Kuma, Home Assistant, impresoras, y algunos scripts personalizados. Todas las notificaciones llegan a la misma app en el móvil.

Lo que más valoro es la simplificación. Antes tenía el bot de Telegram, algún script que mandaba emails para cosas críticas, y Uptime Kuma con sus propias notificaciones. Ahora todo va a Ntfy y yo solo miro una app.

La integración con scripts de shell es lo más práctico del día a día. Un curl al final de cualquier script y ya tienes notificación. Sin tokens que gestionar, sin bibliotecas que instalar, sin configuraciones complejas. Si tu homelab tiene muchos scripts automatizados y quieres saber cuándo terminan o fallan, Ntfy es la forma más simple de hacerlo.