Skip to content

ADR-0026 — Arquitectura de dos nodos: roles, HA, fallos y vuelta a la normalidad

  • Fecha: 2026-10-17.
  • Versión: v3.1 (repaso del 2026-10-18 de madrugada).
  • v1: el traslado.
  • v2: roles, fallos y recuperación.
  • v3: reglas de operación, vías de emergencia, caza de cuelgues y pendientes.
  • v3.1: resultados de F0, plan de F2 corregido (lo crítico no espera en pmx-50) y lista de mañana.
  • Estado: en ejecución.
  • Cadena de acceso externo en HA: hecha.
  • F0: hecha (§D3).
  • F1-F6: hechas el 2026-10-18 (§D4, con correcciones de la revisión).
  • Responsable: Ramon (trabajo físico: RAM y BIOS de los dos nodos); ejecución técnica con Claude.
  • Solicitudes:
  • «examina todo y piensa cómo deberíamos montar todo con la CPU, RAM, etc. que tenemos… uso diario normal y cómo debe reaccionar cuando se caiga uno de ellos… cómo recuperar la normalidad… currátelo fuerte».
  • «plantea todo lo que puedas, mejora el diseño de todo el ADR».
  • «valida el resto, asegúrate de que todo tiene sentido aún, el plan. Haz un repaso».
  • Relacionado: ADR-0007 (cohesión, Caddy HA). Roles Ansible power_safety y proxmox_node. Memoria local: pmx50_apagado_vera_autowake_20261017, ha_acceso_externo_20261017.

0. Resumen

  1. pmx-50 sigue siendo el nodo principal en potencia. Hace unas tres cuartas partes del trabajo de CPU: multimedia, fotos, RAG, WP-Pulse, backups y la voz de Leina.
  2. pmx-51 pasa a ser el nodo de control y de la casa: acceso, login, contraseñas, consola, Vera y Home Assistant. Es poca CPU, y su valor está justo en el momento en que lo otro falla.
  3. Cada nodo es el salvavidas del otro:
  4. HA de Proxmox con réplicas.
  5. Reserva de RAM N-1 en los dos sentidos.
  6. Watchdog de hardware en los dos.
  7. Retorno automático (failback).
  8. Volver a la normalidad es un clic: comprobador normalidad (ya funciona), consola maint y runbooks en GitHub.
  9. Nada sabe en qué nodo vive un invitado: ayudante guest y envoltorio pve. Los 12 comandos fijos ya están migrados.

0.1 Lista para mañana (2026-10-18)

Ramon:

  • Recordatorio: poner un ESP32 como nodo Bluetooth (proxy BLE), por Ethernet si es posible, flasheado con ESPHome bluetooth_proxy. Los 4 actuales están apagados y son restos. Sin USB, HA sigue pudiendo moverse de nodo en caliente.
  • Antes de apagar pmx-51: consola maint → «6 · Normalidad y cambio de RAM» → «pmx-51 → mantenimiento». La propia consola se mueve a pmx-50 y se reinicia ~30 s: volver a entrar. Después, «pmx-51: apagar», que se niega si queda algo HA en pmx-51.
  • RAM: 4 tornillos de la tapa; levantarla como un libro, sin tirar del cable plano del hueco de 2,5"; fuera el Kingston de 8 GB (guardarlo); dentro los 2×16 GB a ~30° hasta el clic.
  • BIOS de pmx-51 (Supr; el primer arranque puede estar 1-2 min en negro): ve 32 GB, Restore on AC Power Loss = Power On y Wake-on-LAN activo.
  • BIOS de pmx-50 (reinicio, ~3 min sin multimedia): Restore on AC Power Loss = Power On, Wake-on-LAN y UMA Frame Buffer = 512 MB.

Claude, en este orden (§D2): F2 → F3 → F4 (HA) → F5 (ha-ml, tv-gw) → F6 (Vera).

0.2 Mapa de decisiones

# Decisión Estado
D1 C0 (rescate) y C1 (casa y asistente) viven en pmx-51, con failover a pmx-50 C0 ✅ · C1 mañana
D2 Watchdog de hardware iTCO_wdt en pmx-51 ✅ configurado y probado; activo tras el reinicio de mañana
D3 BIOS de los dos nodos: encender al volver la corriente y WoL; iGPU de pmx-50 a 512 MB (+3 GB) Mañana (Ramon)
D4 HA: cpu x86-64-v2-AES y sin USB ✅ los dos hechos
D5 Grupo crítico con failback 1, preferencia por pmx-51 y shutdown_policy=migrate Preferencia ✅ · el resto en F3
D6 ARC por fracción de RAM, orden de arranque y espera al NAS ✅ · cpuunits pendiente (F8)
D7 Vaultwarden sale de VM208 (CT 214) F7
D8 Reglas de operación (§C) ✅ casi todas · cpuunits y revisión de las tareas L1-L4 pendientes
D9 Comprobador de normalidad · restaurador, timer y avisos ✅ comprobador · el resto en F9
D10 Diagnóstico de cuelgues: kdump (640 MB de RAM reservada; máx. 3 volcados en disco), journald cada 5 s y journal en tiempo real a pmx-51 (sin ruido SSH, rotación diaria, máx. 50 MB × 14) ✅
D12 Logs acotados: journald con tope en los dos nodos (pmx-50 2 GB y 5 GB libres siempre; pmx-51 200 MB); sesiones SSH de root sin ruido (LogLevelMax=notice en logind y linger de root: ~35 → ~9 líneas por sesión, conservando Accepted/Failed para fail2ban/crowdsec); el comprobador avisa si / pasa del 85 % ✅
D11 Vías de emergencia (§B6) El PIN de maint espera la decisión de Ramon
— ESP32 BT, QDevice, enchufes inteligentes, corosync link1, SAI, copia externa Pendientes (§E3)

Parte A — Arquitectura

A1. Lo que hay (medido el 2026-10-17/18)

