Instalación de Cachet: Página de Estado Autoalojada

Cachet es una plataforma de página de estado de código abierto que permite comunicar incidentes y el estado de los servicios a usuarios y clientes de forma profesional. Con soporte para componentes, métricas, suscriptores por correo y una API REST completa, Cachet es la alternativa autoalojada ideal a servicios como Statuspage.io para equipos DevOps en servidores Linux.

Requisitos Previos

  • Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
  • Docker Engine 20.10+ y Docker Compose (para instalación con Docker)
  • PHP 8.1+ con extensiones: pdo, pdo_mysql, curl, gd, mbstring (instalación manual)
  • MySQL 8.0+ o PostgreSQL 14+
  • Nginx o Apache como servidor web
  • Composer (para instalación manual)
  • Acceso root o usuario con privilegios sudo

Instalación con Docker

La forma más rápida de desplegar Cachet es con Docker Compose:

# Crear directorio de trabajo
mkdir -p /opt/cachet && cd /opt/cachet

# Crear archivo docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  # Base de datos MySQL para Cachet
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root_seguro_123
      MYSQL_DATABASE: cachet
      MYSQL_USER: cachet
      MYSQL_PASSWORD: cachet_pass_456
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Aplicación Cachet
  cachet:
    image: cachethq/docker:latest
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      DB_DRIVER: mysql
      DB_HOST: db
      DB_DATABASE: cachet
      DB_USERNAME: cachet
      DB_PASSWORD: cachet_pass_456
      APP_KEY: base64:generada_automaticamente
      APP_ENV: production
      APP_DEBUG: false
      APP_URL: https://status.mi-dominio.com
      MAIL_DRIVER: smtp
      MAIL_HOST: smtp.mi-dominio.com
      MAIL_PORT: 587
      MAIL_USERNAME: [email protected]
      MAIL_PASSWORD: password_correo
      MAIL_FROM_ADDRESS: [email protected]
      MAIL_FROM_NAME: "Estado del Servicio"
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - cachet_data:/var/www/html/storage

volumes:
  db_data:
  cachet_data:
EOF

# Iniciar los servicios
docker-compose up -d

# Ver los logs de inicio
docker-compose logs -f cachet

Configurar Nginx como proxy:

# Crear configuración de Nginx para Cachet
sudo cat > /etc/nginx/sites-available/cachet << 'EOF'
# Proxy inverso para Cachet
server {
    listen 80;
    server_name status.mi-dominio.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name status.mi-dominio.com;
    
    ssl_certificate /etc/letsencrypt/live/status.mi-dominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/status.mi-dominio.com/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/cachet /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Instalación Manual con PHP

Para mayor control sobre la configuración:

# Instalar dependencias del sistema
sudo apt-get update
sudo apt-get install -y php8.1 php8.1-fpm php8.1-mysql php8.1-gd \
    php8.1-curl php8.1-mbstring php8.1-xml php8.1-zip \
    mysql-server nginx git unzip

# Instalar Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# Clonar Cachet
cd /var/www
sudo git clone https://github.com/cachethq/cachet.git
sudo chown -R www-data:www-data cachet
cd cachet

# Instalar dependencias PHP
sudo -u www-data composer install --no-dev --prefer-dist

# Configurar variables de entorno
sudo cp .env.example .env
sudo nano .env

# Generar clave de aplicación
sudo -u www-data php artisan key:generate

# Ejecutar migraciones de base de datos
sudo -u www-data php artisan migrate --force

# Instalar y activar
sudo -u www-data php artisan cachet:install

Gestión de Componentes

Los componentes representan los servicios que se monitorizan:

# Crear componente via API
curl -X POST https://status.mi-dominio.com/api/v1/components \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "API Principal",
        "description": "API REST del servicio principal",
        "status": 1,
        "order": 1,
        "group_id": null,
        "enabled": true
    }'

# Estados posibles:
# 1 = Operacional
# 2 = Degradado
# 3 = Interrupción parcial
# 4 = Interrupción mayor

# Crear grupo de componentes
curl -X POST https://status.mi-dominio.com/api/v1/component_groups \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "Servicios de Alojamiento",
        "order": 1,
        "collapsed": false
    }'

# Actualizar estado de componente
curl -X PUT https://status.mi-dominio.com/api/v1/components/1 \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{"status": 2}'

Reportar Incidentes

Gestión del ciclo de vida de incidentes:

# Crear nuevo incidente
curl -X POST https://status.mi-dominio.com/api/v1/incidents \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "Latencia elevada en la red",
        "message": "Estamos investigando un incremento inusual en la latencia de red que afecta a algunos usuarios.",
        "status": 1,
        "visible": 1,
        "component_id": 1,
        "component_status": 2,
        "notify": true
    }'

# Estados del incidente:
# 1 = Investigando
# 2 = Identificado
# 3 = En seguimiento
# 4 = Resuelto

# Añadir actualización a un incidente existente
curl -X POST https://status.mi-dominio.com/api/v1/incidents/1/updates \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "status": 2,
        "message": "Hemos identificado el origen del problema: un switch de red defectuoso. Trabajamos en la solución."
    }'

