Guía de despliegue

Alojar ntfy en un VPS: notificaciones push para sus scripts

Desplegar en un VPS Cloud →

Tutorial

Alojar ntfy en un VPS: notificaciones push para sus scripts

Seguridad y monitorización16 min de lectura8 pasos

Slack se paga por asiento. Los correos se pierden en el ruido. Los webhooks de Discord desaparecen en un hilo. ntfy (Apache 2.0, ~32 k ⭐, v2.30.0 — oct. 2026) resuelve el problema de otra manera: un servidor pub/sub HTTP que usted mismo aloja en su VPS y al que cualquier script envía una alerta con un `curl -d`. La aplicación móvil recibe el push en tiempo real — incluso fuera de la red local. Un solo contenedor Docker, < 30 MB de RAM, sin cuenta de terceros. En este artículo: despliegue, autenticación, configuración multi-tenant con `server.yml`, integraciones con Backrest / Uptime Kuma / cron, notificaciones SMTP y los cinco errores reales que todo administrador se encuentra en producción.

Contenido· El problema: demasiadas herramientas de monitoreo, demasiados canales de notificación1/14
  1. 01El problema: demasiadas herramientas de monitoreo, demasiados canales de notificación
  2. 02Lo que ntfy aporta de entrada
  3. 03Arquitectura: un pub/sub HTTP en un solo contenedor
  4. 04Desplegar ntfy en producción: 8 pasos
  5. 05Autenticación y tokens de acceso: nunca exponga un topic público
  6. 06Configuración multi-tenant: un servidor, varios equipos
  7. 07Consejo: los nombres de topic como espacios de nombres y estrategia de silencio nocturno
  8. 08Resolución de problemas: 5 errores reales en producción
  9. 09iOS: por qué un ntfy autoalojado pasa por ntfy.sh para el push
  10. 10Checklist iOS: siete comprobaciones antes de buscar más lejos
  11. 11Cuando no llega nada pese a todo: lo que dicen realmente las issues #1305 y #1844
  12. 12Tip: no confíe una alerta crítica solo al push de iOS
  13. 13Integraciones avanzadas: Backrest, Uptime Kuma, Grafana
  14. 14Consejo: pruebe la cadena de entrega de extremo a extremo antes de confiar en ella

El problema: demasiadas herramientas de monitoreo, demasiados canales de notificación

Uptime Kuma vigila sus servicios, Beszel vigila las métricas de su VPS, Backrest gestiona sus copias de seguridad, y sus cron jobs callan por la noche — salvo cuando fallan. Cada uno tiene su canal de notificación: Slack, correo, webhook, Telegram. Resultado: cinco integraciones distintas que mantener, cinco tipos de alerta que formatear y ninguna vista unificada cuando algo falla a las 03:00. ntfy resuelve el problema al revés: es usted quien aloja el hub de notificaciones, y cada herramienta o script le envía sus alertas por HTTP puro.

Lo que ntfy aporta de entrada

  • Envío de una notificación con un simple curl — curl -d "Build fallido" https://ntfy.ejemplo.com/alertas-ci — cero SDK, cero bibliotecas.
  • Recepción en Android (F-Droid / Play Store), iOS (App Store), navegador de escritorio e interfaz web de ntfy — todos se suscriben al mismo topic vía WebSocket o SSE.
  • Acciones dentro de la notificación — botones que disparan callbacks HTTP, abren URL o ejecutan comandos en el dispositivo.
  • Notificaciones programadas — entrega diferida (X-Delay: 30min) para programar recordatorios desde sus scripts.
  • Niveles de prioridad (mín. / baja / predeterminada / alta / urgente) con anulación del modo No molestar para las alertas críticas.
  • Archivos adjuntos — imágenes o archivos de hasta 15 MB mediante la cabecera X-Attach o una subida multipart.
  • Notificaciones SMTP — ntfy puede enviar un correo de respaldo si su móvil está desconectado o la app no está instalada.
  • Control de acceso granular — usuarios, contraseñas cifradas con bcrypt, tokens de acceso y ACL por topic.
  • < 30 MB de RAM, SQLite, un solo contenedor — el servidor de notificaciones push más ligero de su categoría.

Arquitectura: un pub/sub HTTP en un solo contenedor

ntfy es un binario Go que cabe en un único contenedor Docker. Expone una interfaz HTTP sencilla: un PUT o un POST sobre /su-topic publica un mensaje; cualquier cliente que escuche ese topic lo recibe al instante. Los mensajes se guardan en caché en SQLite con una retención configurable (12 horas por defecto). En producción, ntfy se coloca detrás de un proxy inverso nginx que gestiona el TLS — behind-proxy: true en server.yml indica a ntfy que lea la IP real desde X-Forwarded-For. Toda la configuración avanzada vive en un único archivo /etc/ntfy/server.yml.

