--- title: "Cómo instalar ntfy en Ubuntu 24.04 con Nginx y HTTPS" description: "Instala tu servidor de notificaciones push ntfy en Ubuntu 24.04 detrás de Nginx con HTTPS, protege los topics con usuarios y tokens y envía alertas con curl." category: "Herramientas de Servidor" language: es source: https://cubepath.com/es/docs/herramientas-de-servidor/instalacion-de-ntfy-servidor-de-notificaciones updated: 2026-09-25 --- # Cómo instalar ntfy en Ubuntu 24.04 con Nginx y HTTPS ntfy es un servidor de notificaciones push basado en HTTP: para enviar un aviso basta con hacer una petición `POST` a un topic, y cualquier móvil, navegador o script suscrito a ese topic lo recibe al momento. En este tutorial instalarás ntfy en Ubuntu 24.04 desde su repositorio oficial, lo publicarás detrás de Nginx con un certificado de Let's Encrypt, cerrarás el acceso con usuarios y tokens, y configurarás systemd para que te avise cuando un servicio falle. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, y un usuario no root con privilegios `sudo`. ntfy consume muy pocos recursos: 512 MB de RAM son suficientes. - Un subdominio (en esta guía, `ntfy.your_domain`) con un registro DNS A que apunte a la IP del servidor. - Nginx instalado y los puertos 80 y 443 abiertos. Si usas UFW: `sudo ufw allow 'Nginx Full'`. - La aplicación de ntfy en tu móvil (Android o iOS) para probar la recepción, opcional. ## Paso 1: Instalar ntfy desde el repositorio oficial El autor de ntfy mantiene un repositorio APT con paquetes para amd64, arm64 y armhf. Descarga su clave en `/etc/apt/keyrings`: ```bash sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg ``` Añade el repositorio para la arquitectura de tu servidor e instala el paquete: ```bash echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main" | sudo tee /etc/apt/sources.list.d/archive.heckel.io.list sudo apt update sudo apt install ntfy ``` Comprueba la versión instalada: ```bash dpkg -s ntfy | grep '^Version' ``` El paquete crea el usuario de sistema `ntfy`, la unidad `ntfy.service` y un archivo de configuración de ejemplo en `/etc/ntfy/server.yml` con todas las opciones comentadas. ## Paso 2: Configurar el servidor Por defecto ntfy escucha en el puerto 80, que en este servidor usará Nginx. Lo configurarás para que escuche solo en `127.0.0.1:2586`, guarde los mensajes en disco para que los clientes que se reconectan no los pierdan y deniegue el acceso a cualquier usuario no autenticado. Crea los directorios de datos con el propietario correcto: ```bash sudo install -d -o ntfy -g ntfy /var/lib/ntfy /var/cache/ntfy ``` Guarda una copia del archivo de ejemplo y edita la configuración: ```bash sudo cp /etc/ntfy/server.yml /etc/ntfy/server.yml.orig sudo nano /etc/ntfy/server.yml ``` Sustituye el contenido por lo siguiente, cambiando `ntfy.your_domain`: ```yaml base-url: "https://ntfy.your_domain" listen-http: "127.0.0.1:2586" behind-proxy: true cache-file: "/var/cache/ntfy/cache.db" cache-duration: "12h" auth-file: "/var/lib/ntfy/user.db" auth-default-access: "deny-all" attachment-cache-dir: "/var/cache/ntfy/attachments" attachment-file-size-limit: "15M" upstream-base-url: "https://ntfy.sh" ``` Qué hace cada bloque: - `base-url` es la URL pública del servidor y es obligatoria para los adjuntos y para la aplicación web. - `behind-proxy: true` hace que ntfy lea la IP del cliente de la cabecera `X-Forwarded-For` que envía Nginx, necesario para que los límites por visitante funcionen. - `cache-file` y `cache-duration` guardan los mensajes 12 horas; también son necesarios para programar mensajes. - `auth-default-access: "deny-all"` obliga a autenticarse para leer o publicar en cualquier topic. - `upstream-base-url` reenvía un aviso sin contenido a `ntfy.sh` para que la aplicación de iOS reciba notificaciones instantáneas de un servidor propio. El texto del mensaje nunca sale de tu servidor. Si no usas iOS, puedes quitar esta línea. Habilita y arranca el servicio: ```bash sudo systemctl enable --now ntfy ``` Verifica que está activo y responde en local: ```bash sudo systemctl status ntfy --no-pager curl -s http://127.0.0.1:2586/v1/health ``` ```output {"healthy":true} ``` Si el servicio no arranca, `sudo journalctl -u ntfy -n 50 --no-pager` muestra el error, normalmente una clave mal escrita en `server.yml`. ## Paso 3: Publicar ntfy con Nginx y HTTPS ntfy mantiene conexiones abiertas (HTTP streaming y WebSocket) con los clientes suscritos, así que Nginx no debe almacenar las respuestas en búfer y debe permitir conexiones largas. Crea el sitio: ```bash sudo nano /etc/nginx/sites-available/ntfy ``` ```nginx server { listen 80; listen [::]:80; server_name ntfy.your_domain; location / { proxy_pass http://127.0.0.1:2586; proxy_http_version 1.1; proxy_buffering off; proxy_request_buffering off; proxy_redirect off; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 3m; proxy_send_timeout 3m; proxy_read_timeout 3m; client_max_body_size 20M; } } ``` Activa el sitio, valida la configuración y recarga Nginx: ```bash sudo ln -s /etc/nginx/sites-available/ntfy /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` Obtén el certificado con Certbot. El plugin de Nginx añade la configuración TLS y la redirección de HTTP a HTTPS en el mismo archivo: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d ntfy.your_domain ``` Comprueba el acceso desde fuera: ```bash curl -s https://ntfy.your_domain/v1/health ``` ```output {"healthy":true} ``` ## Paso 4: Crear usuarios, permisos y tokens Con `deny-all`, nadie puede usar el servidor hasta que crees usuarios. Los comandos `ntfy user`, `ntfy access` y `ntfy token` leen la ruta de la base de datos de `/etc/ntfy/server.yml`, por eso se ejecutan con `sudo` en el propio servidor. Crea un administrador, que tiene acceso completo a todos los topics. Te pedirá la contraseña: ```bash sudo ntfy user add --role=admin your_user ``` Crea un usuario sin privilegios para los scripts y dale permiso solo sobre el topic `alertas`. Los niveles son `read-write` (`rw`), `read-only` (`ro`), `write-only` (`wo`) y `deny`: ```bash sudo ntfy user add monitor sudo ntfy access monitor alertas wo ``` Para los scripts es mejor un token que una contraseña: se puede revocar sin cambiar la contraseña del usuario. Genera uno para `monitor`: ```bash sudo ntfy token add monitor ``` ```output token tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 created for user monitor, never expires ``` Revisa los permisos resultantes: ```bash sudo ntfy access ``` La salida debe mostrar a `your_user` con acceso de lectura y escritura a todos los topics por su rol de administrador, a `monitor` con acceso de solo escritura a `alertas` y al usuario anónimo (`*`) sin acceso a ningún topic. ## Paso 5: Enviar notificaciones Suscríbete primero al topic para ver los mensajes. En la aplicación móvil, añade el servidor `https://ntfy.your_domain` con tu usuario administrador en los ajustes de usuarios y suscríbete al topic `alertas`. También puedes abrir `https://ntfy.your_domain/alertas` en el navegador e iniciar sesión. Envía un mensaje con el token de `monitor` (sustituye `your_token`). El cuerpo de la petición es el texto de la notificación: ```bash curl -H "Authorization: Bearer your_token" -d "Copia de seguridad terminada" https://ntfy.your_domain/alertas ``` ntfy responde con el mensaje en JSON y la notificación aparece en los clientes suscritos: ```output {"id":"hN3kd9Zq2cXy","time":1790331120,"expires":1790374320,"event":"message","topic":"alertas","message":"Copia de seguridad terminada"} ``` Las cabeceras permiten añadir título, prioridad (de `1`, mínima, a `5`, máxima), etiquetas (que se muestran como emojis si coinciden con un nombre de emoji) y un enlace que se abre al pulsar la notificación: ```bash curl \ -H "Authorization: Bearer your_token" \ -H "Title: Disco casi lleno en web01" \ -H "Priority: 4" \ -H "Tags: warning,floppy_disk" \ -H "Click: https://grafana.your_domain" \ -d "La particion / esta al 91%" \ https://ntfy.your_domain/alertas ``` > Nota: los valores de las cabeceras HTTP deben ser ASCII. Si necesitas tildes o eñes en el título, envía el mensaje como JSON a la raíz del servidor o usa el parámetro `?title=` codificado en la URL. Para programar un mensaje, usa la cabecera `In` con un intervalo: ```bash curl -H "Authorization: Bearer your_token" -H "In: 30min" -d "Revisar la migracion" https://ntfy.your_domain/alertas ``` Comprueba que un usuario sin permisos no puede publicar. Una petición sin credenciales debe recibir un `403`: ```bash curl -s -o /dev/null -w "%{http_code}\n" -d "prueba" https://ntfy.your_domain/alertas ``` ```output 403 ``` ## Paso 6: Recibir un aviso cuando falle un servicio systemd puede lanzar otra unidad cuando una falla, mediante la directiva `OnFailure=`. Usarás una unidad plantilla que llama a un pequeño script con el nombre del servicio caído. Guarda la URL y el token en un archivo que solo pueda leer root: ```bash sudo nano /etc/ntfy-alert.env ``` ```ini NTFY_URL=https://ntfy.your_domain/alertas NTFY_TOKEN=your_token ``` ```bash sudo chmod 600 /etc/ntfy-alert.env ``` Crea el script que envía el aviso con las últimas líneas del estado del servicio: ```bash sudo nano /usr/local/bin/ntfy-alert-failure ``` ```bash #!/usr/bin/env bash set -euo pipefail unit="$1" status="$(systemctl status --no-pager --lines=10 "$unit" 2>&1 || true)" curl -fsS -m 10 --retry 3 -o /dev/null \ -H "Authorization: Bearer ${NTFY_TOKEN}" \ -H "Title: Fallo de ${unit} en $(hostname)" \ -H "Priority: 5" \ -H "Tags: rotating_light" \ -d "$status" \ "$NTFY_URL" ``` ```bash sudo chmod 755 /usr/local/bin/ntfy-alert-failure ``` Crea la unidad plantilla. `%i` es el nombre que va detrás de la `@`: ```bash sudo nano /etc/systemd/system/ntfy-alert@.service ``` ```ini [Unit] Description=Aviso ntfy por fallo de %i [Service] Type=oneshot EnvironmentFile=/etc/ntfy-alert.env ExecStart=/usr/local/bin/ntfy-alert-failure %i ``` Recarga systemd y prueba la unidad a mano. Debe llegarte una notificación con el título `Fallo de prueba.service`: ```bash sudo systemctl daemon-reload sudo systemctl start ntfy-alert@prueba.service ``` Ahora engánchala a los servicios que quieras vigilar con un archivo de override. Por ejemplo, para Nginx: ```bash sudo systemctl edit nginx ``` Añade estas líneas en la zona editable del archivo: ```ini [Unit] OnFailure=ntfy-alert@%n.service ``` En el override, `%n` se sustituye por el nombre completo de la unidad (`nginx.service`). Comprueba que la directiva se ha aplicado: ```bash systemctl show nginx -p OnFailure ``` ```output OnFailure=ntfy-alert@nginx.service.service ``` La doble extensión es esperable: `%n` ya incluye `.service` y el script recibe `nginx.service`, que es lo que `systemctl status` necesita. ## Solución de problemas **La aplicación muestra "unauthorized" al suscribirse.** El usuario configurado en la aplicación no tiene permiso de lectura sobre ese topic. Revisa `sudo ntfy access` y concede `ro` o `rw` al usuario con el que se conecta el móvil. **Las notificaciones llegan con retraso o solo al abrir la aplicación.** En Android, desactiva la optimización de batería para ntfy. En iOS, comprueba que `upstream-base-url` está configurado y que el servidor puede conectar por HTTPS con `ntfy.sh`. **Nginx devuelve 502.** ntfy no está escuchando en `127.0.0.1:2586`. Comprueba `sudo systemctl status ntfy` y que `listen-http` coincide con el `proxy_pass` de Nginx. ## Conclusión Tienes un servidor ntfy propio detrás de Nginx con HTTPS, con los topics cerrados por defecto, un token de solo escritura para tus scripts y avisos automáticos cuando falla un servicio de systemd. Como siguientes pasos, puedes usar el mismo token en las alertas de Grafana o Uptime Kuma (ambos tienen integración con ntfy), crear un topic por entorno o por equipo con permisos distintos y añadir `/var/lib/ntfy/user.db` a tus copias de seguridad.