pmx-50 (proxmox) pmx-51 (proxmox2)
Equipo Minisforum «Venus series» Beelink U59 (placa JB95)
CPU Ryzen 7 7735HS, 8C/16T, AVX2 Celeron N5095, 4C/4T, sin AVX. Unas 2-2,5 veces menos por núcleo
RAM 32 GB DDR5, 28,5 visibles (la iGPU reserva ~3,5 GB) 8 GB → 32 GB DDR4 (2×16) desde el 2026-10-18
Disco NVMe Kingston 1 TB (zfs-ha de 854 G, 288 G libres) SSD VICK 119 G (sistema) y KingDian 240 G (zfs-ha, 163 G libres). SMART correcto
Red 1 GbE (más una Wi-Fi sin usar) 1 GbE
Software PVE 9.2.20, QEMU 11.0.3, kernel 7.0.14-19 Igual, así que la migración en vivo es posible
Watchdog sp5100_tco hardware, 10 s softdog → iTCO_wdt desde el reinicio de mañana (probado)
Fiabilidad De 4 a 12 cuelgues al día desde el 2026-10-05. RAM sana. El último, a las 00:07:35 del 2026-10-18 20 días sin incidencias
CPU (7 días) 2,7 de 16 hilos de media, p95 del 47 % 0,48 de 4 núcleos de media

Terceros que importan:

Equipo Papel Notas
RPi 4 .204 Pi-hole primario y QDevice SD y bajadas de tensión registradas (throttled=0x50000)
NAS .20 NFS, copias de HA y archivo de PBS Ya trae NUT en modo servidor
SAI APC Smart-UPS 1000 por USB en pmx-50 ~80 min. No bloquea a HA (§E3 P4)

Inventario completo de invitados en el Anexo A.

A2. Principios

  1. Colocar por dominio de fallo, no por potencia. Lo que sirve para detectar, entrar y reparar no comparte destino con lo que más falla: el nodo pesado (VM208 con NFS, 84 contenedores, OOMs y estados D).
  2. El HA de Proxmox no protege de cortes cortos. Recuperar exige esperar al aislamiento del nodo caído: unos 2-3 min. Un cuelgue de pmx-50 se resuelve solo en unos 2. Lo que vive en pmx-50 sufre el corte entero, tenga HA o no: hoy unos 25 min al día.
  3. Separar el núcleo de su parte pesada. El núcleo va al nodo estable y lo pesado (síntesis de Leina, RAG, ML) al potente. Si cae el potente, se pierde la función, no el servicio.
  4. Reserva N-1 en los dos sentidos, verificada por el comprobador.
  5. Nada sabe en qué nodo vive un invitado (guest / pve, §C1).
  6. La normalidad está escrita: estado deseado, comprobador y restaurador.

A3. ¿Por qué lo crítico en pmx-51 si el principal es pmx-50?

  • El conjunto crítico es ligero: ~0,5 núcleos del Ryzen y ~9 GB de RAM. En pmx-50 no aprovecha su potencia; solo hereda sus fallos.
  • Su valor está en el momento del fallo. Si vive en el nodo que se rompe, muere con él: el 2026-10-12 Ramon perdió todo durante 4,5 días.
  • pmx-50 conserva su papel: VM208 (el 70 % de la CPU), rag (AVX2), WP-Pulse, PBS (datastore local de 650 G) y la voz de Leina (leina-tts en VM208).
  • El reparto no se deshace cuando pmx-50 se cure (principio 1). Se revisaría si una pieza rinde mal en el Celeron (§E1).

A4. Capas y colocación

Capa Contenido Vive en HA Si cae su nodo
C0 Rescate cloudflared, WireGuard, PocketID, maint, warpgate, Vaultwarden (+ pihole2 y Caddy, con pareja propia) pmx-51 Sí → 50 2-3 min y vuelve sola
C1 Casa y asistente Home Assistant, ha-ml, Vera, tv-gw pmx-51 Sí → 50 2-3 min y vuelve sola
C2 Cómputo VM208 (incluida leina-tts), rag, WP-Pulse, rp-server, PBS, homelable, Caddy primario pmx-50 No Modo degradado (§B3)
C3 Auxiliares n8n, trove, argus pmx-51 No Esperan

A5. Presupuesto de recursos

A5.1 Uso normal

Con la RAM nueva en pmx-51 y la iGPU de pmx-50 a 512 MB.

pmx-51 (31,3 GB) pmx-50 (~31 GB)
Invitados, RAM real (picos) ~9,4 GB (~11) ~14,5 GB (~16,5)
Sistema + ARC (12,5 % de la RAM, máx. 4 GiB) 1,5 + 3,9 GB 1,5 + 2,5 GB
Libre ~15 GB ~11-13 GB
CPU media / p95 ~1,5 / ~2,5 de 4 núcleos ~2,8 / ~7 de 16 hilos

A5.2 Con un nodo caído (N-1)

El cálculo siguiente pertenece al plan original del 17 de octubre. No es la admisión vigente y no cubre todos los servicios, sus dependencias ni los recursos con afinidad estricta.

Cae Supuesto del plan original Alcance de la estimación histórica
pmx-50 C0 y C1 ya están en pmx-51 No preveía llegada adicional para esas capas; no acredita recuperación de VM208 ni de todo el homelab.
pmx-51 C0 + C1: ~9,4 GB y ~1,5 núcleos del Ryzen Estimación originalmente condicionada a reducir la reserva de iGPU; sin ello, ~8 GB y margen justo. No es una prueba de capacidad actual.

La ventana de dos horas del 22 de octubre no acredita margen N−1 suficiente: envolvente conservadora −3,81 GiB tras reservar 2 GiB; alternativa por máximo total de ronda −2,02 GiB. Son extremos descriptivos de aquella ventana, no un déficit simultáneo demostrado ni una lectura instantánea actual. Los pesos de CPU aplicados debajo no cambian ese presupuesto de RAM.

A5.3 Prioridad de CPU por capa (cpuunits, F8)

Grupo cpuunits Invitados
C0 400 Rescate
C1 casa 300 Home Assistant
C1 asistente 200 Vera, tv-gw, ha-ml
C3 50 n8n, trove, argus

Es solo un peso: no limita nada si sobra CPU.

Aplicación parcial de F8, 22 octubre 2026, 15:42 CEST: Cloudflared123, WireGuard155, maint212 y PocketID213 tienen ahora cpuunits=400. Antes no declaraban el parámetro y usaban el valor predeterminado100. Se aplicó con la API nativa de Proxmox sobre su propietario actual, pmx51, comprobando el digest de cada configuración. La configuración PVE queda persistida para el siguiente arranque o recuperación del contenedor.

Ampliación C0, 22 octubre 2026, 17:46:56 CEST: Vaultwarden214 pasa del predeterminado100 a cpuunits=400. Se resolvió el propietario actual pmx51 y se aplicó mediante la API de Proxmox con digest CAS. El resto de la configuración permanece igual. Verificación independiente17:47:37: HA started, peso del cgroup padre400, PID4001/start3439 conservados; sin reinicio ni migración. No se consultaron la aplicación, credenciales o base de datos. Los cuatro CT anteriores no se reaplicaron.

DNS y proxies C0, 22 octubre 2026, 17:57–17:59 CEST: Pi-hole204 y Caddy270/271 reciben también cpuunits=400. La aplicación con digest CAS conserva las demás propiedades de configuración. La lectura independiente de las 17:59:08–18 confirma configuración y peso del cgroup padre de 400, estado running y PID/start conservados: CT270 en pmx50, 2095/2442; CT204 en pmx51, 2252/2116; CT271 en pmx51, 2895/2726. Los boots 51c5b68b… y 86184726… permanecen estables. No hubo reinicios, migraciones ni pruebas de DNS, Caddy o rutas. Son ocho CT comprobados; no se reaplicaron los cinco anteriores.

CT Servicio cpuunits configurado cpu.weight del contenedor en el host
123 Cloudflared 400 400
155 WireGuard 400 400
212 Consola maint 400 400
213 PocketID 400 400
214 Vaultwarden 400 400
204 Pi-hole 400 400
270 Caddy primario 400 400
271 Caddy secundario 400 400

La comprobación final cotejó configuración y /sys/fs/cgroup/lxc/ID/cpu.weight; el cpu.weight del namespace hijo ns es otro nivel y no representa este peso. Los PID/start permanecieron estables durante la aplicación/comprobación final; las demás propiedades de configuración se conservaron. No se solicitó reinicio. La lectura independiente posterior se registra en el portal local.

El peso favorece el acceso de rescate bajo contención entre contenedores. No reserva núcleos, no acredita una mejora de latencia bajo carga y no recupera RAM ni resuelve la causa del watchdog. La ventana N−1 del22 sigue siendo la medición vigente. El resto de F8 sigue pendiente; no se aplicaron pesos a Vera, HA ni auxiliares. La revisión del22oct de las transiciones de maint encuentra L2–L4 ya bloqueadas; L1 se bloqueó también a las19:00 para impedir reanudaciones globales sin estado previo. Es contención, no un restaurador selectivo funcional. Ver la entrega de consola. Para volver al comportamiento previo, resolver primero el propietario y usar pct set ID --cpuunits 100 para esos ocho IDs (123/155/212/213/214/204/270/271). El valor explícito100 tiene el mismo efecto que el predeterminado anterior.


Parte B — Resiliencia

B1. Mecanismos

Mecanismo Cubre Tiempo Estado
Watchdog de hardware Cuelgue del nodo Segundos pmx-50 ✅ / pmx-51 tras F1
kdump Diagnóstico de un panic — pmx-50 ✅ (640 MB reservados; el initrd incluye sp5100_tco para no resetearse a mitad del volcado)
journald cada 5 s + journal en tiempo real a pmx-51 (/var/log/netconsole.log) Ver qué pasó justo antes de un cuelgue <1 s ✅ (netconsole de kernel no es viable: vmbr0 no admite netpoll)
HA de Proxmox + réplicas ZFS Nodo o disco muerto ~2-3 min (RPO de 5-60 min) C0 ✅, C1 mañana
failback 1 Volver al nodo preferido Segundos por CT; en vivo para HA F3
keepalived (Caddy) Caída de un Caddy o de su nodo ~3 s ✅
Pareja de DNS (RPi + pihole2) Caída de un DNS Inmediato ✅
Autoencendido WoL mutuo Nodo apagado 10 min ✅ (pmx-51 sin probar desde apagado: S2)
Orden de arranque + espera al NAS Avalancha de arranque, NFS roto tras un corte — ✅
Avisos de hardware Que Ramon sepa que algo no volvió 15 min F9
Enchufe inteligente Cuelgue que ningún watchdog resuelve Manual, en remoto Pendiente (§E3)

B2. Escenarios de fallo

# Escenario Qué pasa (auto) Corte de C0/C1 Corte de C2 Ramon
E1 pmx-50 se congela (de 4 a 12 veces al día) Watchdog → reset → arranque por orden → VM208 lista en 3-10 min. kdump intenta capturar y el journal ya está en pmx-51 0 3-10 min Nada
E2 pmx-50 apagado o muerto mucho tiempo WoL a los 10 min; aviso a los 15 (F9) 0 Hasta que vuelva Enchufe inteligente o en persona
E3 pmx-51 se congela o muere Reset por iTCO y/o recuperación en pmx-50 desde las réplicas. VIP → Caddy 270, DNS → RPi. Failback al volver ~2-3 min, pierde ≤ RPO 0 Nada; aviso si no vuelve
E4 Corte de luz El SAI aguanta ~80 min. Con batería baja, NUT apaga en orden. Al volver la corriente, la BIOS los arranca (D3) por orden; VM208 espera al NAS 0 mientras haya batería Ídem Mirar el comprobador
E5 QDevice caído Quórum 2/3. Peligro: el siguiente cuelgue de pmx-50 deja a pmx-51 con 1/3 y se autoaislaría (reinicio) 0, pero frágil 0 R5 el mismo día
E6 Cae el NAS VM208 sin multimedia; PBS sin sincronizar el archivo; HA sin copias 0 Multimedia Arreglar el NAS
E7 Cae internet Sin acceso externo; en casa todo funciona 0 en casa 0 en casa —
E8 Cae el switch o el router Todo incomunicado Total Total Red física
E9 Mantenimiento planificado node-maintenance mueve, se trabaja y vuelve Segundos Lo que dure (si es pmx-50) M1
E10 Muere el SSD zfs-ha de pmx-51 HA reintenta y reubica en pmx-50 desde las réplicas ~3-5 min 0 Cambiar el SSD

B3. Modo degradado

Función pmx-50 caído pmx-51 caído (tras 2-3 min)
Acceso externo, login, contraseñas, consola, WireGuard, warpgate ✅ ✅
Casa: luces, Zigbee (SLZB-06M por red), automatizaciones, portero, sensores ✅ ✅
Voz: reconocimiento (stt.home_assistant_cloud) y palabra de activación (openWakeWord en HA) ✅ ✅
Voz: síntesis con Leina (VM208) ⚠️ Piper o la nube ✅
Vera: chat, razonamiento, SSH, HA ✅ ✅
Vera: música, *arr, Paperless, RAG, jev-gateway ❌ ✅
Tele (sale por tv-gw) ✅ ✅
Jellyfin, Immich, Paperless, Karakeep, Navidrome ❌ ✅
Monitorización completa ❌ (sondas de maint y normalidad) ✅
Copias de PBS y restauraciones ❌ ✅
docs.monxas.casa ❌ (VM208): runbooks en GitHub ✅

B4. Estado normal y comprobador

normalidad (en los dos nodos, en la tarea de maint «Estado de normalidad» y con pve normalidad) devuelve «NORMAL» o la lista de desviaciones con su corrección.

# Comprobación En normalidad
1 Quórum con 3 votos (QDevice incluido) ✅
2 Cada recurso HA started en su nodo preferido (detecta error, ignored, stopped y failback pendiente) ✅
3 Réplicas OK y al día (antigüedad < 2× su intervalo, leído de replication.cfg) ✅
4 VIP .250 responde ✅
5 Watchdog de hardware en los dos nodos ✅
6 kdump ready en pmx-50 y volcados nuevos en /var/crash ✅
7 Sin /etc/node-autowake-off olvidado ✅
8 Todos los invitados en algún job de vzdump y con backup en PBS de menos de 26 h ✅
9 VM208: 0 unhealthy, NFS rw y raíz monxas:monxas ✅ desde pmx-50 o maint (pmx-51 no tiene clave para VM208)
10 N-1: lo HA de un nodo cabe en el otro con 2 GB de margen ✅
11 pmx-51: RAM disponible ≥ 20 % y swap < 512 MB ✅
12 Deriva del túnel (homelab-ctl status) = 0 Pendiente (F9)
13 Ningún comando con nodo fijo (grep de tasks.yaml y scripts) Pendiente (F9)

Pendiente (F9):

  • «Restaurar normalidad»: solo correcciones seguras, con confirmación.
  • Timer en pmx-51: tras cada arranque de un nodo y cada 6 h.
  • Aviso de hardware si algo no vuelve en 30 min.

B5. Runbooks

Runbook Cuándo Pasos
R1 Tras un cuelgue de pmx-50 Automático. Revisar /var/log/netconsole.log en pmx-51 (último minuto antes del reset) y /var/crash en pmx-50
R2 Tras una caída larga de pmx-50 R1 + poner PBS al día + homelab-ctl status + vigilar el FailCount de las réplicas
R3 Tras volver pmx-51 El failback lo hace solo. Si un recurso queda en error: ha-manager set <sid> --state disabled y luego --state started. El failback sincroniza antes de mover y no pierde datos; solo se pierde el RPO del momento del fallo
R4 Tras un corte de luz Esperar unos 10 min (NAS y VM208) y lanzar el comprobador
R5 QDevice caído Urgente. ha-manager set <sid> --state ignored en todos los recursos HA (los servicios siguen, sin autoaislamiento ni failover). Arreglar la RPi; si la SD ha muerto, restaurar qnetd desde /root/qdevice-backup/ de pmx-51 (README dentro). Con 3 votos, volver a started
M1 Mantenimiento planificado Tareas de maint «→ mantenimiento» / «← salir». Equivale a node-maintenance enable, flags de autoencendido en los dos nodos, trabajar, disable, quitar los flags y el comprobador

B6. Vías de emergencia

# Vía Depende de Para
1 Túnel + PocketID → maint C0, internet Lo habitual
2 Túnel + PIN por email solo para maint C0 sin PocketID Por si se rompe PocketID. Pendiente de decisión de Ramon (el 2026-09-27 se quitaron los PIN a propósito)
3 WireGuard + SSH CT 155, router Sin Cloudflare
4 warpgate CT 301 Bastión con login propio
5 App del enchufe inteligente en la nube Nada del homelab Cortar y devolver la corriente de un nodo colgado (§E3)
6 Alguien en casa — Último recurso

Los runbooks se leen en GitHub (monxas/homelab-infra), no en docs.monxas.casa.


Parte C — Reglas de operación

C1. Nada asume en qué nodo vive un invitado — ✅

Pieza Qué hace
guest node\|status\|config\|exec <id> (en los dos nodos, Ansible) Localiza el invitado con pvesh get /cluster/resources y ejecuta en su nodo
pve "<cmd>" (en maint) Ejecuta en pmx-51 y, si no responde por SSH, en pmx-50

Migrados: los 12 comandos de homelab-maint/tasks.yaml y la sonda vera.

Quedan:

  • pbs-config-backup.sh en pmx-50. Aceptable: PBS no se mueve (datastore local).
  • Una referencia de Vera a pct exec 172: revisar en F6.

C2. Invitados con HA: su estado solo se toca con ha-manager

  • Regla: para parar o arrancar un invitado con HA, ha-manager set <sid> --state …. Para operaciones largas, ignored.
  • memtest-ram.sh: ya cumple, porque no toca a los invitados con HA.
  • Por revisar (F8):
  • Las tareas L1-L4 de maint.
  • proxmox-ups-shutdown.sh, que para todos los CT. En un apagado por SAI es aceptable; queda documentado.

C3. Un único mecanismo de actualizaciones — ✅

  • Retirado: el cron tteck update-lxcs-cron.sh de pmx-51 (estaba roto: pct: command not found).
  • Queda un único mecanismo: las tareas de maint.
  • Orden de actualización:
  • pmx-50 primero, como canario.
  • 24 h de espera.
  • pmx-51.
  • Los reinicios, siempre con node-maintenance.
  • Versiones: no se fijan (regla de la casa). Se escalonan.

C4. Backup obligatorio — ✅

  • Todo invitado nuevo entra en un job de vzdump al crearse. El comprobador marca cualquiera que no lo esté.
  • Riesgo conocido: el datastore principal de PBS está en el mismo NVMe que la mitad de los invitados. El archivo se sincroniza al NAS; la copia externa está pendiente (§E3).