Desplegar ntfy en producción: 8 pasos

  1. Desplegar ntfy desde el marketplace ServOrbit

    Abra su panel de ServOrbit → Marketplace → Monitoring → ntfy → Desplegar. Docker descarga binwiederhier/ntfy:v2.30.0, arranca ntfy en el puerto 8080 y la interfaz web queda accesible en menos de 5 segundos con un certificado Let's Encrypt en su dominio.

  2. Enviar su primera notificación

    Desde cualquier terminal con curl:
    curl -d "Hola desde mi VPS" https://ntfy.ejemplo.com/mi-topic
    Abra la interfaz web de ntfy, vaya a mi-topic y su mensaje aparece en tiempo real.

  3. Crear el server.yml completo

    Monte un archivo de configuración en el contenedor:
    base-url: https://ntfy.ejemplo.com
    listen-http: ":8080"
    behind-proxy: true
    cache-file: /var/lib/ntfy/cache.db
    cache-duration: 12h
    auth-file: /var/lib/ntfy/user.db
    auth-default-access: deny-all
    smtp-sender-addr: smtp.ejemplo.com:587
    smtp-sender-user: [email protected]
    smtp-sender-pass: contraseñaSMTP
    smtp-sender-from: [email protected]
    Reinicie el contenedor tras cualquier cambio: docker restart ntfy.
    Para recibir notificaciones también en iOS, añada upstream-base-url: "https://ntfy.sh" a este archivo: la sección «iOS» más abajo explica por qué.

  4. Crear usuarios y tokens de acceso

    # Crear un usuario admin interactivo
    docker exec -it ntfy ntfy user add --role=admin admin
    # Crear un usuario para scripts
    docker exec -it ntfy ntfy user add scripts
    # Generar un token de acceso
    docker exec -it ntfy ntfy token add scripts
    # Salida: tk_AbCdEf123456...
    # Conceder lectura/escritura sobre un topic
    docker exec -it ntfy ntfy access scripts server-alerts rw

  5. Suscribirse desde su teléfono con autenticación

    Instale la app ntfy (Android: F-Droid o Play Store; iOS: App Store). Pulse + → introduzca la URL del servidor y el topic. Cuando ntfy solicite credenciales, introduzca el nombre de usuario y la contraseña. Recibirá push mediante UnifiedPush, FCM o APNs. En iOS, el push instantáneo solo llega si su servidor tiene upstream-base-url definido (vea la sección dedicada más abajo).

  6. Alertar desde cron jobs usando un token

    #!/bin/bash
    NTFY_URL="https://ntfy.ejemplo.com"
    NTFY_TOKEN="tk_AbCdEf123456"
    /usr/local/bin/backup.sh; STATUS=$?
    if [ $STATUS -eq 0 ]; then
    curl -s -H "Authorization: Bearer $NTFY_TOKEN" -H "Title: Backup nocturno" -H "Priority: default" -d "Backup completado a las $(date)" "$NTFY_URL/cron-jobs"
    else
    curl -s -H "Authorization: Bearer $NTFY_TOKEN" -H "Title: Backup FALLIDO" -H "Priority: urgent" -d "Backup fallido — código $STATUS" "$NTFY_URL/cron-jobs"
    fi

  7. Configurar Backrest y Uptime Kuma

    Backrest: UI → Planes → su plan → Hooks → Añadir Hook → tipo Webhook (ntfy) → URL del topic y token Bearer.

    Uptime Kuma: Ajustes → Notificaciones → Nuevo → tipo ntfy → URL del servidor → topic server-alerts → usuario/contraseña. Pruebe la notificación desde la UI.

    Grafana: Contact point → webhook → URL https://ntfy.ejemplo.com/grafana → cabeceras Authorization: Bearer tk_... y Content-Type: text/plain.

  8. Activar notificaciones de correo de respaldo (SMTP)

    Una vez configurado smtp-sender-addr en server.yml, envíe una notificación con la cabecera X-Email:
    curl -H "Authorization: Bearer $NTFY_TOKEN" -H "Title: Alerta crítica" -H "X-Email: [email protected]" -d "Disco lleno al 95%" https://ntfy.ejemplo.com/server-alerts
    ntfy envía el push Y el correo electrónico.

Autenticación y tokens de acceso: nunca exponga un topic público

Sin configuración, ntfy arranca sin control de acceso (la doc indica auth-default-access en read-write) — cualquiera que conozca la URL puede leer y escribir. En producción: auth-default-access: deny-all cierra el servidor; usuarios con contraseñas bcrypt en user.db; tokens de acceso vinculados a un usuario específico y revocables de forma independiente. Un token comprometido se revoca sin cambiar la contraseña del usuario.