# Resolver el incidente
curl -X PUT https://status.mi-dominio.com/api/v1/incidents/1 \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "status": 4,
        "message": "El incidente ha sido resuelto. Se reemplazó el hardware defectuoso.",
        "component_status": 1
    }'

Métricas y Gráficas

Cachet permite mostrar métricas personalizadas:

# Crear una métrica (tiempo de respuesta)
curl -X POST https://status.mi-dominio.com/api/v1/metrics \
    -H "X-Cachet-Token: TU_TOKEN_API" \
    -H "Content-Type: application/json" \
    -d '{
        "name": "Tiempo de Respuesta API",
        "suffix": "ms",
        "description": "Tiempo medio de respuesta de la API REST",
        "default_value": 0,
        "calc_type": 1,
        "display_chart": true,
        "places": 2
    }'

# Enviar puntos de datos a la métrica
# Automatizar con un script cron
cat > /usr/local/bin/cachet-metrics.sh << 'EOF'
#!/bin/bash
# Script para enviar métricas a Cachet cada minuto

CACHET_URL="https://status.mi-dominio.com/api/v1"
CACHET_TOKEN="TU_TOKEN_API"
METRIC_ID=1

# Medir tiempo de respuesta de la API
TIEMPO=$(curl -o /dev/null -s -w "%{time_total}" https://api.mi-dominio.com/health)
TIEMPO_MS=$(echo "$TIEMPO * 1000" | bc | cut -d. -f1)

# Enviar el dato a Cachet
curl -s -X POST "$CACHET_URL/metrics/$METRIC_ID/points" \
    -H "X-Cachet-Token: $CACHET_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"value\": $TIEMPO_MS, \"timestamp\": $(date +%s)}"
EOF

chmod +x /usr/local/bin/cachet-metrics.sh

# Añadir al cron
echo "* * * * * root /usr/local/bin/cachet-metrics.sh" | sudo tee /etc/cron.d/cachet-metrics

Suscriptores y Notificaciones

Gestión de notificaciones a suscriptores:

# Ver suscriptores registrados
curl -X GET https://status.mi-dominio.com/api/v1/subscribers \
    -H "X-Cachet-Token: TU_TOKEN_API"

# La suscripción se realiza desde la interfaz web o via API:
curl -X POST https://status.mi-dominio.com/api/v1/subscribe \
    -H "Content-Type: application/json" \
    -d '{
        "email": "[email protected]",
        "components": [1, 2, 3]
    }'

# Configurar SMTP en .env para notificaciones
# MAIL_DRIVER=smtp
# MAIL_HOST=smtp.sendgrid.net
# MAIL_PORT=587
# MAIL_USERNAME=apikey
# MAIL_PASSWORD=SG.clave_sendgrid
# [email protected]

Uso de la API

La API REST de Cachet permite integración completa:

# Obtener token de API desde el panel de usuario
# Settings > API Token

# Ver todos los componentes
curl -s https://status.mi-dominio.com/api/v1/components \
    -H "X-Cachet-Token: TU_TOKEN_API" | python3 -m json.tool

# Ver incidentes activos
curl -s "https://status.mi-dominio.com/api/v1/incidents?status=open" \
    -H "X-Cachet-Token: TU_TOKEN_API" | python3 -m json.tool

# Integración con script de monitorización
cat > /usr/local/bin/check-services.sh << 'EOF'
#!/bin/bash
# Monitorización básica con actualización automática en Cachet

CACHET_TOKEN="TU_TOKEN_API"
CACHET_URL="https://status.mi-dominio.com/api/v1"

# Comprobar disponibilidad de la web
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://mi-dominio.com)

if [ "$HTTP_CODE" != "200" ]; then
    # Actualizar componente a degradado
    curl -s -X PUT "$CACHET_URL/components/1" \
        -H "X-Cachet-Token: $CACHET_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"status": 4}'
    echo "ALERTA: Servicio web no disponible (HTTP $HTTP_CODE)"
fi
EOF

chmod +x /usr/local/bin/check-services.sh

Solución de Problemas

Cachet muestra error 500:

# Ver logs de la aplicación
docker-compose logs cachet --tail=50

# En instalación manual, revisar logs de Laravel
sudo tail -f /var/www/cachet/storage/logs/laravel.log

# Verificar permisos
sudo chown -R www-data:www-data /var/www/cachet/storage
sudo chmod -R 775 /var/www/cachet/storage

Los correos de notificación no se envían:

# Probar la configuración SMTP
docker exec -it cachet php artisan tinker
# Tinker: Mail::raw('Prueba', function($m) { $m->to('[email protected]')->subject('Test'); });

# Verificar cola de trabajos
docker exec -it cachet php artisan queue:work

Error de conexión a base de datos:

# Verificar credenciales en .env
docker exec -it cachet env | grep DB_

# Probar conexión manualmente
docker exec -it db mysql -u cachet -p cachet

Conclusión

Cachet proporciona una solución completa y profesional para comunicar el estado de los servicios a usuarios y clientes sin depender de plataformas externas. Su API REST permite la integración con herramientas de monitorización existentes para actualizar estados automáticamente, mientras que el sistema de suscriptores garantiza que los usuarios reciban notificaciones en tiempo real ante cualquier incidencia. El despliegue con Docker simplifica enormemente el mantenimiento y las actualizaciones en producción.