Uptime Kuma en Docker para monitorización externa
Instale Uptime Kuma en Docker para vigilar webs, puertos, DNS y cron desde otro VPS, con alertas por correo, Telegram, Discord o webhook y página de estado.
Qué va a crear
Un único contenedor pequeño que supervisa sus otros servidores y sitios web desde el exterior y le avisa en cuanto uno deja de responder, por correo electrónico, Telegram, Discord o un webhook. Uptime Kuma es un proceso de Node respaldado por un archivo SQLite, por lo que funciona sin problemas con 256-512 MB de RAM y ofrece un panel en tiempo real, gráficos históricos y una página de estado pública. La instalación consta de un archivo Compose de diez líneas. Lo que realmente importa es dónde lo ejecuta y si alguna vez ha comprobado que las alertas se activan en una prueba, porque un monitor cuya capacidad para avisarle nunca se ha verificado es peor que no tener ninguno: le hace creer que está protegido mientras no supervisa nada.
Ejecute el monitor en un lugar al que no llegue la interrupción
Esta decisión determina si todo el sistema funciona o no, por eso aparece primero. No ejecute Uptime Kuma en el mismo servidor que los servicios que supervisa. Si el monitor está en el servidor supervisado, el mismo evento que le interesa detectar —que ese servidor deje de funcionar o se quede sin memoria— también detiene el monitor y no recibe ninguna alerta: el silencio de un monitor detenido es idéntico a que «todo funciona correctamente». Hay un problema más sutil incluso cuando el servidor sigue activo: un monitor dirigido a localhost comparte la CPU con la carga de trabajo, por lo que un aumento de carga hace que su propia comprobación agote el tiempo de espera y marque el objetivo como caído. Es una falsa alarma; los usuarios reales siguen recibiendo servicio.
Por tanto, ejecute Uptime Kuma en un VPS distinto del que supervisa, preferiblemente con otro proveedor o en otra región, y acceda a sus servicios como lo hacen los usuarios: a través de Internet pública y mediante el nombre de host. Una instancia económica es suficiente, y un VPS pequeño de monitorización puede supervisar todos sus servidores. Esta separación es especialmente importante para las aplicaciones exigentes que aloja, ya que algo como una biblioteca de fotos de PhotoPrism o Immich puede mantener la CPU ocupada durante horas mientras indexa una importación reciente. Un monitor que comparta ese hardware marcaría como caído un servicio que sólo está ocupado. Para detectar que el propio Kuma ha dejado de funcionar, añada un heartbeat push desde un cron externo.
Requisitos previos y dimensionamiento
- Un VPS nuevo con Ubuntu 24.04, Docker Engine y el complemento Compose v2 instalados desde el repositorio apt del propio Docker, no desde el paquete
docker.iode la distribución, que suele estar desactualizado. - 256 MB de RAM son suficientes para varios monitores; entre 512 MB y 1 GB ofrecen margen para varias decenas, además del proxy inverso. El uso de CPU es casi nulo entre comprobaciones.
- Un dominio y un registro DNS
A(por ejemplo,status.example.comque apunte al VPS), sólo si quiere TLS y una página de estado pública. Una instancia privada puede omitir DNS y usar una VPN o un túnel SSH. - Acceso de red saliente a los destinos de las alertas: SMTP hacia su proveedor de correo o HTTPS hacia Telegram y Discord.
El archivo Compose
Coloque lo siguiente en /srv/uptime-kuma/compose.yaml.
services:
uptime-kuma:
image: louislam/uptime-kuma:2
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- kuma-data:/app/data
volumes:
kuma-data:Inícielo y supervise el primer arranque:
sudo mkdir -p /srv/uptime-kuma
# save the file above as /srv/uptime-kuma/compose.yaml, then:
cd /srv/uptime-kuma && sudo docker compose up -d
sudo docker compose logs -f uptime-kumaUn arranque correcto registra Listening on 3001 y deja de generar mensajes. Hay tres aspectos deliberados en ese archivo.
127.0.0.1:3001:3001, no 3001:3001. Docker publica los puertos mediante reglas DNAT que se evalúan antes de que ufw vea el paquete. Por tanto, un 3001:3001 sin restricciones expone el panel en Internet, independientemente del firewall. El enlace con loopback lo mantiene privado y deja expuesto únicamente el reverse proxy. Una instancia privada puede omitir el proxy y acceder a 3001 mediante una VPN WireGuard autogestionada.
Un volumen con nombre en /app/data. Todo lo que Uptime Kuma conserva, incluida la base de datos SQLite, las comprobaciones, la configuración de notificaciones y los logotipos de las páginas de estado, se almacena allí. Si lo pierde, volverá a una pantalla de administración vacía. Es el único elemento que debe incluir en las copias de seguridad.
La imagen está fijada a la etiqueta principal :2. Esa es la línea estable actual. Consulte Docker Hub para comprobar cuál es la versión principal más reciente antes de copiarla. Nunca siga una etiqueta cambiante como latest, que el proyecto ha declarado obsoleta. En esta imagen, el salto de una versión principal provoca una migración de base de datos irreversible. Debe iniciarlo deliberadamente y no encontrarlo por sorpresa durante una actualización rutinaria.
Hay una salvedad: /app/data debe encontrarse en un sistema de archivos compatible con bloqueos de archivos POSIX. Un volumen local de Docker es adecuado. En NFS, la base de datos SQLite se corrompe y aparecen SQLITE_BUSY y database disk image is malformed. Por tanto, no use nunca un recurso compartido de red.
Primera ejecución: cree la cuenta de administrador
Acceda a la instancia a través del proxy en https://status.example.com o mediante un túnel SSH: ejecute ssh -L 3001:127.0.0.1:3001 user@your-vps y abra http://localhost:3001. La primera página es un formulario de configuración para el nombre de usuario y la contraseña del administrador. No existe un inicio de sesión predeterminado. Elija una contraseña segura: este panel puede ver las direcciones internas y los tokens de todo lo que monitoriza. ¿La ha olvidado? Restablézcala desde el host, no desde el navegador:
sudo docker compose exec uptime-kuma npm run reset-passwordAñada primero los canales de notificación y pruébelos
Configure las alertas antes de añadir monitores para poder asociar un canal al crear cada uno. Vaya a Settings then Notifications then Setup Notification y use el botón Test de cada canal para confirmar que el mensaje llega. Una notificación sin probar es la segunda causa más habitual de que una configuración falle silenciosamente.
Correo electrónico (SMTP). Introduzca el host, el puerto, el cifrado, el nombre de usuario, la contraseña, un campo From y un campo To. Las dos combinaciones válidas son 465 con "Secure" establecido en TLS/SSL, o 587 con STARTTLS. En Gmail y en la mayoría de los proveedores con autenticación de dos factores debe generar una app password; una contraseña normal de la cuenta devuelve Error: Invalid login: 535-5.7.8 Username and Password not accepted.
Telegram. Envíe el mensaje @BotFather, envíe /newbot y copie el token del bot. Para obtener el ID del chat, envíe primero un mensaje al bot nuevo, abra https://api.telegram.org/bot<token>/getUpdates y lea chat.id del JSON. Un bot al que nunca se ha enviado un mensaje primero tiene un getUpdates vacío y no tiene dónde enviar mensajes.
Discord. En el canal, abra Edit Channel then Integrations then Webhooks then New Webhook, copie la URL y péguela como una notificación de Discord.
Webhook genérico. Para cualquier otro servicio, como un webhook entrante de Slack, un endpoint personalizado o un webhook de automatización doméstica, el tipo Webhook envía una carga JSON mediante POST a la URL que indique. La integración incluida de Apprise cubre la mayoría de los otros aproximadamente noventa servicios de la lista. Si prefiere que ningún tercero se interponga entre una interrupción y su teléfono, elija el tipo integrado ntfy y apúntelo a un servidor ntfy que administre usted mismo, que envía las notificaciones a su dispositivo mediante un canal que controla de extremo a extremo.
Añadir monitores, uno por tipo
Haga clic en Add New Monitor, elija un tipo y configure el Friendly Name, el Check Interval (60 segundos es un valor razonable), los Retries (fallos consecutivos antes de marcarlo como «down»; use 2 o 3 para que un paquete perdido no genere una alerta) y las notificaciones que deben activarse. Estos son los tipos que usará:
- HTTP(s). Una URL completa. Está disponible cuando devuelve un código de estado aceptado (200-299 de forma predeterminada; amplíe el intervalo en Accepted Status Codes si
301o401es normal en su caso). Es el monitor principal para sitios web y API. - HTTP(s) - Keyword. Envía la misma solicitud, pero sólo marca el servicio como disponible si el cuerpo contiene una cadena o, con Invert, si no la contiene. Detecta que el sitio devuelva
200 OKmientras muestra «Error establishing a database connection», algo que un monitor HTTP simple considera correcto. También es el monitor adecuado para una interfaz web que se comunica con un backend independiente, como una interfaz de tienda de vídeo Halcyon sobre Jellyfin, cuya estructura de página devuelve200aunque el servidor multimedia subyacente no esté disponible. - TCP Port. Una conexión TCP directa con un host y un puerto, para servicios que no usan HTTP: SSH en 22, Postgres en 5432, un servidor SMTP en 25 o un servidor de juegos.
- Ping. Eco ICMP para comprobar la disponibilidad y la latencia con un coste bajo. Sin embargo, muchas redes y firewalls en la nube bloquean ICMP. Por tanto, un monitor de ping en rojo puede indicar que el host está caído o que el proveedor bloquea el ping. Confírmelo con un monitor TCP.
- DNS. Resuelve un registro (A, AAAA, MX, TXT, entre otros) mediante el resolver que indique y puede comprobar la respuesta. Esto permite detectar pronto una interrupción del registrador o de DNS.
- Push. El monitor que funciona desde dentro hacia fuera, descrito a continuación.
Supervisión de un trabajo de cron con un monitor push (heartbeat)
Todos los monitores anteriores acceden a su servicio desde el exterior. Un monitor push funciona al contrario: Uptime Kuma espera y su trabajo lo llama para indicar que se ejecutó. Es la única forma fiable de supervisar una copia de seguridad o un trabajo de cron: una comprobación HTTP sabe que una URL responde, pero sólo el trabajo sabe si terminó correctamente.
Cree un monitor de tipo Push. Uptime Kuma genera una URL única como esta:
https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=OK&ping=Establezca Heartbeat Interval en la frecuencia con la que se ejecuta el trabajo, más un pequeño margen. Después, añada una línea al final del script para que se ejecute sólo si el trabajo termina correctamente:
#!/usr/bin/env bash
set -euo pipefail
# ... your backup or job runs here; set -e aborts on any failure ...
curl -fsS --retry 3 "https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=backup+ok&ping="Si el trabajo falla, set -e se interrumpe antes de ejecutar curl; si el equipo está apagado, tampoco se ejecuta. En ambos casos, el heartbeat se detiene y, cuando transcurre el intervalo más los reintentos, Uptime Kuma cambia el monitor a down y le envía una alerta. Trate ese token push como un secreto: cualquiera que lo tenga puede falsificar un heartbeat correcto.
Crear una página de estado pública
Una página de estado es la vista para los clientes: muestra qué servicios están disponibles y su historial reciente, sin exponer el panel. Vaya a Status Pages y, después, New Status Page, asígnele un nombre y un slug (la ruta pública, como /status/main), arrastre los monitores que quiera a grupos como "Websites" y "APIs", añada un logotipo y una descripción breve, y haga clic en Save. También puede asociar la página a su propio dominio para que status.example.com la sirva directamente.
Tenga en cuenta dos aspectos: añada sólo los monitores que esté dispuesto a hacer públicos, porque una página de estado revela que existe un servicio e indica si está disponible; además, el panel sigue protegido por su inicio de sesión, mientras que la página de estado es pública de forma intencionada y no requiere autenticación.
Colóquelo detrás de un reverse proxy con TLS y tenga en cuenta los WebSocket
Para una instancia pública, coloque un reverse proxy delante del contenedor enlazado a loopback para gestionar TLS y un nombre de host. El detalle que suele causar problemas: la interfaz de Uptime Kuma es una aplicación Socket.IO activa, por lo que el proxy debe actualizar la conexión WebSocket. Si se omite, la página carga, pero nunca se conecta; el panel queda en "Connecting...", los heartbeats en tiempo real no se actualizan y la consola del navegador muestra WebSocket connection to 'wss://.../socket.io/...' failed.
Instale nginx y certbot. Después, escriba el vhost que haga proxy hacia el puerto de loopback. Déjelo en el puerto 80 por ahora y permita que certbot añada TLS después; el desafío, el temporizador de renovación y sus modos de fallo se explican en emitir certificados de Let's Encrypt con certbot y nginx.
sudo apt install -y nginx certbot python3-certbot-nginxGuarde esto como /etc/nginx/sites-available/status.example.com; las dos líneas de WebSocket son las importantes:
server {
listen 80;
server_name status.example.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
}Habilite el sitio y pruebe la configuración. Después, permita que certbot reescriba el bloque para escuchar en 443, instale el certificado y añada una redirección de HTTP a HTTPS:
sudo ln -s /etc/nginx/sites-available/status.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d status.example.comEl par Upgrade y Connection "upgrade" es lo esencial. proxy_read_timeout 3600s evita que nginx cierre el socket de larga duración; certbot copia ambas directivas en el bloque de 443 que genera. Si ya ejecuta varios contenedores detrás de un único proxy, enrutarlos mediante Traefik con TLS automático hace lo mismo con etiquetas de contenedor y reenvía las actualizaciones de WebSocket de forma predeterminada.
No proteja todo el vhost con autenticación básica, porque eso también bloquea la página de estado pública y el endpoint /api/push. Mantenga el inicio de sesión integrado de Uptime Kuma. Añada fail2ban para supervisar repetidos intentos de inicio de sesión fallidos si está expuesto a Internet. Si el panel nunca debe ser público, elimine el proxy y acceda a él mediante una VPN.
Supervisión de la caducidad de certificados, bien configurada
Un monitor HTTP(s) también puede avisarle antes de que caduque un certificado TLS: active Certificate Expiry Notification y Uptime Kuma enviará alertas cuando falte el número de días configurado. Dos errores pueden hacer que la comprobación sea incorrecta. Supervise por nombre de host, no por IP, porque una solicitud sin SNI recibe el certificado predeterminado del servidor y muestra Hostname/IP does not match certificate's altnames. Tampoco active Ignore TLS/SSL Error en un monitor del que quiera recibir avisos de caducidad: esa opción se usa para hosts internos con certificados autofirmados (unable to verify the first certificate, DEPTH_ZERO_SELF_SIGNED_CERT), pero hace que Uptime Kuma deje de comprobar el certificado, incluida su caducidad.
Copias de seguridad: es un solo directorio
Como todo se almacena en /app/data, una copia de seguridad es una copia de ese volumen tomada mientras el contenedor está detenido. Así, el archivo de SQLite queda en un estado coherente:
cd /srv/uptime-kuma
sudo docker compose stop
sudo docker run --rm \
-v uptime-kuma_kuma-data:/data \
-v /var/backups/kuma:/backup \
alpine tar czf /backup/kuma-$(date -u +%Y%m%dT%H%M%SZ).tgz -C /data .
sudo docker compose startConfirme primero el nombre real del volumen con docker volume ls | grep kuma, porque Compose le antepone el directorio del proyecto. Después, copie el archivo tar fuera del servidor. Una copia de seguridad en el mismo VPS es una copia, no una copia de seguridad. La restauración se realiza en sentido inverso: detenga la pila, extraiga el contenido en un volumen /app/data vacío y vuelva a iniciarla.
Actualizaciones
Las actualizaciones consisten en extraer una imagen:
cd /srv/uptime-kuma
sudo docker compose pull
sudo docker compose up -dEl contenedor nuevo ejecuta cualquier migración de la base de datos durante el primer arranque; monitorice docker compose logs -f. Realice la copia de seguridad indicada arriba antes de extraer la imagen y manténgase dentro de la misma etiqueta principal: pasar de :1 a :2 es una migración irreversible, así que haga primero una copia de seguridad y revise las notas de la versión.
Modos de fallo y cadenas que verá
Falso estado «caído» en un monitor dirigido a localhost. El monitor cambia a rojo con timeout of 48000ms exceeded o connect ETIMEDOUT, pero el servicio responde desde su portátil. Si apunta al mismo host donde se ejecuta Uptime Kuma, un pico de CPU o memoria dejó sin recursos a la comprobación, no al destino. Mueva el monitor a un VPS independiente y diríjalo al nombre de host público.
connect ECONNREFUSED 127.0.0.1:443 (o cualquier puerto). No había ningún proceso escuchando en ese puerto: el servicio está detenido o supervisó localhost desde dentro del contenedor, donde 127.0.0.1 es el contenedor, no el servidor. Supervise el nombre de host público, no loopback.
Invalid login: 535-5.7.8 Username and Password not accepted en una prueba de correo electrónico. Las credenciales SMTP son incorrectas o el proveedor requiere una contraseña específica de aplicación y recibió la contraseña de su cuenta. Genere una contraseña de aplicación y péguela.
connect ETIMEDOUT o queryA ETIMEDOUT <host> en una prueba de correo electrónico. El puerto es incorrecto o el proveedor bloquea el SMTP saliente. Confirme que 465 o 587 coincida con la configuración Secure/STARTTLS y pruebe desde el host con nc -vz smtp.example.com 587. Muchos proveedores bloquean 25 saliente y algunos bloquean los puertos de envío hasta que lo solicite.
self signed certificate o unable to verify the first certificate en una prueba de correo electrónico. El servidor SMTP presenta un certificado en el que Node no confía; corrija el certificado del servidor de correo en lugar de omitir la validación.
El panel se queda en «Connecting...» y la consola muestra WebSocket connection ... failed. El proxy inverso no está actualizando la conexión WebSocket. Añada las cabeceras Upgrade y Connection "upgrade" en nginx o use un proxy que las reenvíe de forma predeterminada, como Traefik o Caddy. El HTML se carga porque es una solicitud HTTP GET normal; sólo el socket activo necesita la actualización.
El monitor de caducidad de certificados nunca avisa o avisa incorrectamente. Puede que Ignore TLS/SSL Error esté marcado, lo que desactiva la comprobación del certificado, o que el monitor apunte a una IP y lea el certificado incorrecto por falta de SNI, mostrando Hostname/IP does not match certificate's altnames. Desmarque la opción de ignorar errores y supervise mediante el nombre de host.
SQLITE_BUSY o database disk image is malformed en los registros. El volumen /app/data está en un sistema de archivos sin bloqueo de archivos adecuado, normalmente NFS; muévalo a un volumen Docker local y restáurelo desde una copia de seguridad.
FAQ
¿Dónde debo ejecutar mi monitor de disponibilidad?
En un servidor distinto de los que supervisa, idealmente en otro proveedor o región, y accediendo a ellos por nombre de host a través de Internet pública, igual que sus usuarios. Si el monitor comparte servidor con sus objetivos, la interrupción que deja el servidor fuera de servicio también deja el monitor fuera de servicio, y un host sobrecargado puede marcar como "down" servicios que funcionan correctamente. Un VPS pequeño e independiente evita ambos problemas.
¿Cómo recibo alertas en Telegram o por correo electrónico?
Añada el canal en Settings then Notifications y asígnelo a cada monitor. Para Telegram, cree un bot con @BotFather y lea chat.id de https://api.telegram.org/bot<token>/getUpdates; para el correo electrónico, use 465 para SSL o 587 para STARTTLS, con una contraseña de aplicación si su proveedor utiliza autenticación de dos factores. Pulse Test y confirme que el mensaje llega antes de depender de ese canal.
¿Puede Uptime Kuma supervisar un trabajo de cron o un script de copia de seguridad?
Sí. Ese es el monitor Push: Uptime Kuma le proporciona una URL y usted ejecuta curl al final del script, de modo que sólo se active si la ejecución termina correctamente. Si el trabajo falla o el servidor está fuera de servicio, el latido nunca llega y recibirá una alerta cuando transcurra el intervalo. Es la única forma fiable de saber que un trabajo programado se ejecutó realmente, porque una comprobación externa no puede ver lo que ocurre dentro de él.
Uptime Kuma frente a Zabbix: ¿cuál debo ejecutar?
Uptime Kuma responde en diez minutos, con un consumo mínimo de recursos, a las preguntas "¿está disponible desde el exterior y me ha enviado una alerta?", y además ofrece una página de estado. No recopila métricas detalladas, como tendencias de CPU, memoria y disco, ni aplica umbrales para toda una flota. Para eso, un servidor completo de monitorización Zabbix es la herramienta basada en agentes y con mayor consumo de recursos; muchas personas ejecutan ambos. Si todavía no sabe qué ejecutar, nuestro resumen de lo que puede alojar por su cuenta en 2026 explica el contexto de la monitorización.