Configuración multi-tenant: un servidor, varios equipos

Cree un usuario por servicio o equipo, concédale derechos solo sobre sus topics, y cada servicio creerá tener su propio hub. El rol admin ve todo; los usuarios normales están limitados a sus ACL. Para equipos con aislamiento total, despliegue dos contenedores ntfy en dos subdominios distintos.

Consejo: los nombres de topic como espacios de nombres y estrategia de silencio nocturno

ci-builds para GitHub Actions/GitLab CI, server-alerts para Uptime Kuma/Beszel, cron-jobs para scripts por lotes, backups para Backrest. La app ntfy le permite silenciar ciertos topics por la noche mientras mantiene server-alerts en alerta máxima con anulación de No molestar.

Resolución de problemas: 5 errores reales en producción

1. HTTP 403 Forbidden al publicar o suscribirse
Mensaje: {"code":40301,"http":403,"error":"Unauthorized"}
Causa: auth-default-access: deny-all activo y el token falta o ha caducado. Regenere el token con ntfy token add <usuario> y actualice sus scripts.

2. Notificación enviada pero nunca recibida en el móvil
En Android, compruebe primero que la app está suscrita a su instancia y no al servidor público ntfy.sh (URL en los ajustes de la app). En iOS, la causa más probable es la ausencia de upstream-base-url: "https://ntfy.sh" en server.yml: sin ese relé, la doc advierte de que la entrega puede tardar horas. Configúrelo y repase la checklist de la sección iOS más abajo. base-url también debe estar definido, pero la doc lo asocia a las URL de adjuntos y al pie de los correos, no a la llegada del push.

3. Enlaces incorrectos en los correos salientes
Sin base-url, el pie del correo (enlace a la notificación) se construye sin la URL pública y no sirve desde el exterior. Solución: establecer base-url: https://ntfy.ejemplo.com y reiniciar el contenedor.

4. Caídas repetidas de WebSocket en producción (reconexiones cada 30 s)
Causa: el timeout keepalive de nginx es inferior al intervalo de heartbeat de ntfy (keepalive-interval: "45s" en la configuración de ejemplo de la doc). Añada proxy_read_timeout 60; y proxy_send_timeout 60; al bloque location. Verifique también proxy_http_version 1.1; y proxy_set_header Upgrade $http_upgrade;.

5. OOM (Out of Memory) en un topic de alto volumen
Reduzca cache-duration a 1h o 30m. Filtre en el script (| grep -E 'ERROR|WARN') para enviar solo eventos relevantes. ntfy puede usar PostgreSQL en lugar de SQLite para sus almacenes (vea la doc de configuración).

iOS: por qué un ntfy autoalojado pasa por ntfy.sh para el push

En iOS una app no puede mantener una conexión abierta en segundo plano: la documentación de ntfy explica que esta restricción hace imposible un push instantáneo sin un servidor central. Su servidor autoalojado reenvía por tanto, por cada mensaje, una petición de «poll» a un servidor ascendente, ntfy.sh por defecto, que se encarga de despertar la app. El ajuste es upstream-base-url: "https://ntfy.sh". Esa petición solo contiene el identificador del mensaje (cabecera X-Poll-ID) y el hash SHA-256 de la URL del topic, nunca el texto: el servidor autoalojado envía literalmente «New message» y la app va a buscar el contenido real a su servidor. Sin upstream-base-url, la documentación advierte de que las notificaciones acaban llegando, pero la entrega puede tardar horas (20 a 30 minutos si el teléfono se usa activamente). upstream-access-token es opcional: la doc solo lo reserva para cuando se superan los límites del servidor ascendente o este está protegido.

Checklist iOS: siete comprobaciones antes de buscar más lejos

  • base-url — definido con la URL pública en HTTPS de su servidor, la que el teléfono puede alcanzar.
  • upstream-base-url — presente en server.yml (o como variable de entorno), valor https://ntfy.sh, contenedor reiniciado.
  • Servidor por defecto de la app — en los ajustes de la app iOS, la URL de su servidor es la declarada como servidor por defecto.
  • Suscripción al servidor correcto — el topic se añadió eligiendo su servidor, no ntfy.sh: un topic con el mismo nombre en el servidor público es otro topic.
  • Token ascendente — upstream-access-token solo sirve si se alcanzan los límites del relé; sin causa establecida, no lo añada por reflejo esperando arreglar el problema.
  • Registros del servidor — compruebe que el mensaje se publica y luego se transmite al relé. Si es así, su lado funciona y el problema está entre el relé, Apple y el teléfono.
  • Ajustes del teléfono — Actualización en segundo plano y Notificaciones activadas para la app, y ningún bloqueador DNS (AdGuard Home, Pi-hole) que filtre ntfy.sh.