C5. Capacidad vigilada — ✅

  • El comprobador recalcula N-1 en cada pasada.
  • Antes de añadir un invitado a C0/C1, se comprueba que siga cabiendo en el otro nodo.

Parte D — Plan

D1. Caza de cuelgues

Hallazgo del 2026-10-18 que cambia el análisis: los cuelgues se comían los últimos ~5 min de log. journald solo escribía a disco cada 5 min los mensajes no críticos: el qm set 171 --delete usb0 de las 00:0x no llegó al disco antes del cuelgue de las 00:07:35. Los cuelgues parecían «silenciosos» en parte por eso. Desde ahora:

  • journald escribe cada 5 s.
  • El journal entero va en tiempo real a pmx-51 (/var/log/netconsole.log).
  • kdump tiene640MiB reservados. Corrección21oct: el kernel de captura figura cargado en el boot e269 a las18:08, pero un reset hardware puede ocurrir sin panic/kexec o antes de que termine el volcado. No se garantiza un vmcore ni que el watchdog permita terminar la captura.

Estas vías aumentan las posibilidades de conservar evidencia; no garantizan rastro del siguiente cuelgue. journal-stream y Pulso necesitan ejecución y red; el receptor llamado netconsole no acredita por sí solo una consola de kernel independiente del espacio de usuario. Véanse los límites de captura y la admisión causal actual.

  • Ritmo: λ ≈ 8 al día. La probabilidad de no ver ninguno en t horas sin que nada cambie es e^(−λt/24): 12 h → 1,8 %, 24 h → 0,03 %.
  • Experimentos:
# Cambio Estado
1 Dongle BT fuera de HA (passthrough USB) En curso desde las 00:08:40 (VM 171 arrancó sin usb0 tras el cuelgue de las 00:07:35). Con 12 h sin cuelgues ya sería significativo
2 Home Assistant fuera de pmx-50 F4
3 Vera fuera de pmx-50 F6
4 Si sigue: lo que queda en pmx-50 (VM208, rag, WP-Pulse) o el kernel (probar 7.0.14-15) ADR aparte, con los logs nuevos
  • Interferencia: F4 y F6 caen dentro de la ventana del experimento 1. Se acepta, porque mover C1 está justificado por diseño, no solo por los cuelgues. Si los cuelgues paran, se atribuye a «dongle o C1» y se afina después si interesa.
  • Criterio de aborto en pmx-51: cualquier reinicio inexplicado de pmx-51 con un invitado recién llegado → ese invitado vuelve a pmx-50 de inmediato.

D2. Fases

Fase Cuándo Contenido Corte
F0 ✅ 2026-10-17 Preparación (§D3) ~2 min de HA (cambio de CPU)
F1 Mañana (Ramon, ~40 min) «pmx-51 → mantenimiento» → «apagar» → RAM → BIOS de pmx-51 → (aparte) BIOS de pmx-50 C0 se mueve a pmx-50 (segundos por CT); C3 y Caddy 271 apagados ~20 min; C2 ~3 min por la BIOS de pmx-50
F2 En cuanto arranque pmx-51 (1) «pmx-51: comprobar RAM nueva, watchdog y quórum». (2) «pmx-51 ← salir de mantenimiento»: C0 vuelve enseguida (la consola se reinicia de nuevo). (3) «pmx-51: lanzar memtester» con C0 ya en pmx-51, y «progreso». Si hay un solo error: C0 vuelve a pmx-50 (mantenimiento) y se devuelve la RAM Segundos
F3 Tras el memtester OK shutdown_policy=migrate; failback 1 en C0. El ARC lo sube Ansible solo (~3,9 GiB) 0
F4 Tras F3 HA: qm migrate 171 proxmox2 --online (sin reinicio: la CPU ya es portable y no tiene USB), HA y regla de afinidad. Experimento 2 ~0
F5 Tras F4 ha-ml y tv-gw (pct migrate --restart) con HA Segundos
F6 Tras F5 (o +1 día) Vera (pct migrate --restart, con réplica: ~1 min), HA y pruebas. Experimento 3 ~1 min
F7 +1-2 días warpgate en HA; Vaultwarden → CT 214 (RPO de 5 min) Minutos
F8 Parcial, 22 oct cpuunits=400 aplicado a CT123/155/212/213/214/204/270/271; resto de pesos y tareas L1-L4 (C2) pendientes 0
F9 +2-3 días Restaurador, timer y avisos de hardware; checks 12-13 del comprobador; PIN de maint si Ramon lo aprueba 0
F10 +3-7 días Simulacros S1-S3; cierre del ADR tras 7 días en «NORMAL» Controlados

Por qué F2 cambió en el repaso: antes C0 esperaba en pmx-50 durante el memtester (unas 3 h). Con λ ≈ 8 al día, la probabilidad de al menos un cuelgue de pmx-50 en 3 h es del 63 %, y cada uno cortaría todo el acceso externo 2-3 min. Con C0 de vuelta en pmx-51, el riesgo pasa a ser que la RAM nueva sea defectuosa: es menor, y el memtester lo detecta mientras ocurre.

Simulacros de F10:

Simulacro Qué se comprueba
S1. Mantenimiento de pmx-51 Ida y vuelta de C0+C1, midiendo el corte por servicio
S2. poweroff de pmx-51 (con Ramon en casa) Recuperación del HA y que el WoL despierta a pmx-51 desde apagado
S3. Cuelgue natural de pmx-50 C0/C1 no se enteran; el journal queda en pmx-51

D3. Resultado de F0 (2026-10-17 23:30 → 2026-10-18 00:25)

