Skip to content

Alerting Flow — Centralizado via Alertmanager

Last updated: 2026-08-01 (reescrito tras el rediseño "silencio primero" del 2026-07-20 — la versión anterior de este documento, de 2026-07-12, describía un diseño ya sustituido)

El componente central de alertas del homelab es Prometheus Alertmanager corriendo en VM 208 (192.168.0.208). Recibe alertas de Prometheus (reglas + Grafana) y las enruta con política "silencio primero": por defecto todo va solo a Vera (webhook, silenciosa, con digest 6h); solo un carril reducido de alertas realmente graves interrumpe con Telegram al instante. El viejo flujo basado en n8n queda como legacy (ver más abajo).

🎯 Diseño (actual, "silencio primero" desde 2026-07-20)

┌────────────────────────┐
│ Prometheus rules        │ ─┐
│ + Grafana alert rules   │  │
└────────────────────────┘  │
                  ┌───────────────────────┐
                  │ Alertmanager           │  (VM 208, prom/alertmanager)
                  │ /home/monxas/appdata/  │
                  │   alertmanager/        │
                  │   alertmanager.yml     │
                  │                        │
                  │ receiver por defecto: VERA (silencioso)
                  │                        │
                  │ Carril 1 — GRAVE (14 alertnames: corrupción,
                  │  RAID/SMART/NVMe, disco crítico, NAS/Caddy caídos)
                  │  → telegram-grave AL INSTANTE + continue:true → Vera
                  │  también, en paralelo (repeat 4h)
                  │                        │
                  │ Carril 2 — TODO LO DEMÁS (severity critical|warning)
                  │  → SOLO Vera, en silencio (repeat 24h; el bridge
                  │  aplica su propio cooldown 30min por fingerprint)
                  │                        │
                  │ inhibit_rules: cascada NAS, jerarquía de disco,
                  │  bundling SMART, critical ⊳ warning genérico
                  └───────┬────────────┬───┘
                          │            │
              ┌───────────▼──┐   ┌─────▼─────────────┐
              │ telegram-grave│   │ vera (webhook)    │
              │ chat_id       │   │ http://vera.lan:8099/alert
              │ 730947207     │   │ Bearer auth       │
              │ parse_mode HTML│  │ send_resolved     │
              └──────┬────────┘   └────────┬──────────┘
                     ▼                     ▼
             api.telegram.org      Vera diagnostica + intenta
             Bot @Veraclawd_bot    arreglo reversible. Si falla o
             Chat 730947207        descubre algo grave, rompe el
                                    silencio; si no, digest cada 6h.

┌────────────────────────┐
│ Proxmox (pmx-50/51)     │ ──► webhook `telegram` (PVE notifications)
│ PVE notifications.cfg   │      → api.telegram.org  (chat 730947207)
│ SOLO severity warning/error va a Telegram; TODO va a mail root@pam │
└────────────────────────┘

┌────────────────────────┐
│ backup-freshness.sh     │ ──► Telegram vía bot de Vera en CT100
│ (pmx-50, cron 09:00)    │
└────────────────────────┘

Por qué cambió (2026-07-20): antes, toda alerta critical|warning iba a Telegram Y a Vera en paralelo, así que una sola cascada (p.ej. NAS nfsd colgado → contenedores de media → probes) producía ~25 mensajes redundantes. Ahora solo 14 alertnames realmente graves rompen el silencio de inmediato; el resto lo gestiona Vera callada, con digest cada 6h, y solo avisa si el arreglo automático falla. Detalle del bridge: /root/clawd/scripts/alert-bridge.py en LXC 100 (Vera, ahora en 192.168.0.203).

⚙️ Alertmanager — configuración

Fichero: /home/monxas/appdata/alertmanager/alertmanager.yml (container alertmanager). Fuente versionada: ansible/roles/observability_collector/files/alertmanager.yml.

  • Route raíz: receiver: vera (default silencioso), group_by: [alertname, severity], group_wait: 30s, group_interval: 5m, repeat_interval: 12h.
  • Sub-route Carril 1 (grave): matchea 14 alertnames de riesgo real de datos/caída total (nas_btrfs_corruption, nas_mdadm_degraded, nas_smart_failed, nas_nvme_critical_warning, CriticalDiskUsage, pbs_datastore_main_critical, nas_down, CaddyLXCDown, etc.) → receiver telegram-grave, continue: true (así el carril 2 también dispara a Vera en paralelo), group_wait: 20s, group_interval: 10m, repeat_interval: 4h.
  • Sub-route Carril 2 (resto): severity=~"critical|warning" → receiver vera únicamente, group_wait: 45s, group_interval: 15m, repeat_interval: 24h.
  • inhibit_rules (más elaboradas que antes): cascada NAS (nas_down/nas_high_load silencia síntomas dependientes sin equal:, porque la causa está en otro host), jerarquía de disco (CriticalDiskUsageHighDiskUsage, nas_volume1_critical⊳otras), bundling de SMART (un disco muriéndose no manda 4 alertas sueltas), NVMe wearout/spare, y la regla genérica severity=criticalseverity=warning (equal: [alertname, instance]).

Receiver telegram-grave (nativo)

telegram_configs nativo de Alertmanager (no pasa por n8n): - bot_token_file: /etc/alertmanager/telegram-bot-token - chat_id: 730947207 - parse_mode: HTML, send_resolved: true - Plantilla message: 🔥 GRAVE — {alertname} (firing) / ✅ Resuelto — {alertname} (resolved), con severity + lista de alerts (summary/description) + instance, y nota de que Vera está diagnosticando en paralelo.

Receiver vera (webhook)

  • url: http://vera.lan:8099/alert (LXC 100, 192.168.0.203)
  • send_resolved: true, max_alerts: 0
  • Auth Bearer vía credentials_file: /etc/alertmanager/vera-alert-secret (fuera de git a propósito).

🎨 Output Telegram

Corregido 2026-08-01: el bloque de ejemplo de la versión anterior de este documento (🚨 alertname / Severity / Status / • summary) correspondía al receiver genérico telegram que ya no existe. El receiver real hoy es telegram-grave (solo para el carril GRAVE de 14 alertnames), con esta plantilla:

🔥 <b>GRAVE — alertname</b>
Severity: critical

• summary de la alerta
  Instance: host:port

🤖 Vera está diagnosticando en paralelo.

En resolución (✅ Resuelto — alertname) no lleva la línea de Vera. Aparte, PVE manda sus propios mensajes directamente (no vía Alertmanager) con formato 🖥️ *title*\n\nmessage en Markdown — ver sección PVE → Telegram abajo.

🔔 PVE → Telegram

Proxmox notifica directamente, sin pasar por Alertmanager. Configurado en /etc/pve/notifications.cfg (verificado en vivo 2026-08-01 — la descripción de este documento a fecha 2026-07-12 estaba desactualizada, ver nota abajo):

  • Endpoint webhook: telegramPOST https://api.telegram.org/bot{{ secrets.token }}/sendMessage, body con chat_id 730947207, parse_mode Markdown.
  • matcher: default-matcher (mode all) → target mail-to-root únicamente. TODA notificación PVE (incluidos fallos de backup vía mailnotification=failure) llega al mail de root.
  • matcher: telegram-important (separado, match-severity warning,error, mode all) → target telegram. Solo las notificaciones PVE de severity warning/error llegan también a Telegram — no todas, como decía la versión anterior de este doc. Los backups OK van solo por mail; el agregado diario se ve en el morning report.

🛡️ backup-freshness.sh (nuevo, 2026-07-12)

Monitor de frescura de backups en pmx (/usr/local/sbin/backup-freshness.sh en proxmox-50), cron diario 09:00 (tras las ventanas de backup). Signal-only:

  • Para cada guest con job de backup, busca la última snapshot en PBS (pvesm list pbs).
  • Umbral 48h (THRESH_H): si un guest no tiene backup más reciente que eso, o no tiene ninguno, genera aviso.
  • Críticos (🔴): 100 (Vera), 208 (media), 270/271 (caddy), 280 (rp). El resto son 🟡.
  • Entrega la alerta a Telegram vía el bot de Vera dentro de CT100 (pct exec 100 -- ... source secrets.env ... curl api.telegram.org), sin copiar el token a pmx.
  • Log en /var/log/backup-freshness.log.

🚨 Reglas de alerta activas

Las reglas viven en Prometheus/Grafana y disparan hacia Alertmanager. Grupos:

Reparto de responsabilidades (desde 2026-07-26)

Los dos pipelines tenían 9 reglas duplicadas, así que el mismo evento llegaba dos veces a Telegram con nombres distintos (memory-high y HighMemoryUsage, load-high y HighLoadAverage…). Se deduplicó con un criterio de capacidad, no de preferencia:

Pipeline De qué se ocupa Nº reglas
Prometheus (alerts.yml) Umbrales sobre métricas: host, NAS, SMART/NVMe, backup, servicios 41
Grafana Lo que Prometheus no puede: logs de Loki, probes sintéticos, métricas de Caddy, tendencias 20

Se borraron de Grafana las 9 duplicadas (backup en appdata/grafana/alert-rules-backup-20260726.json). Antes de borrar se comparó expresión a expresión, no sólo el nombre — y ahí apareció la excepción de abajo.

prom-target-down NO es un duplicado de ContainerDown

Se parecen por el nombre y no hacen lo mismo:

  • prom-target-downup{job=~"node|proxmox-nodes|cadvisor"} < 1 — salta si cae un solo target.
  • ContainerDownsum by (job) (up{job=~"cadvisor|node"}) == 0 — salta sólo si caen todos los de un job, y no cubre proxmox-nodes.

Borrar la de Grafana habría dejado ciego el caso "se muere el node_exporter de pmx-51 o del NAS". Se conserva a propósito. Misma lógica al eliminar smart-failed (Grafana, for: 0s): para no perder inmediatez ante un disco muriéndose, nas_smart_failed bajó de 5m a 1m.

Grafana escucha en :3030, no en :3000

En :3000 hay otro contenedor que responde {"success":false,"error":"Authentication not configured"}. Parece un fallo de credenciales de Grafana y no lo es — estás llamando al servicio equivocado.

Para editar reglas: PUT|DELETE /api/v1/provisioning/alert-rules/{uid} con cabecera X-Disable-Provenance: true.

Grafana — homelab-critical (8)

UID Trigger
backup-failed count_over_time({job="vzdump"} \|~ "ERROR:"[10m]) > 0
caddy-upstream-down min(caddy_reverse_proxy_upstreams_healthy) < 1 (2min)
host-silent count_over_time({host=~"proxmox-50\|proxmox2-51\|ubuntu-media-server"}[10m]) < 1
n8n-down-direct n8n DOWN (alerta directa)
pbs-verify-failed PBS verify-job fallido
pihole-down up{job="pihole"} < 1 (3min)
prom-target-down up{job=~"node\|proxmox-nodes\|cadvisor"} < 1 (3min) — cualquier target
tv-gw-down tv-gw LXC DOWN — TV LG sin internet

Grafana — homelab-warning (8)

UID Trigger
caddy-5xx-spike rate(caddy_http_requests_total{code=~"5.."}[5m]) > 0.5 (5min)
caddy-p99-slow p99 latency > 2s (10min)
container-restarting container reinicia >3×/15min
disk-fill-trend disco llenándose en <7d (predictiva)
error-spike rate errores reales >2/s (2min)
loki-grafana-internal-error error interno Loki/Grafana
probe-down probe_success < 1 (3min)
pvesr-fail max(pvesr_fail_count) > 0 (15min) — replicación PVE entre nodos

Grafana — iarq (4)

Stack de iarquitectos en la VM de Carmelo: CPU sostenida y disco de openclaw-vm, errores de iarq y fallos de scraping del RAG. UIDs autogenerados, sin nombre legible.

Prometheus — alerts.yml (52 en 7 grupos, verificado en vivo 2026-08-01)

Reagrupado el 2026-07-26 por dominio real. Antes había un grupo nas-smart de 18 reglas que contenía media_container_missing/_unhealthy (contenedores del stack de media, nada que ver con SMART) y un nas-preventive que separaba BTRFS/mdadm/PCIe del resto de almacenamiento sin criterio. Desde entonces se añadió un grupo nuevo, red_network (11 reglas), que no estaba documentado en la versión anterior de este doc.

Grupo Contenido
host_system 7 Disco, memoria, swap, load y ContainerDown de todos los hosts
nas_health 5 NAS vivo, load, memoria, volumen, temperatura
nas_storage 7 Integridad de almacenamiento: RAID, mdadm, BTRFS, PCIe, cache NVMe
nas_smart 15 Sólo salud de disco reportada por SMART/NVMe
backup 2 Ocupación del datastore PBS
services 5 WP-Pulse, Caddy LXC, Remote-Pulse y contenedores de media
red_network 11 Red: internet/router ASUS/AiMesh/switch+AP UniFi/exporters caídos, router carga/memoria, nuevo cliente visto — grupo nuevo, no documentado antes

🕰️ Legacy — flujo n8n (complementario / en retirada)

Antes de Alertmanager, TODA alerta pasaba por n8n (Beszel Alert Direct Webhook, LXC 200, endpoint POST http://192.168.0.200:5678/webhook/beszel-alert-direct), que clasificaba severity, aplicaba cooldown 5min y reenviaba a Telegram vía la API nativa.

Estado actual: - beszel fue decomisado (LXC 249 retirado), así que su origen de alertas ya no existe. - Alertmanager sustituyó a n8n como sistema central de alertas. - El workflow n8n puede seguir vivo para orígenes puntuales que aún posteen a su webhook (Healthchecks, morning report, watchdog), pero no es el camino canónico. Trátalo como complementario/legacy y no añadas nuevas integraciones ahí.

Detalle del payload/nodos del workflow legacy (por si hay que depurar algo que aún lo use):

  • Format 1 (simple): {source, severity, title, message, url?, skip_cooldown?}.
  • Format 2 (Grafana Alertmanager): n8n auto-detecta alerts: [...].
  • Nodo Process Alert v2: auto-detect Grafana vs simple, clasificación de severity por keyword, cooldown 5min por hash source:severity:title[:40]:message[:60], log en staticData.alertLog (últimas 200).
  • Extraer: pct exec 200 -- n8n export:workflow --id=dKTsixDYpxc76rYI --output=/tmp/wf.json.

🔧 Troubleshooting

"Alerta de Prometheus disparó pero no llegó a Telegram"

Verificar Alertmanager y su config:

# Estado del container
ssh [email protected] 'docker ps | grep alertmanager'
# Alertas activas / silences
curl -s http://192.168.0.208:9093/api/v2/alerts | jq .
# Config cargada
curl -s http://192.168.0.208:9093/api/v2/status | jq .config
# Logs
ssh [email protected] 'docker logs alertmanager --tail 50'

Comprobar que el token de bot existe: /etc/alertmanager/telegram-bot-token dentro del container.

"No llegan alertas de Proxmox a Telegram"

Verificar el endpoint webhook y el matcher en PVE:

ssh [email protected] 'cat /etc/pve/notifications.cfg'
# Probar el endpoint
ssh [email protected] 'pvesh create /cluster/notifications/endpoints/webhook/telegram/test 2>/dev/null || echo "usa la UI: Datacenter -> Notifications -> Test"'

"backup-freshness.sh no avisa / avisa de más"

# Ejecución manual (con umbral bajo para test)
ssh [email protected] 'THRESH_H=1 /usr/local/sbin/backup-freshness.sh'
# Log
ssh [email protected] 'tail -20 /var/log/backup-freshness.log'
Si falla el envío, revisar que CT100 tiene TG_BOT/TG_CHAT en /root/.openclaw/secrets.env.

"Grafana alert disparó pero no llegó"

curl -s -u admin:$GRAFANA_ADMIN_PASS http://192.168.0.208:3030/api/v1/provisioning/contact-points
curl -s -u admin:$GRAFANA_ADMIN_PASS http://192.168.0.208:3030/api/v1/provisioning/policies

📍 Componentes desactivados

  • OpenClaw watchdog timer (openclaw-watchdog.timer) — DISABLED. Causaba spam de alertas durante maintenance.
  • Beszel Alert Forwarder workflow (UID vj0ZOqNN4vkSkzYG) — DISABLED, versión vieja basada en poll a ntfy topic beszel-alerts.
  • Beszel (LXC 249) — decomisado. Ya no emite alertas.