{
"meta": {
"title": "Architettura di ProxMenux Monitor — AppImage, Flask, SQLite, WebSocket | ProxMenux",
"description": "Struttura di ProxMenux Monitor: AppImage, blueprint Flask, attività in background, dati da psutil, pvesh, smartctl e journalctl, archiviazione SQLite, terminale WebSocket, provider IA, canali di notifica, proxy inverso e Fail2Ban opzionale.",
"ogTitle": "ProxMenux Monitor Architettura",
"ogDescription": "Dentro ProxMenux Monitor: AppImage, blueprint Flask, attività in background, SQLite, WebSocket, provider IA e canali di notifica.",
"twitterTitle": "ProxMenux Monitor Architettura",
"twitterDescription": "AppImage, Flask, SQLite, WebSocket, provider IA e canali di notifica: dentro Monitor."
},
"header": {
"title": "Architettura",
"description": "Come viene distribuito ProxMenux Monitor, cosa contiene l’AppImage e come le richieste del browser passano da Flask agli strumenti dell’host e all’archivio SQLite.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Un processo, molte responsabilità",
"body": "Un processo Python ascolta su TCP 8008. Serve la versione statica Next.js, espone l’API REST, gestisce il terminale WebSocket, esegue Health Monitor e invia notifiche. Non richiede un server web separato, un broker di messaggi o un database esterno."
},
"requestFlow": {
"heading": "Percorso di una richiesta",
"intro": "Una richiesta di dati tipica segue questo percorso; le preferenze del browser possono essere gestite localmente:",
"diagramCaption": "Le rotte protette verificano JWT con autenticazione attiva. Rotte principali e blueprint restituiscono dati in cache o appena raccolti. Il controllo Fail2Ban opzionale consulta la lista dei blocchi in cache. Le intestazioni IP inoltrate sono attendibili solo con PROXMENUX_TRUST_PROXY=1; altrimenti usa l’indirizzo della connessione. Lo stato persistente include SQLite e file JSON come auth.json.",
"diagramArrowLabel": "HTTP / WS",
"nodes": {
"clientLabel": "Cliente",
"clientDetail": "Browser o PWA\n+ proxy opzionale\nNginx / Caddy /\nTraefik",
"flaskLabel": "Flask :8008",
"flaskDetail": "Blueprint\nMiddleware JWT\nControllo Fail2Ban\n(se installato)",
"hostLabel": "Strumenti dell’host",
"hostDetail": "psutil\npvesh\nsmartctl\njournalctl",
"stateLabel": "Stato locale",
"stateDetail": "SQLite DB\n+ auth.json"
},
"threadsIntro": "Il processo esegue anche thread in background. Questi esempi raccolgono dati, aggiornano cache e SQLite e inviano notifiche. Esistono altre attività; l’invio dipende dalla relativa attivazione:",
"headerThread": "Thread",
"headerCadence": "Cadenza",
"headerJob": "Attività pianificata",
"rows": [
{
"thread": "_temperature_collector_loop",
"cadence": "60 s",
"job": "Salva temperatura CPU e campioni di latenza nel database storico, così i grafici hanno dati anche senza browser connessi."
},
{
"thread": "_health_collector_loop",
"cadence": "5 min",
"job": "Esegue il ciclo Health Monitor delle dieci categorie, salva errori e osservazioni sui dischi, gestisce gli avvisi ignorati e passa i nuovi eventi al motore di notifica."
},
{
"thread": "_vital_signs_sampler",
"cadence": "CPU 5 s; temperatura 15 s; memoria 30 s",
"job": "Campiona CPU, memoria e temperatura CPU per gli indicatori e il rilevamento di condizioni prolungate, indipendentemente dal controllo generale di cinque minuti."
},
{
"thread": "notification_manager.start()",
"cadence": "Basato su eventi",
"job": "Avvia gli osservatori di journal, attività e hook (JournalWatcher, TaskWatcher, ProxmoxHookWatcher) e invia ai canali configurati, con riformulazione IA opzionale."
}
]
},
"systemd": {
"heading": "Unità systemd",
"intro": "L’installer crea l’unità /etc/systemd/system/proxmenux-monitor.service. Configurazione predefinita:",
"items": [
"User=root: il servizio usa privilegi root per SMART, pvesh e gestione ZFS. I processi del terminale web ereditano questi permessi.",
"Restart=on-failure con attesa di dieci secondi: il servizio riparte automaticamente dopo un’uscita con errore.",
"After=network.target: ordina l’avvio dopo quel target; non garantisce IP assegnato, DNS o connettività esterna."
],
"inspectTitle": "Esaminare l’unità attuale"
},
"appimage": {
"heading": "Cosa contiene l’AppImage",
"intro": "L’AppImage contiene un filesystem montato all’esecuzione. AppRun alla radice prepara l’ambiente e avvia flask_server.py:",
"consequencesIntro": "Due conseguenze di questo layout:",
"consequences": [
"Pacchetti Python inclusi. I pacchetti Python sono distribuiti nell’AppImage e girano sull’interprete Python dell’host stesso, 3.11 (PVE 8) o 3.13 (PVE 9), senza installare nulla nel Python di sistema dell’host. L’app usa comunque interfacce del kernel e strumenti esterni dell’host.",
"Client hardware inclusi. Sono presenti ipmitool, lm-sensors e upsc. Le letture richiedono hardware compatibile, accesso ai sensori e, per l’UPS, un server NUT configurato."
]
},
"flask": {
"heading": "Struttura dell’applicazione Flask",
"intro": "flask_server.py crea un’istanza Flask(__name__) con origini CORS limitate, registra direttamente dieci blueprint e inizializza le rotte del terminale. La tabella mostra i moduli principali; sono registrati anche i blueprint di PBS, collegamenti del Monitor, audit e backup VM. I precaricamenti specifici di PVE si eseguono solo sugli host PVE.",
"headerBlueprint": "Blueprint / modulo",
"headerPrefix": "Prefisso delle rotte",
"headerOwns": "Responsabilità",
"rows": [
{
"blueprint": "flask_server.py",
"prefix": [
"/api/system",
"/api/storage",
"/api/network",
"/api/vms",
"/api/hardware",
"/api/logs",
"/api/prometheus"
],
"owns": "Endpoint principali, web statico e controllo Fail2Ban opzionale se il jail proxmenux è presente sull’host."
},
{
"blueprint": "flask_auth_routes.py",
"prefix": [
"/api/auth/*"
],
"owns": "Accesso, emissione JWT, configurazione e verifica TOTP, cambio password e token API."
},
{
"blueprint": "flask_health_routes.py",
"prefix": [
"/api/health/*"
],
"owns": "Controlli di stato, dettagli, errori attivi e ignorati e impostazioni di silenziamento. Le rotte protette richiedono autenticazione quando attiva."
},
{
"blueprint": "flask_terminal_routes.py",
"prefix": [
"/api/terminal/* + WS"
],
"owns": "Assegna un PTY per sessione e lo collega via WebSocket a xterm.js nel browser."
},
{
"blueprint": "flask_notification_routes.py",
"prefix": [
"/api/notifications/*"
],
"owns": "Creazione, lettura, modifica e rimozione dei canali; prove, IA, cronologia e invii manuali."
},
{
"blueprint": "flask_security_routes.py",
"prefix": [
"/api/security/*"
],
"owns": "Errori di accesso e, con Fail2Ban installato, stato del jail, blocchi e sblocco manuale."
},
{
"blueprint": "flask_proxmenux_routes.py",
"prefix": [
"/api/proxmenux/*"
],
"owns": "Legge le ottimizzazioni ProxMenux registrate sull’host."
},
{
"blueprint": "flask_oci_routes.py",
"prefix": [
"/api/oci/*"
],
"owns": "Funzioni di distribuzione di applicazioni OCI e container su Proxmox VE 9.1+."
}
],
"endpointsLink": "Gli endpoint di integrazione e i loro formati sono descritti in Riferimento API."
},
"dataSources": {
"heading": "Fonti dati",
"intro": "I dati dell’host provengono soprattutto da librerie standard, file e comandi amministrativi. Alcuni dati degli ospiti dipendono anche da QEMU Guest Agent o da comandi nel CT:",
"headerSource": "Fonte",
"headerUsedFor": "Usato per",
"rows": [
{
"source": "psutil",
"usedFor": "Carico CPU, memoria, swap, utilizzo dei montaggi, contatori di rete e processi."
},
{
"source": "pvesh / qm / pct",
"usedFor": "Informazioni del nodo Proxmox, inventario e configurazione VM/CT, storage e cronologia delle attività."
},
{
"source": "smartctl",
"usedFor": "Attributi SATA/NVMe, stato SMART, usura, vita utile, modello e numero di serie."
},
{
"source": "zpool / zfs",
"usedFor": "Stato del pool (ONLINE / DEGRADED / FAULTED / UNAVAIL), avanzamento dello scrub e utilizzo dei dataset."
},
{
"source": "journalctl",
"usedFor": "Log di sistema, processi terminati per OOM, errori ATA/NVMe/dm, sicurezza e unità di servizio personalizzate."
},
{
"source": "ip / iproute2",
"usedFor": "Interfacce, indirizzi, bridge, bond e dispositivi gestiti da OVS."
},
{
"source": "nvidia-smi · intel_gpu_top",
"usedFor": "Dati GPU disponibili su utilizzo, VRAM, temperatura e codifica/decodifica. I campi dipendono da produttore, strumento e driver."
},
{
"source": "lspci · lscpu · dmidecode",
"usedFor": "Topologia PCIe, modello e topologia CPU, scheda madre e BIOS."
},
{
"source": "ipmitool · sensors",
"usedFor": "Sensori fuori banda, ventole e temperature della scheda madre, se l’hardware li supporta."
},
{
"source": "upsc (NUT)",
"usedFor": "Stato batteria, carico e autonomia UPS con un server NUT configurato."
}
],
"cacheTitle": "Cache per ridurre le richieste all’host",
"cacheBody": "I risultati costosi di smartctl -a e pvesh get sono conservati temporaneamente nel processo Flask per ridurre le richieste a dischi e API del cluster. La durata varia: secondi per le metriche e minuti per SMART."
},
"persistence": {
"heading": "Persistenza",
"intro": "Diversi file di stato hanno contenuti e requisiti di accesso differenti:",
"headerPath": "Path",
"headerOwner": "Proprietario",
"headerContents": "Contenuto",
"rows": [
{
"path": "/usr/local/share/proxmenux/health_monitor.db",
"owner": "root:root",
"contents": "Database SQLite. Tabelle: errors, events, disk_registry, disk_observations, user_settings, notification_history, excluded_storages, excluded_interfaces. Modalità journal WAL."
},
{
"path": "/usr/local/share/proxmenux/.notification_key",
"owner": "root 0600",
"contents": "Chiave principale di 32 byte per i segreti di notifica ENC2. Usa sale casuale per valore, chiavi derivate e MAC. I vecchi valori XOR sono supportati per la migrazione."
},
{
"path": "/root/.config/proxmenux-monitor/auth.json",
"owner": "root:root",
"contents": "Configurazione di accesso: attivazione, utente, hash password PBKDF2-HMAC-SHA256 con salt, segreto TOTP, codici di recupero, chiave JWT dell’installazione, metadati dei token API e hash di revoca. I vecchi hash SHA-256 vengono migrati all’accesso riuscito."
},
{
"path": "/var/log/proxmenux-auth.log",
"owner": "root:root",
"contents": "Log di autenticazione in testo semplice, indipendente da Fail2Ban. Se il jail [proxmenux] è installato e attivo, legge il file per rilevare errori di accesso ripetuti. Senza quel jail, il log resta consultabile."
}
],
"backupTitle": "Salvare auth.json prima della reinstallazione",
"backupBody": "Sostituire l’AppImage normalmente conserva /root/.config/proxmenux-monitor/auth.json e /usr/local/share/proxmenux/health_monitor.db. Conserva auth.json con jwt_secret per mantenere validità e metadati dei token. Il database conserva separatamente stato e notifiche. Salva .notification_key insieme per ripristinare i segreti dei canali; il solo database non ripristina l’autenticazione API."
},
"health": {
"heading": "Ciclo Health Monitor",
"intro": "Circa ogni cinque minuti, il processo in background invoca health_monitor.py per i controlli delle dieci categorie del pannello:",
"items": [
"Servizi PVE critici (pveproxy, pvedaemon, pvestatd, pve-cluster).",
"Storage Proxmox: pvesh get /storage e disponibilità di ciascuno.",
"Dischi e filesystem: SMART, errori I/O in dmesg, stato ZFS e capacità dei montaggi.",
"VM e CT: errori di avvio, arresti anomali, errori QMP e problemi di spegnimento.",
"Rete: stato di bridge e bond, collegamenti e latenza verso il gateway.",
"Aggiornamenti: pacchetti in attesa e patch di sicurezza.",
"Log: schemi persistenti, picchi e sequenze a cascata nel journal di sistema.",
"Memoria: interventi dell’OOM killer e pressione RAM prolungata.",
"CPU: utilizzo e temperatura della CPU rispetto alle soglie configurabili; i sensori disponibili dipendono dall’hardware.",
"Sicurezza: errori di accesso, blocchi e stato del jail Fail2Ban."
],
"afterIntro": "I risultati usano error_key, categoria e gravità stabili. I record esistenti in errors vengono aggiornati sul posto (last_seen, gravità, motivo), senza duplicarli. L’invio delle notifiche ha anche regole proprie di impronta e intervallo.",
"cycleEnd": "La pulizia può risolvere errori obsoleti con la durata del silenziamento per categoria e regole di stato, rimuovere voci orfane di risorse eliminate e cancellare events oltre 30 giorni. Le categorie sono in Pannello → Health Monitor."
},
"notifications": {
"heading": "Motore di notifica",
"intro": "notification_manager.py coordina l’invio: carica i canali, gestisce la coda e offre un’API Python per Flask e Health Monitor e un ingresso CLI per gli hook .sh di ProxMenux.",
"items": [
"Gli osservatori generano eventi: JournalWatcher segue il journal, TaskWatcher consulta le attività Proxmox, ProxmoxHookWatcher riceve hook di backup, replica e snapshot e PollingCollector gestisce fonti lente.",
"I modelli trasformano eventi in titolo e testo. Il provider IA configurato (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) può riformularli in linguaggio naturale. Entrambe le versioni sono salvate in notification_history.",
"I canali inviano tramite servizi come Telegram, Discord, email, Gotify, Pushover e Apprise. Le implementazioni in notification_channels.py condividono create_channel() / send().",
"Cifratura. Le impostazioni sensibili (telegram.bot_token, discord.webhook_url, pushover.user_key, pushover.api_token, ai_api_key_*, email.password) vengono cifrate con la chiave di .notification_key prima del salvataggio e mascherate nell’interfaccia."
],
"linksFooter": "Controlli per evento, opzioni dei canali e IA sono descritti in Impostazioni → Notifiche e Impostazioni → Assistente IA."
},
"websocket": {
"heading": "Terminale WebSocket",
"intro": "La scheda Terminale collega un client leggero xterm.js a un PTY del server via WebSocket. Esistono due modalità:",
"items": [
"Modalità HTTP, predefinita: il server Flask integrato con flask-sock gestisce il passaggio al protocollo WebSocket.",
"Modalità HTTPS / WSS: il server TLS usa gevent.pywsgi.WSGIServer con il suo gestore predefinito; flask-sock gestisce le connessioni WebSocket su TLS."
],
"outro": "I processi figli del terminale ereditano User=root dal servizio. Aprire un WebSocket richiede un ticket breve monouso ottenuto dall’endpoint autenticato dei ticket del terminale con permessi amministrativi.",
"proxyNote": "Con un proxy inverso, abilita WebSocket e le intestazioni Upgrade e Connection. Il terminale richiede questo inoltro."
},
"proxy": {
"heading": "Proxy inverso e Fail2Ban",
"intro": "La scelta dell’IP client e il blocco applicativo opzionale dipendono da queste impostazioni e componenti:",
"items": [
"Scelta dell’IP client. Il controllo before_request e il log di accesso si fidano di X-Forwarded-For, poi X-Real-IP, solo con PROXMENUX_TRUST_PROXY=1. Altrimenti usano request.remote_addr. Le intestazioni inoltrate non sono accettate automaticamente.",
"Fail2Ban applicativo opzionale. Una connessione proxy può mostrare l’IP del proxy come origine TCP. Con l’IP client attendibile e il jail proxmenux attivo, Flask rifiuta gli IP bloccati con HTTP 403. La lista resta in cache per 30 secondi e si aggiorna alle richieste dopo la scadenza, senza timer dedicato."
],
"calloutTitle": "Fail2Ban non è incluso",
"calloutBody": "Fail2Ban non è incluso né installato automaticamente. Si può installare da Sicurezza di Monitor o Sicurezza → Fail2Ban in ProxMenux Scripts. Senza fail2ban-client o il jail proxmenux, questo controllo non blocca richieste. Resta valida la politica di autenticazione configurata.",
"outro": "Esempi Nginx/Caddy/Traefik e guida del jail sono in Accesso e autenticazione e Sicurezza → Fail2Ban."
},
"whereNext": {
"heading": "Come proseguire",
"items": [
{
"label": "Accesso e autenticazione",
"href": "/docs/monitor/access-auth",
"tail": " — primo avvio, password e TOTP 2FA, esempi di proxy inverso e jail Fail2Ban."
},
{
"label": "Riferimento API",
"href": "/docs/monitor/api",
"tail": " — endpoint di integrazione, gestione token e convenzioni di autenticazione."
},
{
"label": "Impostazioni → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — controllo del servizio e verifica dello stato nel menu testuale ProxMenux."
}
]
}
}