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:
- SSH al VPS correcto
- Ejecutar
systemctl status service-name - Verificar manualmente el endpoint HTTP
- 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.
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
- 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
- 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:
- Sin alertas proactivas: Configurar Alertmanager para notificaciones a Telegram cuando un servicio cae.
- Historial limitado: Actualmente solo muestra estado actual. Grafana ya está configurado pero falta integración visual.
- Sin métricas de performance: Agregar CPU, RAM, disk usage por servicio.
- Dashboard de Cloudflare: Mostrar configuración DNS y proxying status en el admin panel.
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.