"description":"Cómo se construye ProxMenux Monitor: estructura AppImage, blueprints Flask, tareas de fondo, datos de psutil, pvesh, smartctl y journalctl, almacenamiento SQLite, terminal WebSocket, proveedores de IA, canales de aviso, proxy inverso y Fail2Ban opcional.",
"description":"Cómo se distribuye ProxMenux Monitor, qué contiene el AppImage y cómo las peticiones del navegador pasan por Flask hasta las herramientas del host y el almacenamiento SQLite.",
"body":"Un proceso Python escucha en TCP 8008. Sirve la web estática Next.js, ofrece la API REST, gestiona el terminal WebSocket, ejecuta Health Monitor y envía notificaciones. No necesita un servidor web separado, un intermediario de mensajes ni una base de datos externa."
"intro":"Una petición de datos típica sigue este recorrido; las preferencias del navegador pueden gestionarse localmente:",
"diagramCaption":"Las rutas protegidas validan JWT si la autenticación está activa. Flask devuelve datos del host almacenados en caché o recién obtenidos. El control opcional de Fail2Ban consulta su lista de bloqueos en caché. Solo se confía en cabeceras de IP reenviadas con PROXMENUX_TRUST_PROXY=1; si no, se usa la IP de la conexión. El estado persistente incluye SQLite y archivos JSON como auth.json.",
"threadsIntro":"El proceso también ejecuta <strong>hilos en segundo plano</strong>. Estos ejemplos recogen datos, actualizan cachés y SQLite, y envían notificaciones. Hay más tareas y el envío depende de que esté activado:",
"job":"Ejecuta el ciclo Health Monitor de diez categorías, guarda errores y observaciones de disco, mantiene los descartes y envía nuevos eventos al motor de avisos."
"cadence":"CPU 5 s; temperatura 15 s; memoria 30 s",
"job":"Muestrea uso CPU, memoria y temperatura CPU para los indicadores y la detección sostenida, con independencia del análisis general de cinco minutos."
"job":"Inicia observadores del journal, tareas y hooks (<code>JournalWatcher</code>, <code>TaskWatcher</code>, <code>ProxmoxHookWatcher</code>) y envía a los canales configurados, con reformulación IA opcional."
"<strong><code>User=root</code></strong>: el servicio usa privilegios root para operaciones del host como SMART, <code>pvesh</code> y gestión ZFS. Los procesos del terminal heredan esos permisos.",
"<strong><code>Restart=on-failure</code></strong> con espera de 10 segundos: se reinicia automáticamente tras una salida con error.",
"<strong><code>After=network.target</code></strong>: ordena el inicio después de ese objetivo; no garantiza IP asignada, DNS ni conectividad externa."
"intro":"AppImage es un sistema de archivos que se monta al ejecutarlo. <code>AppRun</code> en su raíz prepara el entorno y lanza <code>flask_server.py</code>:",
"<strong>Paquetes Python incluidos.</strong> Los paquetes Python vienen en la AppImage y se ejecutan con el intérprete Python 3.11 (PVE 8) o 3.13 (PVE 9) del propio host, sin instalar nada en su Python del sistema. La aplicación sigue usando interfaces del kernel y herramientas externas del host.",
"<strong>Clientes de hardware incluidos.</strong> Contiene <code>ipmitool</code>, <code>lm-sensors</code> y <code>upsc</code>. Las lecturas dependen del hardware compatible, acceso a sensores y, para el SAI, un servidor NUT configurado."
"intro":"<code>flask_server.py</code> crea una instancia <code>Flask(__name__)</code> con CORS restringido, registra directamente diez blueprints e inicializa el terminal. La tabla destaca módulos principales; también registra PBS, enlaces del Monitor, auditoría y backups de VM. Las precargas PVE solo se ejecutan en hosts PVE.",
"owns":"Comprobaciones de salud, estado detallado, errores activos y descartados, y silenciamientos. Las rutas protegidas exigen autenticación si está activada."
"intro":"Los datos del host proceden principalmente de bibliotecas, archivos y comandos habituales de administración. Algunos datos del invitado dependen además de QEMU Guest Agent o de comandos ejecutados en el CT:",
"usedFor":"Datos GPU disponibles de utilización, VRAM, temperatura y codificación/decodificación. Los campos dependen del fabricante, herramienta y controlador."
"cacheTitle":"Caché para reducir las consultas al host",
"cacheBody":"Los resultados costosos de <code>smartctl -a</code> y <code>pvesh get</code> se guardan temporalmente en el proceso Flask para reducir consultas repetidas al disco y a la API del clúster. La duración depende de la fuente: segundos para métricas y minutos para SMART."
"contents":"Base SQLite. Tablas: <code>errors</code>, <code>events</code>, <code>disk_registry</code>, <code>disk_observations</code>, <code>user_settings</code>, <code>notification_history</code>, <code>excluded_storages</code>, <code>excluded_interfaces</code>. Modo de registro WAL."
"contents":"Clave maestra de 32 bytes para secretos de notificación ENC2. Usa sal aleatoria por valor, claves derivadas y MAC. Los valores XOR antiguos se admiten para migrarlos."
"contents":"Configuración de acceso: activación, usuario, hash de contraseña PBKDF2-HMAC-SHA256 con sal, secreto TOTP, códigos de recuperación, clave JWT propia de la instalación, metadatos de tokens API y hashes de revocación. Los hashes SHA-256 antiguos migran al iniciar sesión correctamente."
"contents":"Registro de autenticación en texto plano, independiente de Fail2Ban. Si el jail <code>[proxmenux]</code> está instalado y activo, lee este archivo para detectar fallos repetidos de acceso. Sin ese jail, el registro sigue disponible para consulta."
"backupTitle":"Guarda auth.json antes de reinstalar",
"backupBody":"Sustituir AppImage suele conservar <code>/root/.config/proxmenux-monitor/auth.json</code> y <code>/usr/local/share/proxmenux/health_monitor.db</code>. Conserva <code>auth.json</code> con su jwt_secret para mantener validez y metadatos de tokens. La base guarda estado de salud y avisos por separado. Guarda <code>.notification_key</code> con ella para restaurar secretos de canales; restaurar solo la base no restaura la autenticación API."
"intro":"Aproximadamente cada cinco minutos, el proceso de fondo llama a <code>health_monitor.py</code> para comprobar las diez categorías del panel:",
"afterIntro":"Los hallazgos usan <code>error_key</code>, categoría y gravedad estables. Las filas de <code>errors</code> se actualizan en el sitio (<code>last_seen</code>, gravedad, motivo), sin duplicarlas. El envío de avisos tiene además sus propias huellas y tiempos de espera.",
"cycleEnd":"La limpieza puede resolver errores obsoletos con la <em>duración de silenciamiento</em> por categoría y reglas de estado, retirar registros huérfanos de recursos eliminados y borrar <code>events</code> de más de 30 días. Las categorías se explican en <link>Panel → Health Monitor</link>."
"intro":"<code>notification_manager.py</code> coordina el envío: carga canales, gestiona la cola y ofrece una API Python para Flask y Health Monitor, además de una entrada de consola para los hooks <code>.sh</code> de ProxMenux.",
"Los <strong>observadores</strong> generan eventos: <code>JournalWatcher</code> sigue el journal, <code>TaskWatcher</code> consulta tareas Proxmox, <code>ProxmoxHookWatcher</code> recibe hooks de backups, replicación y snapshots, y <code>PollingCollector</code> gestiona fuentes lentas.",
"Las <strong>plantillas</strong> convierten eventos en título y texto. El proveedor de IA configurado (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) puede reformularlos en lenguaje natural. Ambas versiones se guardan en <code>notification_history</code>.",
"Los <strong>canales</strong> envían por Telegram, Discord, correo, Gotify, Pushover y Apprise, entre otros. Las implementaciones en <code>notification_channels.py</code> comparten <code>create_channel()</code> / <code>send()</code>.",
"<strong>Cifrado.</strong> Los ajustes sensibles (<code>telegram.bot_token</code>, <code>discord.webhook_url</code>, <code>pushover.user_key</code>, <code>pushover.api_token</code>, <code>ai_api_key_*</code>, <code>email.password</code>) se cifran con la clave de <code>.notification_key</code> antes de guardarse en la base de datos y se muestran enmascarados en la interfaz."
"linksFooter":"Los controles por evento, ajustes por canal e IA se explican en <notifLink>Ajustes → Notificaciones</notifLink> y <aiLink>Ajustes → Asistente de IA</aiLink>."
"<strong>Modo HTTPS / WSS:</strong> usa <code>gevent.pywsgi.WSGIServer</code> con su gestor predeterminado; <code>flask-sock</code> atiende las conexiones WebSocket sobre TLS."
"outro":"Los procesos del terminal heredan <code>User=root</code>. Abrir WebSocket exige un ticket breve y de un solo uso, obtenido del endpoint de tickets autenticado con permisos administrativos.",
"proxyNote":"Si usas un proxy inverso, permite el tráfico WebSocket y sus cabeceras <code>Upgrade</code> y <code>Connection</code>. El terminal necesita ese reenvío."
"<strong>Elección de IP.</strong> El control <code>before_request</code> y el registro de acceso solo confían en <code>X-Forwarded-For</code> y después <code>X-Real-IP</code> con PROXMENUX_TRUST_PROXY=1. Si no, usan <code>request.remote_addr</code>. Las cabeceras reenviadas no se aceptan automáticamente.",
"<strong>Fail2Ban opcional en la aplicación.</strong> Una conexión por proxy puede mostrar la IP del proxy como origen TCP. Si se obtiene la IP fiable del cliente y está activo el jail <code>proxmenux</code>, Flask rechaza las IP bloqueadas con HTTP 403. La lista se guarda 30 segundos y se renueva al procesar peticiones tras caducar, sin un temporizador de consultas."
"calloutBody":"Fail2Ban <strong>no</strong> viene incluido ni se instala automáticamente. Puede instalarse desde Seguridad del Monitor o <link>Seguridad → Fail2Ban</link> en ProxMenux Scripts. Si faltan <code>fail2ban-client</code> o el jail <code>proxmenux</code>, este control no bloquea peticiones. La autenticación sigue la política configurada.",
"outro":"Los ejemplos de proxy inverso Nginx/Caddy/Traefik y la guía del jail están en <accessLink>Acceso y autenticación</accessLink> y <fail2banLink>Seguridad → Fail2Ban</fail2banLink>."