# Paso Resultado
1 CT 213 al backup ✅
2 Réplicas previas a pmx-51 ✅ 100-0 (/15), 172-0 (/30), 110-0 (hourly), al día
3 Cron tteck ✅ Retirado
4 iTCO_wdt ✅ Carga e inicializa sin bloqueo NO_REBOOT. Configurado; activo tras el reinicio
5 Ansible proxmox_node ✅ guest, ARC por fracción, wait-nas-hook.sh, memtest-ram.sh, normalidad
6 Orden de arranque ✅ 21 invitados en order=1..6; VM208 la última, con hookscript (probado)
7 HA x86-64-v2-AES ✅ API en 166 s; todos los add-ons arrancan sin AVX; HA completo ≈ 5-6 min tras reiniciar (el Supervisor tarda ~4 min en levantar Z2M y el resto)
8 Dongle BT ✅ Retirado el 2026-10-18 (ver más abajo)
9 Voz ✅ Ya usaba STT en la nube; síntesis con Leina (VM208); openWakeWord en HA. Nada que mover
10 tv-gw ✅ Es la salida de la tele (NAT, DNS → .204, bloqueo DoH/DoT; vecino LG ac:5a:f0 .227)
11 Vera sin AVX ✅ Backup restaurado sin red en pmx-51: el gateway arranca y sigue activo; koffi, node-pty y rolldown cargan; Piper sintetiza (más lento); 0 invalid opcode. No hay faster-whisper ni embeddings locales en uso. CT de prueba destruido
12 Consola maint ✅ pve + guest; pack «6 · Normalidad y cambio de RAM» con 7 tareas probadas (las de solo lectura)
13 normalidad ✅ Hoy marca 2 avisos esperados: softdog y swap en pmx-51. Los dos desaparecen con F1
14 Diagnóstico de cuelgues ✅ journald cada 5 s, journal en tiempo real a pmx-51 (probado <1 s) y kdump con 640 MB activos

El dongle BT, en detalle:

  • Por qué se quitó:
  • Los 4 proxies ESP32 (BT-proxy-habitacion, cocina, cocina-2 y oficina) no están en la red (ni concesión DHCP). Para Ramon son restos.
  • Los Shelly son 1L de primera generación, sin Bluetooth.
  • Con el dongle puesto, el seguimiento BLE ya no funcionaba: los 3 private_ble_device (iPhone y Apple Watch) y los 10 rastreadores de Bermuda en not_home con Ramon en casa.
  • Cómo: qm set 171 --delete usb0, en caliente.
  • Alternativa descartada: un dongle por nodo con resource mapping. PVE 9.2 rechaza la migración en vivo con USB mapeado.
  • Futuro: proxy ESP32 por Ethernet (lista de mañana).

D4. Ejecución del 2026-10-18 y correcciones de la revisión con agentes

Hecho (11:20-13:50):

Paso Detalle
F1 pmx-51 en mantenimiento (C0 → pmx-50 en 77 s, verificado desde fuera) → apagado → 2×16 GB Gigastone a 2933 MT/s en doble canal → arranque con iTCO_wdt y quórum de 3
F3 failback 1 en C0 (sin él, los recursos no volvieron al salir del mantenimiento, porque la regla migrada traía failback 0) y shutdown_policy=migrate
F2 Memtester de 27,4 GB: lo cortó Ramon tras pasar los 7 primeros tests (Stuck Address, Random Value, Compare ×6, Sequential Increment), para mover C1 de inmediato: pmx-50 estaba con PSI full avg300 = 21-31 % y la swap al 100 %
F4 HA: migración en vivo completada (28 ms de parada), pero el invitado se reinició al llegar. La migración en vivo AMD↔Intel no es fiable ni con x86-64-v2-AES. Por eso vm:171 lleva failback 0: cada movimiento supone ~5-6 min de reinicio de HA
F5-F6 ha-ml, tv-gw y Vera con pct migrate --restart (14-23 s cada uno), dados de alta en HA (failback 1) y añadidos a la regla de afinidad. Todas las réplicas con rate 50
Efecto PSI de pmx-50 a ~0, swap vaciada, 8,7 GB disponibles. pmx-51 con ~15 GB libres

Pendiente: repetir el memtester esta noche sobre la RAM libre de pmx-51 (~15 GB) para cubrir los tests de patrones.

BIOS de pmx-50 (14:00-15:50): el UM773 Lite con BIOS 1.15 (la última) no arranca con UMA_SPECIFIED + 512M. Pantalla negra, ni siquiera llega a la red, y la BIOS vuelve sola a los valores anteriores tras el arranque fallido. D3 (iGPU) queda descartado; la iGPU sigue en ~2,5 GiB. Para resetear la BIOS: agujero CLR_CMOS del frontal, 30 s con el equipo desenchufado; el primer arranque tarda hasta 2 min en negro. Queda por confirmar si se guardó «Restore on AC Power Loss».

Banco de pruebas de la migración en vivo AMD↔Intel (2026-10-18, 17:10-18:50). Clon de HA sin red (VM 9171); en cada caso se compara el boot_id del invitado antes y después, y a los 90 s.

Configuración de CPU Dónde arrancó Resultado
x86-64-v2-AES (qemu64) Intel ✅ 2/2 al migrar (sin comprobación tardía)
x86-64-v2-AES AMD ❌ se cuelga al llegar al Intel (lo mismo que le pasó al HA real)
+ tsc-frequency=2000000000 AMD ❌
kvm64 AMD ❌ (el invitado sigue viendo AuthenticAMD)
+ vendor=GenuineIntel AMD ✅ 4 seguidas, ❌ en la 5.ª
vendor=GenuineIntel + TSC fijo AMD ✅ 3, ❌ se cuelga un rato después
vendor=GenuineIntel + TSC fijo Intel ❌ se cuelga tras la 1.ª migración (Intel→AMD)

Causas identificadas:

  • Con KVM el invitado hereda el fabricante del nodo donde arranca: con AuthenticAMD usa VMMCALL, que en Intel falla.
  • Además, el TSC no se transmite si no está fijado.

Con las dos causas corregidas los fallos se vuelven intermitentes, pero no desaparecen.

Conclusión: no hay migración en vivo fiable entre estos dos nodos. Encaja con la postura de Proxmox de no soportar la migración en vivo entre fabricantes. Home Assistant se mueve solo en frío, con failback 0.

Opciones:

  1. Acortar el arranque de HA, pasando a manual los add-ons que no hacen falta al arrancar.
  2. A medio plazo, dos nodos del mismo fabricante. Por ejemplo, un mini PC Ryzen con DDR4 que reaproveche los 2×16 GB, con lo que habría migración en vivo y AVX2 en los dos.