Cuando no llega nada pese a todo: lo que dicen realmente las issues #1305 y #1844

Estas dos issues del repositorio de ntfy describen el síntoma que busca: un servidor autoalojado, un push iOS que no aparece, mensajes que solo aparecen al refrescar la app a mano. Leídas el 30 de octubre de 2026, ambas están abiertas y ninguna señala una causa confirmada.

#1305 «No push notifications on ios?» (abierta en marzo de 2025, etiquetas ios y bug). El autor no recibe ningún aviso, ni con ntfy.sh ni con su propia instancia. Algunos comentarios dicen que reinstalar la app ayudó, otros que el problema volvió meses después. Un colaborador propone que la app se reabone a los topics de Firebase al arrancar y abrió una PR en borrador, precisando que no pudo probarla. Un mantenedor pregunta al autor si la suscripción de Firebase es la causa, sin concluir.

#1844 «No iOS Push notification, also with valid subscription» (abierta en julio de 2026, etiquetas ios, server y bug). El autor ejecuta ntfy en Docker con NTFY_UPSTREAM_BASE_URL en https://ntfy.sh y NTFY_UPSTREAM_ACCESS_TOKEN informado. Dice haber alcanzado el límite gratuito de 250 mensajes al día y haber contratado después una suscripción de pago. Sus registros muestran el mensaje publicado y enviado al relé, y aun así ningún push. Un colaborador responde que los errores 429 pueden suponer un bloqueo de IP de hasta 4 horas, constata que la prueba con curl del autor funciona (por tanto no hay bloqueo) y que la cuenta mostraba 48 mensajes enviados de 2 500. Añade que las notificaciones iOS son caprichosas sin que se sepa exactamente por qué. Solución alternativa comunicada: desactivar y volver a activar «Actualización en segundo plano» y «Notificaciones» en los ajustes de iOS. El autor escribe que no sabe por qué funciona; el problema volvió, luego desapareció sin causa conocida, y otro usuario confirma la solución en septiembre de 2026. Otro informe relaciona un caso parecido con listas de bloqueo DNS.

Lo que se puede concluir y lo que no. Ni un límite diario de mensajes ni un bloqueo 429 quedan establecidos como causa en estos hilos: el 429 se descarta para la IP del autor, y el límite de 250 mensajes es una cifra dada por él, no por la documentación de configuración. El token ascendente no resuelve ahí el problema. Trate la lista anterior como comprobaciones, no como una corrección garantizada.

Tip: no confíe una alerta crítica solo al push de iOS

Mientras estas issues sigan abiertas, duplique las alertas que importan: añada la cabecera X-Email (vea el paso SMTP) para recibir también un correo, o mantenga un segundo canal en el teléfono. Los colaboradores de ambas issues sugieren además la PWA (web push) como alternativa a la app iOS. Y pruebe de extremo a extremo tras cada actualización de la app o de iOS, con el heartbeat del watchdog descrito más arriba.

Integraciones avanzadas: Backrest, Uptime Kuma, Grafana

Backrest soporta ntfy de forma nativa: configure la URL del topic y el token Bearer en la UI de Backrest, y cada snapshot completada o fallida genera automáticamente una notificación push con el nombre de la snapshot, el tamaño deduplicado y la duración. Cero scripts, cero cron.

Uptime Kuma soporta ntfy de forma nativa en su gestor de notificaciones. Cada monitor puede tener múltiples canales — combine ntfy para el push móvil y el SMTP de ntfy para la trazabilidad.

Grafana usa webhooks genéricos. Cree un contact point de tipo webhook, apúntelo a https://ntfy.ejemplo.com/grafana, añada las cabeceras Authorization: Bearer tk_... y Content-Type: text/plain.

Consejo: pruebe la cadena de entrega de extremo a extremo antes de confiar en ella

Antes de conectar su infraestructura a ntfy, pruebe la cadena completa: envíe una notificación con curl, confirme que aparece en la interfaz web, que llega a la app móvil, y que el correo SMTP de respaldo aterriza en la bandeja de entrada. Programe un cron */30 * * * * que envíe un heartbeat al topic watchdog — si la app móvil no lo recibe en 30 minutos, ntfy en sí mismo está caído.

Su hub de notificaciones bajo su control

Despliegue ntfy en un VPS ServOrbit y centralice todas sus alertas de monitoreo, CI/CD y cron en un hub de notificaciones autoalojado — sin SaaS, sin suscripción.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva