Alerting Flow — Centralizado via Alertmanager¶
Last updated: 2026-07-12
El componente central de alertas del homelab es Prometheus Alertmanager (v0.32.1) corriendo en VM 208. Recibe alertas de Prometheus (reglas + Grafana) y las enruta por severity a dos receivers: Telegram (nativo) y Vera (webhook). El viejo flujo basado en n8n queda como legacy (ver más abajo).
🎯 Diseño (actual)¶
┌────────────────────────┐
│ Prometheus rules │ ─┐
│ + Grafana alert rules │ │
└────────────────────────┘ │
▼
┌──────────────────────┐
│ Alertmanager v0.32.1 │ (VM 208, prom/alertmanager)
│ /home/monxas/appdata/ │
│ alertmanager/ │
│ alertmanager.yml │
│ │
│ route por severity: │
│ critical|warning ─►vera (continue)
│ critical ─► telegram (repeat 1h)
│ warning ─► telegram (repeat 6h)
│ inhibit: critical ⊳ warning (equal alertname,instance)
└───────┬───────────┬──┘
│ │
┌───────────▼──┐ ┌────▼──────────────┐
│ telegram │ │ vera (webhook) │
│ telegram_configs │ http://192.168.0.245:8099/alert
│ chat_id │ │ Bearer auth │
│ 730947207 │ │ send_resolved │
│ send_resolved │ └───────────────────┘
└──────┬────────┘
▼
api.telegram.org
Bot @Veraclawd_bot
Chat 730947207
┌────────────────────────┐
│ Proxmox (pmx-50/51) │ ──► webhook `telegram` (PVE notifications)
│ PVE notifications.cfg │ → api.telegram.org (chat 730947207)
└────────────────────────┘
┌────────────────────────┐
│ backup-freshness.sh │ ──► Telegram vía bot de Vera en CT100
│ (pmx-50, cron 09:00) │
└────────────────────────┘
⚙️ Alertmanager — configuración¶
Fichero: /home/monxas/appdata/alertmanager/alertmanager.yml (container alertmanager, imagen prom/alertmanager). Fuente versionada: docs-repo/ansible/roles/observability_collector/files/alertmanager.yml.
- Route raíz:
receiver: telegram,group_by: [alertname, severity],group_wait: 30s,group_interval: 5m,repeat_interval: 12h. - Sub-routes:
severity=~"critical|warning"→veraconcontinue: true(Vera ve críticas y warnings, pero el flujo sigue evaluando).severity="critical"→telegram,repeat_interval: 1h.severity="warning"→telegram,repeat_interval: 6h.- inhibit_rules: una
criticalsilencia lawarningequivalente (equal: [alertname, instance]).
Receiver telegram (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 con emoji por estado + alertname + severity + lista de alerts (summary/description) + instance.
Receiver vera (webhook)¶
url: http://192.168.0.245:8099/alertsend_resolved: true,max_alerts: 0- Auth
Bearer(credencial en elalertmanager.yml, no versionada en claro).
🎨 Output Telegram¶
Emoji por estado/severity: 🚨 firing · ✅ resolved. En mensajes de severity manual: 🔴 critical · 🟡 warning · 🟠 high · 🟢 recovery · ℹ️ info.
🔔 PVE → Telegram (nuevo, 2026-07-12)¶
Proxmox envía todas sus notificaciones a Telegram directamente, sin pasar por Alertmanager. Configurado en /etc/pve/notifications.cfg:
- Endpoint
webhook: telegram→POST https://api.telegram.org/bot{{ secrets.token }}/sendMessage, body conchat_id 730947207,parse_mode Markdown. - Enganchado al
matcher: default-matcher(modeall) junto amail-to-root, de modo que cada alerta de Proxmox (incluidos fallos de backup víamailnotification=failure) llega tanto al mail de root como a Telegram.
🛡️ 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-down→up{job=~"node|proxmox-nodes|cadvisor"} < 1— salta si cae un solo target.ContainerDown→sum by (job) (up{job=~"cadvisor|node"}) == 0— salta sólo si caen todos los de un job, y no cubreproxmox-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 (41 en 6 grupos)¶
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.
| Grupo | Nº | 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 |
🕰️ 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 hashsource:severity:title[:40]:message[:60], log enstaticData.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'
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 Forwarderworkflow (UIDvj0ZOqNN4vkSkzYG) — DISABLED, versión vieja basada en poll a ntfy topicbeszel-alerts.- Beszel (LXC 249) — decomisado. Ya no emite alertas.