Después de gestionar 14 servicios distribuidos en 3 VPS diferentes, decidimos construir un sistema de monitoreo unificado que expone el estado completo de la infraestructura en tiempo real. Este artículo documenta las decisiones arquitectónicas y los principios de diseño que guiaron el desarrollo.

El Problema: Visibilidad Fragmentada

Inicialmente, cada VPS operaba de forma independiente. Para verificar el estado de un servicio, necesitábamos:

  1. SSH al VPS correcto
  2. Ejecutar systemctl status service-name
  3. Verificar manualmente el endpoint HTTP
  4. Revisar logs en caso de errores

Con 14 servicios activos, este proceso se volvió insostenible. Necesitábamos un dashboard centralizado que mostrara todo el estado de forma inmediata.

Principio clave: La información crítica debe estar visible sin requerir acciones del usuario. Si necesitas hacer click para ver el estado, el diseño falló.

Arquitectura: Túneles HTTP + Scraping Periódico

La solución implementada consta de tres componentes principales:

1. Túneles HTTP para Métricas

Los puertos de monitoreo (9100) están bloqueados por el firewall cloud. Solución: exponer las métricas vía reverse proxy HTTPS.

# Caddy config
metrics.illanes00.cl {
    reverse_proxy localhost:9100

    log {
        output file /var/log/caddy/metrics.log
    }
}

Ventajas:

  • No requiere abrir puertos adicionales
  • SSL automático via Let's Encrypt
  • Prometheus puede scrapear vía HTTPS público
  • Logs centralizados en Caddy

2. Script Python de Scraping

Un script ejecutado cada minuto (cron) verifica:

  • Systemd status: systemctl is-active service-name
  • HTTP local: curl http://localhost:PORT/health
  • HTTP Caddy: Verifica reverse proxy interno
  • HTTP público: Request a dominio público (Cloudflare)
  • Latencia: Tiempo de respuesta de cada endpoint
def check_service(service):
    """Verifica estado completo de un servicio"""
    return {
        'systemd': check_systemd(service['name']),
        'http_local': check_http(f"http://localhost:{service['port']}/health"),
        'http_caddy': check_http(f"https://{service['domain']}/health"),
        'http_public': check_http(f"https://{service['domain']}/health", external=True),
        'latency_ms': measure_latency(service['domain'])
    }

3. Dashboard Estático con Auto-refresh

El script genera index.html estático con todo el estado visible. Meta-refresh de 30 segundos garantiza actualización automática.

<meta http-equiv="refresh" content="30">

Principios de Diseño Visual

Flat Design Absoluto

Cero gradientes. Cero sombras. Cero border-radius (excepto status dots). Todos los efectos decorativos fueron eliminados.

:root {
  --radius: 0;
  --shadow: none;
}

button, .card, .tab {
  border-radius: 0;
  box-shadow: none;
}

Razón: Los efectos visuales no comunican información. Ocupan recursos (CPU para render, atención visual del usuario) sin agregar valor funcional.

Densidad Informativa

Inspirados en el principio P-03 de usgraphics.com: "Dense, not sparse". Toda la información crítica debe caber en una pantalla sin scroll.

Métrica Dashboard Anterior Dashboard Actual
Servicios visibles 4-5 (con scroll) 14 (sin scroll)
Clicks para ver estado 2-3 clicks/servicio 0 clicks
Información por servicio 2 campos 8 campos
Whitespace ratio ~40% ~15%

Exposición de Estado Interno

Principio P-02: "Expose state and inner workings". El dashboard muestra:

  • VPS donde corre cada servicio (badge de color)
  • Puerto específico
  • Systemd status con dot indicator
  • HTTP response codes exactos (200, 404, 500)
  • Latencia en milisegundos
  • URL pública clickeable
  • Timestamp de última actualización
"El usuario nunca debería preguntarse: ¿Por qué falló esto? Toda la información de debugging debe estar visible por defecto."

Tipografía Funcional

IBM Plex Sans 800/900 para headings. JetBrains Mono para datos tabulares. Sin serifs decorativas.

Razón: Sans-serif monospace facilita escaneo rápido de tablas. Los números se alinean verticalmente. Mayor legibilidad en monitores.

Resultados: Antes vs Después

❌ Antes
  • SSH manual a cada VPS
  • Comandos individuales por servicio
  • Sin visibilidad de HTTP público
  • No se detectaban fallos de Caddy
  • Tiempo de diagnóstico: ~5 minutos
✓ Después
  • Dashboard unificado en navegador
  • 14 servicios visibles simultáneamente
  • Verificación multi-capa automática
  • Detección de fallos en <60 segundos
  • Tiempo de diagnóstico: ~10 segundos

Próximos Pasos

El sistema actual funciona pero tiene limitaciones:

  1. Sin alertas proactivas: Configurar Alertmanager para notificaciones a Telegram cuando un servicio cae.
  2. Historial limitado: Actualmente solo muestra estado actual. Grafana ya está configurado pero falta integración visual.
  3. Sin métricas de performance: Agregar CPU, RAM, disk usage por servicio.
  4. Dashboard de Cloudflare: Mostrar configuración DNS y proxying status en el admin panel.
✓ Lección aprendida: El diseño funcional no es sobre estética. Es sobre maximizar la información útil visible y minimizar las acciones requeridas para tomar decisiones.

Conclusión

Este proyecto demuestra que el diseño minimalista (en el sentido de "menos clicks, más información") es compatible con el anti-minimalismo visual (dense, not sparse). El resultado es un dashboard que:

  • Expone todo el estado de forma inmediata
  • No requiere interacción para diagnóstico básico
  • Usa recursos mínimos (13KB CSS, HTML estático)
  • Se actualiza automáticamente
  • Es legible en cualquier dispositivo

El código completo está disponible en GitHub.