Infra Stack¶
Nota (2026-07-26 — estado real verificado): la nota anterior ("Uptime Kuma ya no existe") era FALSA — Uptime Kuma (:3001) existe, corre y es el meta-monitor oficial: vigila lo que Prometheus no puede auto-vigilar (Prometheus, Grafana, Loki, ntfy + HA y PBS; 6 monitores, avisa por Telegram/ntfy). El 2026-07-26 se podaron 6 monitores duplicados/zombis (Sonarr/Radarr/Jellyfin/Immich/n8n ya los cubre
ContainerDownde Prometheus; Beszel apuntaba a un LXC destruido). Regla: cada alerta tiene un dueño único — servicios=Prometheus/Alertmanager, la propia pila de observabilidad=Kuma. Los que SÍ están retirados son Watchtower y Speedtest Tracker (0 menciones en el compose; el jobspeedtestde Prometheus se eliminó 2026-07-26 tras semanas marcando down).Actualización 2026-08-01: las menciones de Watchtower/Speedtest más abajo (diagrama, tablas, comandos) se han limpiado ahora para dejar de contradecir esta nota — antes decía "ignóralas" y las dejaba igualmente escritas como si estuvieran activas, lo cual confundía más de lo que aclaraba. También se confirmó en vivo (
docker ps -a+ compose real en media-208) que Krawl tampoco está en el compose actual — confirmado decomisionado (fecha exacta desconocida). El directorioappdata/krawlhuérfano estaba vacío (0 bytes de datos reales) → borrado 2026-08-01. Esto conectó un cabo suelto dereference/cf-access.md: las 8 apps CF Accessadmin/panel/login/phpmyadmin/wp-admin/cpanel/webmail/dashboardque ese doc marcaba como "no aparecen en las rutas de homelab-ctl.py, sin confirmar por qué" eran exactamente los 8 subdominios señuelo que servía Krawl — con el honeypot muerto, no protegían nada real. Borradas las 8 apps de CF Access y sus 8 registros DNS el 2026-08-01, confirmado por el propietario. Y el compose real deinfratrae 4 servicios que este doc nunca mencionó: blackbox-exporter, healthchecks, pushgateway, pihole-exporter — añadidos abajo con lo mínimo verificable.Observability, monitoring, and management services. Always running.
| Compose file | infra/compose.yaml |
| Status | Always on (start first) |
| Dependencies | None |
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ VISUALIZATION │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Grafana │◄─────────────────────│ Homepage │ │
│ │ :3030 │ │ :80 │ │
│ └──────┬───────┘ └──────────────────┘ │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ ┌──────┐ ┌──────┐ │
│ │Prom. │ │ Loki │ │
│ │:9090 │ │:3101 │ │
│ └──┬───┘ └──┬───┘ │
│ │ │ │
└────┼────────┼───────────────────────────────────────────────┘
│ │
┌────┼────────┼───────────────────────────────────────────────┐
│ │ DATA COLLECTION │
│ │ │ │
│ │ ┌────┴────┐ │
│ │ │Promtail │ ── Logs from containers & /var/log │
│ │ └─────────┘ │
│ │ │
│ ├──────┬──────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │Node │ │cAdvisor│ │Blackbox-exp. │ │Pihole-exporter │ │
│ │Exp. │ │ :8084 │ │ :9115 │ │ :9617 │ │
│ │:9100 │ └────────┘ └──────────────┘ └────────────────┘ │
│ └──────┘ (+ Pushgateway :9092 — push desde jobs one-shot) │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ MANAGEMENT │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Dockge │ │ Healthchecks │ │ Uptime Kuma │ │
│ │ :5001 │ │ :8073 │ │ :3001 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└──────────────────────────────────────────────────────────────┘
Diagrama corregido 2026-08-01: Watchtower y Speedtest Tracker quitados (retirados, ver nota de arriba); añadidos Blackbox-exporter/Pihole-exporter/Pushgateway/Healthchecks, que sí existen en
infra/compose.yamlen vivo pero nunca se habían dibujado aquí. Dockge está definido en el compose pero verificadoExiteden esta pasada — no es "always on" en la práctica ahora mismo.
Services¶
Metrics Collection¶
| Service | Port | Purpose |
|---|---|---|
| Prometheus | 9090 | Time-series metrics database |
| Node Exporter | 9100 | Host metrics (CPU, memory, disk) |
| cAdvisor | 8084 | Container metrics |
| Blackbox-exporter | 9115 | HTTP/TCP probe-based checks (not documented before 2026-08-01) |
| Pihole-exporter | 9617 | Pi-hole metrics (not documented before 2026-08-01) |
| Pushgateway | 9092 | Push endpoint for one-shot/batch jobs (not documented before 2026-08-01) |
~~Speedtest Tracker | 8765 | Internet speed history~~ — retirado, ver nota al inicio del doc.
Prometheus config: /home/monxas/appdata/prometheus/prometheus.yml
Network mode: Host network (for direct access to node-exporter)
Current scrape targets (Speedtest tracker target removed 2026-08-01, job was already gone):
- localhost:9090 - Self
- localhost:9100 - Node exporter (host network)
- 192.168.0.208:8084 - cAdvisor
- 192.168.0.171:8123 - Home Assistant
- 192.168.0.208:8086 - Plundrio-scanner
- 192.168.0.208:8087 - Plundrio-hunter
Lista de scrape targets no reverificada exhaustivamente
Lo de arriba es la lista previa del doc menos Speedtest. No se hizo una auditoría completa
de prometheus.yml real en esta pasada (por ejemplo, es probable que asus-exporter y
los exporters nuevos de la tabla de arriba también estén como targets — job asus-router
confirmado; el job unifi se retiró el 2026-08-09, equipo devuelto). Tratar esta
lista como incompleta, no como inventario definitivo.
Turbo-boosted settings: - Retention: 30 days / 5GB max - cAdvisor housekeeping: 30s (reduced CPU) - Node-exporter: 20+ collectors disabled (arp, bcache, bonding, btrfs, infiniband, ipvs, mdadm, nfs, nfsd, rapl, schedstat, sockstat, etc.)
Alert Rules: /home/monxas/appdata/prometheus/alerts.yml
No versionado
Este fichero vive sólo en media-208 y no está gestionado por Ansible. Edítalo en
caliente, valida con docker exec prometheus promtool check rules /etc/prometheus/alerts.yml
y recarga con curl -X POST http://localhost:9090/-/reload.
41 reglas en 6 grupos por dominio: host_system (7), nas_health (5), nas_storage (7),
nas_smart (15), backup (2), services (5). El desglose completo y el reparto con Grafana
están en Alerting flow.
Grupo host_system:
- HighDiskUsage (warning at 80%, <20% free)
- CriticalDiskUsage (critical at 90%, <10% free)
- HighMemoryUsage (>90%, con el ARC de ZFS sumado a MemAvailable en los nodos Proxmox)
- LowMemoryAvailable (critical, <10% de MemTotal; umbral relativo)
- SwapNearlyFull (>85% y con presión de memoria real, PSI > 0.05)
- ContainerDown (todas las instancias de un job caídas >2min — no cubre
proxmox-nodes; para caída de un target suelto estáprom-target-downen Grafana) - HighLoadAverage (15min load >2 per core, excluye los jobs LXC
tv-gw|n8n-node|ha-ml-node)
Por qué esas tres salvedades (2026-07-26)¶
Las reglas ingenuas generaban ~20 falsos positivos diarios en pmx-50 (113 HighMemoryUsage +
31 SwapNearlyFull en 7 días) con la PSI de memoria en ~0. Tres artefactos de medición:
MemAvailableno contabiliza el ARC de ZFS. Es memoria reclamable al instante, pero Linux no la reporta como disponible: sobreestimaba el uso de pmx-50 en ~14 puntos (87% vs 69% real). Por esoHighMemoryUsageyLowMemoryAvailablesumannode_zfs_arc_size.- zram está diseñado para ir lleno. En pmx-50 el swap total es 4.3 GiB de zram + 2 GiB de
disco, así que un zram lleno ya fija un suelo del 68% de swap usado.
SwapNearlyFullexige además PSI real, que es el único síntoma que distingue "swap lleno" de "swap doliendo". - Los LXC sin
lxcfs -lleen/proc/loadavgdel host. Su loadavg es un duplicado del de pmx-50/51 y no dice nada del contenedor. El resto de métricas del LXC (CPU, memoria) sí son container-scoped vía lxcfs, así que para vigilar contenedores usa CPU, no load.
Umbrales absolutos aplicados a contenedores pequeños son la misma clase de error: el antiguo
LowMemoryAvailable < 600 MB era inalcanzable por construcción en el LXC 200 (n8n, límite
1 GiB), y disparaba en bucle.
Regla general: en pmx-50 el único síntoma que importa es /proc/pressure/memory. Los
porcentajes de RAM y swap no significan nada en un host con ZFS + zram + sobreasignación
intencionada (~44 GiB asignados entre VMs y LXCs sobre 28 GiB físicos).
Log Aggregation¶
| Service | Port | Purpose |
|---|---|---|
| Loki | 3101 | Log storage and querying |
| Promtail | - | Log collector (ships to Loki) |
Promtail config: /home/monxas/appdata/promtail/config.yml
Collects:
- /var/log/* - System logs
- Docker container logs via labels
Visualization¶
| Service | Port | Purpose |
|---|---|---|
| Grafana | 3030 | Dashboards and alerting |
| Homepage | 80 | Static dashboard (nginx) |
Grafana data: /home/monxas/appdata/grafana/
Security¶
Krawl decomisionado — confirmado y limpiado (2026-08-01, fecha exacta del decomiso desconocida)
No hay contenedor krawl en docker ps -a, no aparece krawl: en
~/stacks/infra/compose.yaml en vivo (solo en un backup viejo,
infra/compose.yaml.bak-20260722, y en el historial git), y no se encontró ninguna ruta
Caddy para admin/panel/login/etc. El directorio huérfano /home/monxas/appdata/krawl/
estaba vacío (sin datos reales que perder) → borrado. La tabla de abajo describe cómo
funcionaba cuando estaba vivo — pura referencia histórica, ya no corre. No se encontró
ninguna nota o memoria que explique cuándo o por qué se quitó.
Las 8 apps CF Access que le daban entrada (admin/panel/login/phpmyadmin/wp-admin/
cpanel/webmail/dashboard, ver reference/cf-access.md) ya no protegían nada real —
borradas junto con sus 8 registros DNS el 2026-08-01.
| Service | Port | Purpose |
|---|---|---|
| Krawl (decomisionado, sección histórica) | 5050 | Honeypot & IP analysis |
Krawl serves fake admin/login pages to attract and log attackers. Exposed via 8 Cloudflare Tunnel subdomains: admin, panel, login, phpmyadmin, wp-admin, cpanel, webmail, dashboard (all *.monxas.casa).
Dashboard: https://admin.monxas.casa/krawl-dashboard
Data: /home/monxas/appdata/krawl/
Management & Monitoring¶
| Service | Port | Purpose |
|---|---|---|
| Dockge | 5001 | Docker Compose UI (verified Exited 2026-08-01, not currently running) |
| Uptime Kuma | 3001 | Uptime monitoring with alerts |
| Healthchecks | 8073 | Dead-man's-switch style cron/job monitoring (not documented before 2026-08-01) |
~~Watchtower — auto-updates at 4 AM~~ — retirado (0 menciones en el compose real, confirmado 2026-08-01), ver nota al inicio del doc. Los ajustes de abajo son históricos.
Data Retention¶
| Service | Retention | Location |
|---|---|---|
| Prometheus | 30 days / 5GB | /home/monxas/appdata/prometheus/data |
| Loki | Default | /home/monxas/appdata/loki |
| Grafana | Unlimited | /home/monxas/appdata/grafana |
Common Tasks¶
Check Prometheus targets:
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health: .health}'
Query Prometheus:
# CPU usage
curl -s 'http://localhost:9090/api/v1/query?query=100-(avg(irate(node_cpu_seconds_total{mode="idle"}[5m]))*100)'
# Memory usage
curl -s 'http://localhost:9090/api/v1/query?query=100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)'
Add new Prometheus target:
Edit /home/monxas/appdata/prometheus/prometheus.yml then:
Troubleshooting¶
Prometheus not scraping?
# Check target status
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.health != "up")'
# Check config
docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
Grafana can't connect to data source?
# Test Prometheus from Grafana container
docker exec grafana curl -s http://prometheus:9090/api/v1/status/config
Logs not appearing in Loki?