{ "meta": { "title": "Architektur von ProxMenux Monitor — AppImage, Flask, SQLite, WebSocket | ProxMenux", "description": "Aufbau von ProxMenux Monitor: AppImage-Struktur, Flask-Blueprints, Hintergrundaufgaben, Daten aus psutil, pvesh, smartctl und journalctl, SQLite-Speicherung, WebSocket-Terminal, KI-Anbieter, Benachrichtigungskanäle, Reverse-Proxy und optionales Fail2Ban.", "ogTitle": "ProxMenux Monitor Architektur", "ogDescription": "ProxMenux Monitor intern: AppImage, Flask-Blueprints, Hintergrundaufgaben, SQLite, WebSocket, KI-Anbieter und Benachrichtigungskanäle.", "twitterTitle": "ProxMenux Monitor Architektur", "twitterDescription": "AppImage, Flask, SQLite, WebSocket, KI-Anbieter und Benachrichtigungskanäle — innerhalb des Monitors." }, "header": { "title": "Architektur", "description": "Wie ProxMenux Monitor ausgeliefert wird, was das AppImage enthält und wie Browseranfragen über Flask zu Host-Werkzeugen und SQLite gelangen.", "section": "ProxMenux Monitor" }, "intro": { "title": "Ein Prozess, viele Verantwortlichkeiten", "body": "Ein Python-Prozess lauscht auf TCP 8008. Er liefert den statischen Next.js-Build aus, stellt die REST-API bereit, verwaltet das WebSocket-Terminal, führt den Health Monitor aus und versendet Meldungen. Ein separater Webserver, Nachrichtenbroker oder externer Datenbankserver ist nicht erforderlich." }, "requestFlow": { "heading": "Ablauf einer Anfrage", "intro": "Eine typische Datenanfrage folgt diesem Weg; reine Browsereinstellungen können lokal bleiben:", "diagramCaption": "Geschützte Routen prüfen JWT bei aktiver Authentifizierung. Kernrouten und Blueprints liefern zwischengespeicherte oder neu erfasste Host-Daten. Der optionale Fail2Ban-Hook prüft seine zwischengespeicherte Sperrliste. Weitergeleitete IP-Header gelten nur mit PROXMENUX_TRUST_PROXY=1; sonst zählt die Gegenstellenadresse. Dauerhafter Zustand liegt in SQLite und JSON-Dateien wie auth.json.", "diagramArrowLabel": "HTTP / WS", "nodes": { "clientLabel": "Client", "clientDetail": "Browser oder PWA\n+ optionaler Proxy\nNginx / Caddy /\nTraefik", "flaskLabel": "Flask :8008", "flaskDetail": "Blueprints\nJWT-Middleware\nFail2Ban-Hook\n(falls installiert)", "hostLabel": "Host-Tools", "hostDetail": "psutil\npvesh\nsmartctl\njournalctl", "stateLabel": "Lokaler Zustand", "stateDetail": "SQLite DB\n+ auth.json" }, "threadsIntro": "Der Prozess führt auch Hintergrundthreads aus. Diese Beispiele erfassen Daten, aktualisieren Caches und SQLite und versenden Meldungen. Weitere Aufgaben existieren; der Versand hängt von seiner Aktivierung ab:", "headerThread": "Thread", "headerCadence": "Intervall", "headerJob": "Auftrag", "rows": [ { "thread": "_temperature_collector_loop", "cadence": "60 s", "job": "Speichert CPU-Temperatur und Latenzproben in der Verlaufsdatenbank, damit Diagramme auch ohne verbundenen Browser Daten haben." }, { "thread": "_health_collector_loop", "cadence": "5 min", "job": "Führt den Health-Monitor-Zyklus mit zehn Kategorien aus, speichert Fehler und Datenträgerbeobachtungen, berücksichtigt Unterdrückungen und übergibt neue Ereignisse an den Benachrichtigungsdienst." }, { "thread": "_vital_signs_sampler", "cadence": "CPU 5 s; Temperatur 15 s; RAM 30 s", "job": "Erfasst CPU-Auslastung, RAM und CPU-Temperatur für aktuelle Anzeigen und anhaltende Zustände, unabhängig von der fünfminütigen Gesamtprüfung." }, { "thread": "notification_manager.start()", "cadence": "Ereignisgesteuert", "job": "Startet Beobachter für Journal, Tasks und Hooks (JournalWatcher, TaskWatcher, ProxmoxHookWatcher) und sendet an eingerichtete Kanäle, optional mit KI-Umformulierung." } ] }, "systemd": { "heading": "systemd-Einheit", "intro": "Der Installer erstellt die Unit /etc/systemd/system/proxmenux-monitor.service. Standardkonfiguration:", "items": [ "User=root: Der Dienst verwendet Root-Rechte für Host-Operationen wie SMART, pvesh und ZFS-Verwaltung. Die Webterminal-Prozesse erben diese Rechte.", "Restart=on-failure mit zehn Sekunden Wartezeit: Nach fehlerhaftem Ende startet der Dienst automatisch neu.", "After=network.target: ordnet den Start nach diesem Ziel ein; garantiert keine IP-Adresse, DNS oder externe Verbindung." ], "inspectTitle": "Aktuelle Unit prüfen" }, "appimage": { "heading": "Was das AppImage enthält", "intro": "Das AppImage enthält ein beim Start eingehängtes Dateisystem. AppRun im Wurzelverzeichnis bereitet die Umgebung vor und startet flask_server.py:", "consequencesIntro": "Zwei Konsequenzen dieses Layouts:", "consequences": [ "Mitgelieferte Python-Pakete. Die Python-Pakete liegen im AppImage und laufen mit dem Python-Interpreter des Hosts, 3.11 (PVE 8) oder 3.13 (PVE 9), ohne dass etwas in das System-Python des Hosts installiert wird. Die Anwendung nutzt weiterhin Kernel-Schnittstellen des Hosts und externe Host-Werkzeuge.", "Hardware-Clients sind enthalten. Mitgeliefert werden ipmitool, lm-sensors und upsc. Messwerte erfordern unterstützte Hardware, Sensorzugriff und für USV-Daten einen eingerichteten NUT-Server." ] }, "flask": { "heading": "Struktur der Flask-Anwendung", "intro": "flask_server.py erstellt eine Flask(__name__)-Instanz mit eingeschränkten CORS-Ursprüngen, registriert zehn Blueprints direkt und initialisiert Terminalrouten. Die Tabelle zeigt die Hauptmodule; die Blueprints für PBS, Monitor-Links, Audit und VM-Sicherung sind ebenfalls registriert. PVE-spezifische Vorwärmer laufen nur auf PVE-Hosts.", "headerBlueprint": "Blueprint / Modul", "headerPrefix": "Routenpräfix", "headerOwns": "Zuständigkeit", "rows": [ { "blueprint": "flask_server.py", "prefix": [ "/api/system", "/api/storage", "/api/network", "/api/vms", "/api/hardware", "/api/logs", "/api/prometheus" ], "owns": "Kernendpunkte, statische Weboberfläche und optionale Fail2Ban-Prüfung bei vorhandenem Jail proxmenux auf dem Host." }, { "blueprint": "flask_auth_routes.py", "prefix": [ "/api/auth/*" ], "owns": "Anmeldung, JWT-Ausgabe, TOTP-Einrichtung und -Prüfung, Passwortänderung und API-Token." }, { "blueprint": "flask_health_routes.py", "prefix": [ "/api/health/*" ], "owns": "Zustandsprüfungen, Detailstatus, aktive und unterdrückte Fehler sowie Unterdrückungseinstellungen. Geschützte Routen verlangen Authentifizierung, wenn aktiviert." }, { "blueprint": "flask_terminal_routes.py", "prefix": [ "/api/terminal/* + WS" ], "owns": "Stellt je Sitzung ein PTY bereit und verbindet es über WebSocket mit xterm.js im Browser." }, { "blueprint": "flask_notification_routes.py", "prefix": [ "/api/notifications/*" ], "owns": "Kanäle anlegen, lesen, ändern und löschen; Testversand, KI, Verlauf und manuelle Meldungen." }, { "blueprint": "flask_security_routes.py", "prefix": [ "/api/security/*" ], "owns": "Anmeldefehler und bei installiertem Fail2Ban Jail-Zustand, Sperrereignisse und manuelles Entsperren." }, { "blueprint": "flask_proxmenux_routes.py", "prefix": [ "/api/proxmenux/*" ], "owns": "Liest die im Host-Bestand registrierten ProxMenux-Optimierungen." }, { "blueprint": "flask_oci_routes.py", "prefix": [ "/api/oci/*" ], "owns": "Hilfen zur Bereitstellung von OCI- und Container-Apps auf Proxmox VE 9.1+." } ], "endpointsLink": "Integrationsendpunkte und ihre Formate erklärt API-Referenz." }, "dataSources": { "heading": "Datenquellen", "intro": "Host-Daten stammen überwiegend aus Standardbibliotheken, Dateien und Verwaltungsbefehlen. Einige Gastdaten benötigen zusätzlich den QEMU Guest Agent oder Befehle innerhalb eines CT:", "headerSource": "Quelle", "headerUsedFor": "Verwendet für", "rows": [ { "source": "psutil", "usedFor": "CPU-Last, RAM, Swap, Belegung von Einhängepunkten, Netzwerkzähler und Prozesse." }, { "source": "pvesh / qm / pct", "usedFor": "Proxmox-Knoteninformationen, VM-/CT-Bestand und Konfiguration, Speicher sowie Task-Verlauf." }, { "source": "smartctl", "usedFor": "SATA-/NVMe-Attribute, SMART-Zustand, Verschleiß, Lebensdauer, Modell und Seriennummer." }, { "source": "zpool / zfs", "usedFor": "Poolzustand (ONLINE / DEGRADED / FAULTED / UNAVAIL), Scrub-Fortschritt und Dataset-Belegung." }, { "source": "journalctl", "usedFor": "Systemprotokolle, OOM-Abbrüche, ATA-/NVMe-/dm-Fehler, Sicherheitsereignisse und eigene Service-Units." }, { "source": "ip / iproute2", "usedFor": "Schnittstellen, Adressen, Bridges, Bonds und OVS-verwaltete Geräte." }, { "source": "nvidia-smi · intel_gpu_top", "usedFor": "Verfügbare GPU-Daten zu Auslastung, VRAM, Temperatur und Encoder/Decoder. Felder hängen von Hersteller, Werkzeug und Treiber ab." }, { "source": "lspci · lscpu · dmidecode", "usedFor": "PCIe-Topologie, CPU-Modell und -Topologie sowie Mainboard- und BIOS-Daten." }, { "source": "ipmitool · sensors", "usedFor": "Out-of-Band-Sensoren, Lüfterdrehzahlen und Mainboard-Temperaturen bei unterstützter Hardware." }, { "source": "upsc (NUT)", "usedFor": "Batteriezustand, Last und Restlaufzeit der USV bei eingerichtetem NUT-Server." } ], "cacheTitle": "Caches reduzieren Host-Abfragen", "cacheBody": "Aufwendige Ergebnisse von smartctl -a und pvesh get werden im Flask-Prozess zeitweise gespeichert, um Datenträger und Cluster-API seltener abzufragen. Die Dauer hängt von der Quelle ab: Sekunden für aktuelle Metriken, Minuten für SMART." }, "persistence": { "heading": "Persistenz", "intro": "Mehrere Zustandsdateien haben unterschiedliche Inhalte und Zugriffsanforderungen:", "headerPath": "Path", "headerOwner": "Eigentümer", "headerContents": "Inhalt", "rows": [ { "path": "/usr/local/share/proxmenux/health_monitor.db", "owner": "root:root", "contents": "SQLite-Datenbank. Tabellen: errors, events, disk_registry, disk_observations, user_settings, notification_history, excluded_storages, excluded_interfaces. WAL-Journalmodus." }, { "path": "/usr/local/share/proxmenux/.notification_key", "owner": "root 0600", "contents": "32-Byte-Hauptschlüssel für Benachrichtigungsgeheimnisse im ENC2-Format. Verwendet zufälliges Salt je Wert, abgeleitete Schlüssel und MAC. Alte XOR-Werte werden zur Migration unterstützt." }, { "path": "/root/.config/proxmenux-monitor/auth.json", "owner": "root:root", "contents": "Authentifizierungskonfiguration: Aktivierung, Benutzername, gesalzener PBKDF2-HMAC-SHA256-Passworthash, TOTP-Geheimnis, Wiederherstellungscodes, installationsbezogener JWT-Schlüssel, API-Token-Metadaten und Widerrufshashes. Alte SHA-256-Hashes werden nach erfolgreicher Anmeldung migriert." }, { "path": "/var/log/proxmenux-auth.log", "owner": "root:root", "contents": "Klartextprotokoll der Authentifizierung, unabhängig von Fail2Ban. Ist das Jail [proxmenux] installiert und aktiv, liest es das Protokoll zur Erkennung wiederholter Anmeldefehler. Ohne Jail bleibt das Protokoll zur Prüfung verfügbar." } ], "backupTitle": "auth.json vor der Neuinstallation sichern", "backupBody": "Ein AppImage-Austausch bewahrt normalerweise /root/.config/proxmenux-monitor/auth.json und /usr/local/share/proxmenux/health_monitor.db. Bewahren Sie auth.json samt jwt_secret für gültige Token und Metadaten. Die Datenbank enthält unabhängig Zustands- und Meldungsdaten. Sichern Sie .notification_key mit ihr für verschlüsselte Kanaleinstellungen; die Datenbank allein stellt API-Authentifizierung nicht wieder her." }, "health": { "heading": "Health-Monitor-Zyklus", "intro": "Etwa alle fünf Minuten ruft der Hintergrundkollektor health_monitor.py für die Prüfungen der zehn Dashboard-Kategorien auf:", "items": [ "Kritische PVE-Dienste (pveproxy, pvedaemon, pvestatd, pve-cluster).", "Proxmox-Speicher: pvesh get /storage und Verfügbarkeit je Speicher.", "Datenträger und Dateisysteme: SMART, E/A-Fehler in dmesg, ZFS-Zustand und Belegung von Einhängepunkten.", "VMs und CTs: Startfehler, Abstürze, QMP-Fehler und Probleme beim Herunterfahren.", "Netzwerk: Bridge- und Bond-Zustand, Verbindungsstatus und Gateway-Latenz.", "Updates: ausstehende Paketaktualisierungen und Sicherheitspatches.", "Protokolle: anhaltende Muster, Spitzen und Kaskaden im Systemjournal.", "Arbeitsspeicher: OOM-Killer-Aktivität und anhaltender Speicherdruck.", "CPU: Auslastung und CPU-Temperatur im Vergleich zu den konfigurierbaren Schwellen; verfügbare Sensoren hängen von der Hardware ab.", "Sicherheit: Anmeldefehler, Sperrereignisse und Fail2Ban-Jail-Zustand." ], "afterIntro": "Befunde verwenden stabile error_key, Kategorie und Schweregrad. Vorhandene Einträge in errors werden an Ort und Stelle aktualisiert (last_seen, Schweregrad, Grund), statt dupliziert zu werden. Der Benachrichtigungsversand hat zudem eigene Regeln für Fingerabdrücke und Wartezeiten.", "cycleEnd": "Die Bereinigung kann alte Fehler anhand der Unterdrückungsdauer je Kategorie und Zustandsregeln auflösen, verwaiste Einträge entfernter Ressourcen entfernen und events über 30 Tage löschen. Kategorien erklärt Dashboard → Health Monitor." }, "notifications": { "heading": "Benachrichtigungsmotor", "intro": "notification_manager.py koordiniert den Versand: lädt Kanäle, verwaltet die Warteschlange und bietet eine Python-API für Flask und Health Monitor sowie einen CLI-Einstieg für ProxMenux-Hooks in .sh.", "items": [ "Beobachter erzeugen Ereignisse: JournalWatcher verfolgt das Journal, TaskWatcher fragt Proxmox-Tasks ab, ProxmoxHookWatcher empfängt Sicherungs-, Replikations- und Snapshot-Hooks und PollingCollector verarbeitet langsame Quellen.", "Vorlagen erzeugen Titel und Nachricht aus Ereignissen. Der konfigurierte KI-Anbieter (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) kann sie verständlich umformulieren. Beide Fassungen werden in notification_history gespeichert.", "Kanäle versenden über Dienste wie Telegram, Discord, E-Mail, Gotify, Pushover und Apprise. Implementierungen in notification_channels.py teilen die Schnittstelle create_channel() / send().", "Verschlüsselung. Vertrauliche Einstellungen (telegram.bot_token, discord.webhook_url, pushover.user_key, pushover.api_token, ai_api_key_*, email.password) werden vor dem Speichern mit dem Schlüssel aus .notification_key verschlüsselt und in der Oberfläche maskiert." ], "linksFooter": "Ereignisschalter, kanalspezifische Einstellungen und KI erklären Einstellungen → Benachrichtigungen und Einstellungen → KI-Assistent." }, "websocket": { "heading": "WebSocket Terminal", "intro": "Die Registerkarte Terminal verbindet einen schlanken xterm.js-Client über WebSocket mit einem serverseitigen PTY. Es gibt zwei Betriebsarten:", "items": [ "HTTP-Modus, Standard: Der integrierte Flask-Server verarbeitet mit flask-sock WebSocket-Upgrade-Anfragen.", "HTTPS-/WSS-Modus: Der TLS-Server verwendet gevent.pywsgi.WSGIServer mit dessen Standard-Handler; flask-sock verarbeitet WebSocket-Verbindungen über TLS." ], "outro": "Terminal-Kindprozesse erben User=root vom Dienst. Das Öffnen eines WebSockets erfordert ein kurzlebiges Einmalticket vom authentifizierten Terminal-Ticket-Endpunkt mit Verwaltungsrechten.", "proxyNote": "Beim Reverse-Proxy muss WebSocket-Weiterleitung mit den Headern Upgrade und Connection funktionieren. Das Terminal benötigt diese Weiterleitung." }, "proxy": { "heading": "Reverse-Proxy und Fail2Ban", "intro": "Client-IP-Auswahl und optionale Sperrung in der Anwendung hängen von diesen Einstellungen und Komponenten ab:", "items": [ "Client-IP-Auswahl. Die Sperrprüfung in before_request und das Auth-Protokoll vertrauen X-Forwarded-For, danach X-Real-IP, nur mit PROXMENUX_TRUST_PROXY=1. Sonst gilt request.remote_addr. Weitergeleitete Header werden nicht automatisch akzeptiert.", "Optionales Fail2Ban in der Anwendung. Bei Proxyverbindungen kann die Proxy-IP als TCP-Gegenstelle erscheinen. Sind die vertrauenswürdige Client-IP und das aktive Jail proxmenux verfügbar, weist Flask gesperrte IPs mit HTTP 403 zurück. Die Liste wird 30 Sekunden gespeichert und bei späteren Anfragen erneuert, nicht durch einen eigenen Timer." ], "calloutTitle": "Fail2Ban ist nicht enthalten", "calloutBody": "Fail2Ban ist nicht enthalten und wird nicht automatisch installiert. Die Installation ist über Monitor-Sicherheit oder Sicherheit → Fail2Ban in ProxMenux Scripts möglich. Fehlen fail2ban-client oder das Jail proxmenux, blockiert dieser Hook keine Anfragen. Die eingestellte Authentifizierung gilt weiter.", "outro": "Beispiele für Nginx, Caddy und Traefik sowie die Jail-Anleitung stehen unter Zugriff und Authentifizierung und Sicherheit → Fail2Ban." }, "whereNext": { "heading": "Weitere Schritte", "items": [ { "label": "Zugriff und Authentifizierung", "href": "/docs/monitor/access-auth", "tail": " — Ersteinrichtung, Passwort und TOTP-2FA, Reverse-Proxy-Beispiele und Fail2Ban-Jail." }, { "label": "API-Referenz", "href": "/docs/monitor/api", "tail": " — Integrationsendpunkte, Token-Verwaltung und Authentifizierungskonventionen." }, { "label": "Einstellungen → ProxMenux Monitor", "href": "/docs/settings/proxmenux-monitor", "tail": " — Dienststeuerung und Zustandsprüfung im ProxMenux-Textmenü." } ] } }