Una página de estado autoalojada te permite informar de caídas y mantenimientos sin pagar por servicios como Instatus o Atlassian Statuspage y sin depender de sus límites de componentes o suscriptores. En esta guía compararás las opciones open source más usadas y después desplegarás Gatus con Docker en Ubuntu 24.04: una página de estado que además comprueba tus servicios, guarda el historial, envía alertas y respeta ventanas de mantenimiento.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS y 1 GB de RAM, por ejemplo un VPS de CubePath, distinto de los servidores que vas a monitorizar.
- Un usuario no root con privilegios
sudo. - Docker Engine y el plugin Docker Compose instalados desde el repositorio oficial de Docker.
- Un subdominio como
status.your_domaincon un registro A apuntando al servidor. - Los puertos 22, 80 y 443 abiertos en UFW.
Importantesi la página de estado vive en el mismo servidor o en la misma red que los servicios que monitoriza, se caerá con ellos. Colócala en otra ubicación o en otro proveedor.
Comparativa de soluciones
| Solución | Tipo | Monitoriza por sí sola | Gestión de incidentes | Dónde se ejecuta |
|---|---|---|---|---|
| Gatus | Aplicación Go, configurada en YAML | Sí (HTTP, TCP, DNS, ICMP, certificados) | Estado automático según las comprobaciones | Docker o binario, SQLite o PostgreSQL |
| Uptime Kuma | Aplicación Node.js con interfaz web | Sí | Incidentes y mantenimientos desde la interfaz | Docker o Node.js |
| Upptime | GitHub Actions + GitHub Pages | Sí, desde los runners de GitHub | Incidentes como issues de GitHub | GitHub, sin servidor propio |
| cState | Sitio estático con Hugo | No | Incidentes como archivos Markdown | Cualquier hosting estático |
Cómo elegir:
- Gatus si quieres que el estado se calcule solo a partir de comprobaciones reales y prefieres configurarlo todo como código en un archivo versionable.
- Uptime Kuma si prefieres una interfaz web para añadir monitores y publicar incidentes a mano.
- Upptime o cState si no quieres mantener ningún servidor: la página se aloja en GitHub Pages u otro hosting estático.
El resto de la guía despliega Gatus.
Paso 1: Crear la configuración de Gatus
Gatus lee toda su configuración de un archivo YAML: qué endpoints comprobar, con qué condiciones y a quién avisar. Crea un directorio para el proyecto:
sudo mkdir -p /opt/gatus
cd /opt/gatus
Crea el archivo de configuración:
sudo nano /opt/gatus/config.yaml
Este ejemplo comprueba una web, el endpoint de salud de una API, un puerto de base de datos y la caducidad del certificado TLS. Sustituye los dominios por los tuyos:
storage:
type: sqlite
path: /data/gatus.db
ui:
title: Estado de los servicios
header: Estado de los servicios
link: https://your_domain
alerting:
email:
from: alertas@your_domain
username: alertas@your_domain
password: ${SMTP_PASSWORD}
host: smtp.your_domain
port: 587
to: sre@your_domain
default-alert:
failure-threshold: 3
success-threshold: 2
send-on-resolved: true
endpoints:
- name: Web
group: Servicios web
url: https://your_domain
interval: 1m
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 2000"
alerts:
- type: email
- name: API
group: Servicios web
url: https://api.your_domain/health
interval: 1m
conditions:
- "[STATUS] == 200"
- "[BODY].status == ok"
alerts:
- type: email
- name: Base de datos
group: Infraestructura
url: tcp://db.your_domain:5432
interval: 1m
conditions:
- "[CONNECTED] == true"
alerts:
- type: email
- name: Certificado TLS
group: Infraestructura
url: https://your_domain
interval: 1h
conditions:
- "[CERTIFICATE_EXPIRATION] > 336h"
alerts:
- type: email
Algunos detalles:
- Cada endpoint aparece en la página dentro de su
group, y su estado es verde solo si se cumplen todas lasconditions. [BODY].status == oklee el campostatusde una respuesta JSON; adáptalo a lo que devuelva tu endpoint de salud.failure-threshold: 3evita avisar por un fallo aislado: la alerta salta tras tres comprobaciones fallidas seguidas.${SMTP_PASSWORD}se sustituye por la variable de entorno del mismo nombre, así la contraseña no queda en el YAML.
Guarda la contraseña SMTP en un archivo de entorno que solo pueda leer root. Sustituye your_smtp_password por la real:
echo "SMTP_PASSWORD=your_smtp_password" | sudo tee /opt/gatus/.env > /dev/null
sudo chmod 600 /opt/gatus/.env
Paso 2: Arrancar Gatus con Docker Compose
Crea el archivo de Compose:
sudo nano /opt/gatus/compose.yaml
services:
gatus:
image: twinproduction/gatus:latest
restart: unless-stopped
env_file: .env
ports:
- "127.0.0.1:8080:8080"
volumes:
- ./config.yaml:/config/config.yaml:ro
- gatus-data:/data
volumes:
gatus-data:
El puerto se publica solo en 127.0.0.1 porque Nginx se encargará del acceso desde fuera con HTTPS. Para producción, sustituye latest por una versión concreta de la imagen y actualízala a propósito.
Arranca el contenedor:
sudo docker compose up -d
Comprueba los logs. Gatus valida la configuración al arrancar y se detiene con un mensaje claro si hay un error de sintaxis:
sudo docker compose logs --tail 20 gatus
Consulta el endpoint de salud del propio Gatus:
curl -s http://127.0.0.1:8080/health
{"status":"UP"}
Paso 3: Publicar la página con Nginx y HTTPS
Instala Nginx y Certbot:
sudo apt install nginx certbot python3-certbot-nginx
Crea el sitio:
sudo nano /etc/nginx/sites-available/gatus
server {
listen 80;
server_name status.your_domain;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
Actívalo, comprueba la sintaxis, abre el firewall y solicita el certificado:
sudo ln -s /etc/nginx/sites-available/gatus /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d status.your_domain
Abre https://status.your_domain. Verás tus endpoints agrupados, con una barra de historial por cada uno que se va llenando con cada comprobación.
Paso 4: Probar las alertas
Antes de fiarte de las alertas, provoca un fallo controlado. Añade temporalmente al final de endpoints en config.yaml un endpoint que no existe:
- name: Prueba de alerta
group: Pruebas
url: https://noexiste.your_domain
interval: 30s
conditions:
- "[STATUS] == 200"
alerts:
- type: email
Gatus detecta los cambios en el archivo de configuración y lo recarga sin reiniciar. Si no ves el endpoint nuevo en la página, reinicia el contenedor:
sudo docker compose restart gatus
Tras tres comprobaciones fallidas (unos 90 segundos) debe llegar el correo de alerta. Si no llega, busca errores SMTP en los logs:
sudo docker compose logs gatus | grep -i alert
Elimina el endpoint de prueba cuando hayas confirmado que funciona.
Gatus admite muchos otros canales además del correo, como Slack, Discord, Telegram, Microsoft Teams, PagerDuty o un webhook genérico. Se configuran en el mismo bloque alerting.
Paso 5: Configurar ventanas de mantenimiento
Durante un mantenimiento planificado no quieres recibir alertas por caídas esperadas. Añade un bloque maintenance en la raíz de config.yaml, por ejemplo para los domingos de 02:00 a 04:00 en hora de Madrid:
maintenance:
start: "02:00"
duration: 2h
timezone: "Europe/Madrid"
every: [Sunday]
Durante esa ventana Gatus sigue comprobando los endpoints y registrando su estado, pero no envía alertas. Si omites every, la ventana se aplica todos los días.
Paso 6: Consultar el estado desde la API
Gatus expone el estado de todos los endpoints en JSON, útil para integrarlo en tu panel o en otras herramientas:
curl -s https://status.your_domain/api/v1/endpoints/statuses | python3 -m json.tool | head -n 20
[
{
"name": "Web",
"group": "Servicios web",
"key": "servicios-web_web",
"results": [
{
"status": 200,
"hostname": "your_domain",
...
Solución de problemas
El contenedor se reinicia en bucle. La configuración tiene un error. sudo docker compose logs gatus muestra la línea del YAML o la condición que no es válida.
Un endpoint aparece en rojo pero el servicio funciona. Mira el detalle del endpoint en la página: Gatus muestra qué condición ha fallado. Lo habitual es un código 301 en lugar de 200 (ajusta la URL o la condición) o un campo JSON con otro nombre en [BODY].
Los cambios en config.yaml no se aplican. Algunos editores reemplazan el archivo en lugar de modificarlo y el montaje de un solo archivo en Docker sigue apuntando al antiguo. Reinicia con sudo docker compose restart gatus.
Conclusión
Has comparado las principales alternativas self-hosted a Instatus y desplegado Gatus con Docker, HTTPS, alertas por correo probadas y una ventana de mantenimiento semanal. Como siguientes pasos, puedes guardar config.yaml en un repositorio Git para revisar los cambios, añadir un canal de alertas de chat para el equipo de guardia y cambiar el almacenamiento a PostgreSQL si vas a monitorizar muchos endpoints.
