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_domain con un registro A apuntando al servidor.
  • Los puertos 22, 80 y 443 abiertos en UFW.

Comparativa de soluciones

SoluciónTipoMonitoriza por sí solaGestión de incidentesDónde se ejecuta
GatusAplicación Go, configurada en YAMLSí (HTTP, TCP, DNS, ICMP, certificados)Estado automático según las comprobacionesDocker o binario, SQLite o PostgreSQL
Uptime KumaAplicación Node.js con interfaz webSíIncidentes y mantenimientos desde la interfazDocker o Node.js
UpptimeGitHub Actions + GitHub PagesSí, desde los runners de GitHubIncidentes como issues de GitHubGitHub, sin servidor propio
cStateSitio estático con HugoNoIncidentes como archivos MarkdownCualquier 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 las conditions.
  • [BODY].status == ok lee el campo status de una respuesta JSON; adáptalo a lo que devuelva tu endpoint de salud.
  • failure-threshold: 3 evita 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.