ADR-0022 — Sesión de hardening y puesta a punto (2026-07-11/12)¶
Fecha: 2026-07-11 → 2026-07-12 Estado: aplicado Ámbito: vm-208 (media/apps), Proxmox (pmx/pmx2 + PBS), CT 100 (Vera/OpenClaw), caja GPU "sobremesa" (RTX 3080).
Sesión larga de auditoría + reparación. Tema recurrente: fallos silenciosos (backups que no corrían, rutas que desaparecían, espacio que no se liberaba, alertas que morían en buzones muertos). Este ADR es el registro de qué se rompió, por qué, y cómo quedó.
Contexto¶
Auditoría read-only en 4 capas (Vera / vm-208-docker / Proxmox-backups / caja-GPU) reveló varios problemas críticos ocultos. Se repararon en caliente. Resumen por área abajo; los detalles durables viven en los docs temáticos enlazados.
D1. Backups — la cadena estaba rota en silencio¶
Hallazgos:
- CT 100 (Vera) ~57 días sin backup (15-may → 11-jul). El job "Vera auto" 04:30 existía pero sin mailnotification ni prune-backups.
- CT 270 (caddy-primary) / 271 (caddy-secondary) / 280 (rp-server) NUNCA respaldados — el borde de routing sin DR.
- pbs-host-backup.service fallido en ambos nodos desde el hardening (fingerprint TLS de PBS cambió → validación fallaba) → config del clúster sin respaldar.
- El verificador backup-verifier-v2.sh (CT100) estaba roto: miraba /var/lib/vz/dump (local, no PBS), VMIDs equivocados (101/104/105/108/109 vs reales 100/208), y no estaba en cron.
- Las alertas de PVE (mailnotification=failure) iban a mail-to-root → /var/mail/root, que nadie lee.
Cambios:
- CT100 job: pvesh set /cluster/backup/0a3b1678… --mailnotification failure --prune-backups keep-last=7,keep-weekly=4,keep-monthly=3.
- Job nuevo edge caddy/rp (--vmid 270,271,280 --schedule 05:00 …) + backup inmediato.
- Job nuevo misc CTs (--vmid 102,110,172,251 --schedule 05:30 …) para los obsoletos (mayo) + backup inmediato.
- pbs-host-backup: fingerprint actualizado en /etc/pbs-host-backup/fingerprint (pmx+pmx2) al vigente de storage.cfg (79:88:22:cf:…:59). Servicio vuelve a subir /var/lib/pve-cluster a PBS.
- Monitor de frescura nuevo: /usr/local/sbin/backup-freshness.sh (pmx, cron 0 9 * * *) — consulta PBS vía pvesm list pbs, alerta a Telegram (bot de Vera vía pct exec 100) si un guest crítico está >48h sin backup. Signal-only.
- PVE → Telegram: endpoint webhook nativo (/cluster/notifications/endpoints/webhook "telegram", token como secreto PVE) enchufado al default-matcher. Ahora TODA alerta de Proxmox llega al móvil.
- PBS garbage-collection: liberó ~23 GB (80.6% → 77.5%).
Ver: backup-retention.md, alerting-flow.md.
D2. Routing — apps lazy caían de managed.caddy al dormir¶
Síntoma: pdf.monxas.casa (+ airdrop, code, jellyseerr, nopor, pinchflat, tube, tunarr) daban Caddy "Not found" 404.
Causa raíz: homelab-ctl.py host_port_for() leía solo NetworkSettings.Ports (runtime, vacío en contenedores "created" que nunca arrancaron) → no resolvía el puerto de una app lazy dormida → la descartaba en silencio de managed.caddy. El label tunnel.port solo salvaba (vía "Fallback 1") a las que tenían puerto host ≠ contenedor.
Cambios:
- Parche a host_port_for(): leer también HostConfig.PortBindings (config, presente en "created"). Ahora cualquier lazy enruta esté dormida o despierta. (Backup homelab-ctl.py.bak-20260711.)
- tunnel.port explícito añadido a los 8 stacks lazy (cinturón + tirantes).
- Herramienta de auditoría de rutas: scripts/route-audit.py (diff de todos los tunnel.hostname vs managed.caddy). ⚠️ (No entregado — el fichero no existe al 2026-07-12.)
- Regla: toda app lazy DEBE llevar tunnel.port o se cae del routing al dormir.
Ver: services-routing.md.
D3. Almacenamiento — 43 GB fantasma + arquitectura verificada¶
Hallazgos:
- vm-208 nunca propagaba los borrados a ZFS sin TRIM — fstrim -av reclamó 43.5 GiB (el zvol zfs-ha/vm-208-disk-1 en el pool pasó de 72.9G → 54.8G). fstrim.timer ya estaba activo (semanal), solo se adelantó.
- Arquitectura VERIFICADA correcta: contenido en el NAS (Terramaster NFS /mnt/nfs_media), la VM solo maquinaria (imágenes docker, DBs, metadata). Nada descolocado.
- ZFS ya comprime el zvol (lz4 1.76x → subido a zstd). Guest ve lógico, el pool guarda comprimido.
- 3 imágenes gordas sin uso eliminadas (open-webui 5G, orcaslicer 5G, firefox/reddit-chat 3G = 13G) → stacks a ~/stacks-disabled/ (recuperables).
- Disco guest vm-208: 82% → 71%. zfs-ha avail: 125G → 144G.
- Alerta HighDiskUsage: umbral subido 80% → 85% (appdata/prometheus/alerts.yml, < 20→< 15; Prometheus /-/reload NO habilitado → reiniciar contenedor para aplicar).
D4. Fiabilidad — logrotate roto + update rate-limited¶
- logrotate.service fallido:
/etc/logrotate.d/custom-limitsduplicaba syslog/auth/kern ya definidos enrsyslog→ logrotate se saltaba TODO el bloque → esos logs sin rotar. Fix: quitadas las 3 líneas duplicadas dersyslog(custom-limits las gestiona con cap 100M). Gotcha: nunca dejar.bakdentro de/etc/logrotate.d/(logrotate procesa todo el dir). Ver log-rotation-config.md. - update diario rate-limited (
toomanyrequests) casi a diario (burst del registry a las 04:00). Parche ahomelab-ctl.py: retry ×3 con backoff 5s solo entoomanyrequests(backup.bak-pullretry-20260712).
D5. Seguridad — credenciales en claro relocalizadas¶
GOG_KEYRING_PASSWORD (clawdbot2026) estaba en 14 ficheros, 3 mecanismos (6 .sh, 4 .py, 3 config yaml, 1 README); jobhunter2025 (Postgres) en 5 .py. Todo movido a /root/.openclaw/secrets.env (CT100). Python usa helpers self-loading (_gogsecret.py/_jobsecrets.py) que leen secrets.env directamente. Backups en /root/creds-bak-20260712/ (FUERA del dir git). Verificado: gog autentica, yamls válidos. Pendiente (diferido): restringir root SSH.
D6. Nuevas capacidades (contexto)¶
- Fábrica de imágenes en la caja GPU: SDXL-Turbo (
imagegen.service:9002) + comandos de Veraimagina.sh/arte.sh(txt2img/img2img → Telegram, auto-WOL). - Panel del piso de Colón:
piso.monxas.casa(stack vm-208, Flask+OIDC PocketID, restringido a un usuario). - Estos viven fuera de este repo (caja GPU / stack piso) — apuntados aquí para trazabilidad.
Residuales / follow-ups¶
- root SSH sin restringir en CT100 — diferido (riesgo de auto-lockout de todo el homelab; requiere sesión dedicada con forced-command keys).
- zfs-ha 72% fragmentación — sin defrag online en ZFS; se alivia liberando espacio (hecho ~19G hoy). Vigilar.
- VM 171 (HA):
discard=onya activo, trimmeado; ~1G real reclamado. No requiere reboot. - gog OAuth: scopes gmail/contacts flakean (re-auth con browser pendiente); calendar OK vía
gog-cal.sh. - Ver tech-debt.md para el registro vivo.