Correcciones (verificadas en el código de PVE 9.2 y en los logs):

  1. Tiempos de HA:
  2. fence_delay 60 s, bloqueo del agente 120 s y detección de corosync ~22 s.
  3. Un cuelgue corto de pmx-50 (~20 s fuera de la membresía) nunca llega a aislarse. El HA ni actúa: el recurso se reinicia en el mismo nodo. El principio A2.2 se queda corto: es aún más cierto.
  4. En una caída real, los CT vuelven en ~2-2,5 min y Home Assistant en ~8 min (2,5 de recuperación + 5-6 de arranque), no en «2-3 min».
  5. R5: ignored tarda ~10 min en soltar el watchdog (max_active_idle_rounds). Se sustituye por ha-manager crm-command disarm-ha ignore (PVE 9.2), que lo suelta casi al momento, y arm-ha para volver.
  6. QDevice: ffsplit es correcto, pero sin tie_breaker gana el nodeid 1 (pmx-50, el inestable). Propuesta: tie_breaker: 2, cambio de corosync con bump de versión. Pendiente de aplicar.
  7. N-1: las tablas A5 contaban memory.current sin la swap.
  8. Medido: el conjunto HA de pmx-51 es de 9,8 GB reales frente a 7,8 libres en pmx-50: no cabe.
  9. normalidad mide ya RAM + swap y la PSI, y comprueba las parejas Caddy 271 y pihole2. Las dos estaban paradas por el memtester; se arrancaron a las 13:3x.
  10. El rediseño del conjunto de failover está en ADR-0027 §5.2.
  11. Cuelgues:
  12. El USB queda refutado: hubo un cuelgue a las 02:25 sin USB.
  13. 85 cuelgues entre el 05-10 y el 18-10, sin ninguna señal previa en métricas ni logs: congelación total de todos los núcleos, sin pánico, NMI ni MCE.
  14. Hipótesis: plataforma ~60 % (Wi-Fi MT7921, APST del NVMe, I225-V, alimentación o temperatura; DIMM de hasta 89 °C), un invitado como VM 208 ~25 %, el kernel ~10 %.
  15. Los experimentos van a un ADR-0028 (ver ADR-0027 §7).

Parte E — Riesgos, alternativas y pendientes

E1. Riesgos

Riesgo Mitigación
QDevice en una RPi con SD y bajadas de tensión (E5) R5 y aviso (F9). Fondo: fuente oficial y SSD (P1)
RAM Gigastone defectuosa o inestable a 32 GB (Intel especifica 16 GB) memtester en F2; C0 vuelve a pmx-50 a la primera; repuesto de 8 GB; devolución
Llevar el disparador de los cuelgues a pmx-51 Uno a uno y criterio de aborto (D1). Ahora, con journal en tiempo real para verlo
pmx-51 concentra lo crítico HA → pmx-50, N-1 vigilado, iTCO_wdt y max_relocate
HA tarda 5-6 min en estar completo tras reiniciar Las migraciones de HA son en vivo (sin reinicio). Solo un failover tras caída lo reinicia
Piper más lento en el Celeron (Vera) Aceptado: uso puntual
failback 1 rebota los servicios si pmx-51 es inestable El comprobador lo detecta; si pasa, failback 0 temporal

Criterios de revisión: pmx-50 lleva 30 días sin cuelgues, pmx-51 pasa del 70 % de CPU p95 sostenido, o llega hardware nuevo.

E2. Alternativas descartadas

Alternativa Por qué no
Lo crítico en pmx-50 con HA hacia pmx-51 Principio A2.2: cada cuelgue sigue cortando 2-3 min (~25 min al día)
Todo en pmx-50 4,5 días sin nada
VM208 o PBS en HA Tamaño, CPU y datastore local
Dongle BT por nodo con resource mapping PVE 9.2 no migra en vivo con USB mapeado: cada movimiento o failback apagaría HA 5-6 min
Liberar RAM sin comprar No daba para HA
Cable USB del SAI a pmx-51 Simétrico: solo reduce la probabilidad
netconsole de kernel Netpoll setup failed en vmbr0 (tiene tap/veth): se usa el journal en tiempo real

E3. Pendientes (por valor/coste)

# Pendiente Valor Coste
P0 ESP32 como proxy Bluetooth (Ethernet, ESPHome bluetooth_proxy) — recordatorio de mañana Medio (presencia BLE) ~10-25 €
P1 Endurecer el QDevice: fuente oficial 5,1 V/3 A y SSD USB para la RPi 4 (o qnetd en un tercer equipo). Copia de sus certificados hecha el 2026-10-18 (/root/qdevice-backup/ en pmx-51 y qdevice-backup/ en el NAS, con README de restauración): una SD muerta se recupera en minutos Alto (E5) ~25 €
P2 Enchufes inteligentes con app en la nube para los dos nodos (requiere D3) Alto ~20-40 €
P3 Segundo enlace de corosync: USB-Ethernet en cada nodo y cable directo (link1, réplicas y migraciones) Medio ~25 €
P4 SAI independiente de los nodos: NUT en el NAS (ya trae netserver) o tarjeta APC. No bloquea a HA (add-on netclient con shutdown_host: false; sin automatizaciones) Bajo-medio 0 / ~60 €
P5 Copia externa de PBS Medio Variable
P6 Historial de sondas en maint Medio 0
P7 homelab-ctl de reserva desde pmx-51 Bajo 0
P8 Más RAM para VM208 con los +3 GB de la iGPU si N-1 lo permite Bajo 0

Anexo A — Inventario y destino por invitado

«Real» = memory.current (LXC) o RSS (VM) del 2026-10-17. CPU = núcleos del nodo actual (RRD de 7 días).

ID Invitado Hoy → destino Capa Límite Real (pico) CPU media / p95 Disco Réplica (RPO) HA Notas
CT 123 cloudflared 51 C0 256 MB 115 MB 0,01 2 G 15 min ✅ —
CT 155 wireguard 51 C0 256 MB 120 MB 0 6 G 15 min ✅ —
CT 212 maint 51 C0 512 MB 89 MB 0 0,4 G 5 min ✅ pve/guest; pack 6
CT 213 pocketid 51 C0 384 MB 186 MB 0 0,4 G 5 min ✅ Backup ✅
CT 214 vaultwarden (nuevo) VM208 → 51 C0 256 MB ~20 MB — <0,1 G 5 min F7 OIDCWarden + SSO con PocketID
CT 301 warpgate 51 C0 512 MB 57 MB 0 4 G 30 min F7 Login propio
CT 204 pihole2 51 C0 512 MB 79 MB 0,01 4 G — pareja RPi —
CT 270 / 271 Caddy 50 / 51 C0 512 MB / 1 GB 107 / 396 MB 0,01 / 0,02 0,6 / 8 G — keepalived —
VM 171 Home Assistant 50 → 51 C1 6 GB (balloon 4,6) 4,5 GB 0,28 / 0,44 30 G 15 min F4 x86-64-v2-AES ✅; sin USB ✅; voz: STT en la nube y TTS Leina; NUT a .50 (no bloquea); arranque completo 5-6 min
CT 172 ha-ml 50 → 51 C1 768 MB 92 (305) MB 0,01 1,1 G 30 min F5 Va con HA
CT 100 Vera 50 → 51 C1 6 GB 2,8 (3,5) GB 0,13 / 0,26 9,5 G 15 min F6 Probada sin AVX ✅. Depende de VM208 y de rag para parte de sus herramientas
CT 110 tv-gw 50 → 51 C1 1 GB 132 MB 0,04 1,2 G 60 min F5 Salida de la tele ✅
VM 208 media server 50 C2 12 GB 11,4 GB 0,91 / 1,61 99 G — ❌ leina-tts; order=6 y espera al NAS
CT 251 rag 50 C2 3 GB 1,3 (3,0) GB 0,11 / 0,38 10 G — ❌ AVX2 obligatorio
CT 281 wp-pulse-host 50 C2 3 GB 1,0 (1,3) GB 0,06 / 0,10 7 G — ❌ —
CT 186 PBS 50 C2 1,5 GB 63 MB 0,03 / 0,17 0,9 G + 650 G — ❌ Datastore local
CT 280 rp-server 50 C2 1 GB 457 MB 0,02 2 G — ❌ —
CT 305 homelable 50 C2 1 GB 166 MB 0,01 1 G — ❌ —
CT 200 n8n 51 C3 1 GB 426 (679) MB 0,01 10 G — ❌ —
CT 302 / 303 trove / argus 51 C3 512 / 384 MB 203 / 80 MB 0 3 / 2 G — ❌ —

Anexo B — Comandos por fase (mañana)

Las tareas de la consola maint, pack «6 · Normalidad y cambio de RAM de pmx-51», envuelven F1-F2. Comandos equivalentes:

F1

# «pmx-51 → mantenimiento»
for h in 192.168.0.XXX 192.168.0.XXX; do ssh root@$h touch /etc/node-autowake-off; done
ssh root@192.168.0.XXX 'ha-manager crm-command node-maintenance enable proxmox2'   # C0 → pmx-50; espera a que se vacíe
# «pmx-51: apagar» (aborta si queda algún recurso HA en pmx-51)
ssh root@192.168.0.XXX poweroff

F2

# Tras arrancar: «pmx-51: comprobar RAM nueva…» (primera parte)
dmidecode -t 17 | grep -E "Size|Configured Memory Speed|Part"; free -g
cat /sys/class/watchdog/watchdog0/identity        # iTCO_wdt
pvecm status | grep -E "Total votes|Quorate"
# «pmx-51 ← salir de mantenimiento»: C0 vuelve; se quitan los flags de autoencendido
ha-manager crm-command node-maintenance disable proxmox2
# memtester con C0 en marcha (memtest-ram.sh no toca los invitados con HA)
systemd-run --unit=memtest-ram --collect /usr/local/sbin/memtest-ram.sh 1

F3

# /etc/pve/datacenter.cfg → ha: shutdown_policy=migrate
for r in ct:123 ct:155 ct:212 ct:213; do ha-manager set $r --failback 1; done
pve normalidad    # debe dar NORMAL (salvo el trabajo pendiente)

F4 — Home Assistant (sin reinicio)

qm migrate 171 proxmox2 --online
ha-manager add vm:171 --state started --max_restart 3 --max_relocate 2 --failback 1 --comment "Home Assistant - C1"
ha-manager rules set node-affinity ha-group-ha-network --resources ct:123,ct:155,ct:212,ct:213,vm:171

Pruebas:

  • API → 401.
  • Automatizaciones disparando.
  • Portero: timbre de prueba.
  • Zigbee responde.
  • Voz: STT en la nube y TTS de Leina.
  • Copias de HA al NAS.
  • CPU de pmx-51 a los 15 min.

F5 / F6

pct migrate 172 proxmox2 --restart; pct migrate 110 proxmox2 --restart
pct migrate 100 proxmox2 --restart --timeout 180
journalctl -k | grep -iE "invalid opcode|illegal instruction"     # vacío
for r in ct:172 ct:110 ct:100; do ha-manager add $r --state started --max_restart 3 --max_relocate 2 --failback 1; done
ha-manager rules set node-affinity ha-group-ha-network --resources ct:123,ct:155,ct:212,ct:213,vm:171,ct:172,ct:110,ct:100

Vuelta atrás en F4-F6: qm migrate 171 proxmox --online / pct migrate <id> proxmox --restart. Las réplicas invierten su sentido solas.

Enmienda 2026-10-19,22:00CEST: política de reinicio con recursos estrictos

Sustituye shutdown_policy=migrate de D5/F3: la configuración activa queda ha: shutdown_policy=conditional. Existen cuatro recursos estrictos51 que no pueden evacuarse y el N-1 no tiene reserva incondicional amplia. Migrate puede bloquear el apagado esperando un destino imposible o cargar50en exceso. Conditional congela la ubicación HA durante un reboot ordenado y recupera en el mismo nodo; en un apagado intenta failover conforme a las afinidades. No modifica las reglas ni el tratamiento de una pérdida inesperada del nodo.

Validación: reboot51 para HuC con freeze temporal, regreso21:59,14recursos started22:00,quórum3y ningún servicio systemd fallido. Copia previa de datacenter.cfg en51/root/datacenter.pre-jellyfin-huc-20261019.cfg. Volver a migrate reintroduce la incompatibilidad con recursos estrictos; no es una solución al déficit RAM. Aplicación y límites.