Describe the Monitor pages as the code behaves

This commit is contained in:
MacRimi
2026-10-18 17:16:51 +02:00
parent 456f7e64f6
commit c1fb72ed0e
109 changed files with 473 additions and 473 deletions
+11 -11
View File
@@ -19,7 +19,7 @@
"reaching": {
"heading": "Reaching the dashboard",
"intro": "ProxMenux Monitor binds to <code>0.0.0.0:8008</code>. There are three common ways to reach it:",
"outro": "Direct access matches the default systemd unit. Reverse-proxy and Secure Gateway access are described below. Trust for client IPs in <code>X-Forwarded-For</code> requires PROXMENUX_TRUST_PROXY=1 and a proxy you control. The presence of <code>X-Forwarded-Proto</code> or <code>X-Forwarded-Host</code> alone does not enable proxy trust; the frontend builds API URLs from the browser’s origin."
"outro": "Direct access matches the default systemd unit. Reverse-proxy and Secure Gateway access are described below. Trust for client IPs in <code>X-Forwarded-For</code> requires PROXMENUX_TRUST_PROXY=1 and a proxy you control. The presence of <code>X-Forwarded-Proto</code> or <code>X-Forwarded-Host</code> alone does not enable proxy trust. On ports 80/443 the frontend uses relative <code>/api/*</code> URLs; on any other port it calls port 8008 on the same host name."
},
"firstLaunch": {
"heading": "First-launch flow",
@@ -117,8 +117,8 @@
"loginImageCaption": "Once authentication is configured, every visit to the dashboard starts here. With 2FA enabled, the screen asks for the 6-digit code in a second step after the password is accepted.",
"loginFlowTitle": "Login flow",
"twofaIntro": "With 2FA enabled, the same call returns <code>requires_totp: true</code> first. Re-issue with the 6-digit code:",
"publicTitle": "Public access and protected probes",
"publicIntro": "Login and authentication status are public. Initial setup is available while no username and password are stored, including after declining protection. System-data probes require authentication when protection is enabled:",
"publicTitle": "Public endpoints (no token)",
"publicIntro": "Login, authentication status, initial setup and the lightweight <code>/api/system-info</code> endpoint are public:",
"publicItems": [
"<code>/api/auth/login</code> and <code>/api/auth/status</code> are public. <code>/api/auth/setup</code> creates the initial account and rejects attempts to overwrite existing credentials.",
"<code>/api/system-info</code> is a public lightweight system-information endpoint, including <code>health.status</code>. It is not decorated with the token requirement. /api/auth/status is another public endpoint suitable for a reachability check."
@@ -146,7 +146,7 @@
},
{
"asset": "2FA TOTP secret",
"algorithm": "Standard TOTP (RFC 6238), with a base32-encoded secret. The eight recovery codes are single-use and stored as SHA-256 hashes.",
"algorithm": "Standard TOTP (RFC 6238), with a base32-encoded secret. The eight backup codes are single-use and stored as SHA-256 hashes.",
"where": "<code>auth.json</code> → <code>totp_secret</code> + <code>backup_codes[]</code>"
},
{
@@ -243,17 +243,17 @@
}
],
"backupTitle": "What \"backup\" really matters for",
"backupBody": "If you lose the authenticator device, use a saved recovery code or restore the app from a backup you configured beforehand. Cloud sync and local exports differ by app; check that your chosen method actually restores the TOTP secrets. Root access to the host also allows recovery, as explained below. Keep a separate, secure backup.",
"backupBody": "If you lose the authenticator device, use a saved backup code or restore the app from a backup you configured beforehand. Cloud sync and local exports differ by app; check that your chosen method actually restores the TOTP secrets. Root access to the host also allows recovery, as explained below. Keep a separate, secure backup.",
"setupTitle": "Step-by-step setup from the dashboard",
"setupImageAlt": "2FA setup screen with QR code and backup codes",
"setupImageCaption": "The 2FA setup dialog shows a QR code, a Base32 secret for manual entry, and eight one-time recovery codes. Copy the codes before closing the dialog; they are not displayed again.",
"setupImageCaption": "The 2FA setup dialog shows a QR code, a Base32 secret for manual entry and, after verification, eight one-time backup codes. Copy the codes before closing the dialog; they are not displayed again.",
"setupSteps": [
"<strong>Install the authenticator app on your phone</strong> (or open your password manager). One of the apps from the table above. You only need to do this once — the same app will hold codes for every service you protect.",
"<strong>Log into the dashboard</strong> with your username and password.",
"<strong>Open the Security tab</strong> in the dashboard sidebar, then click <strong>Enable 2FA</strong>. A dialog shows a QR code, the Base32 secret and eight recovery codes.",
"<strong>Open the Security tab</strong> in the dashboard sidebar, then click <strong>Enable 2FA</strong> and <strong>Start setup</strong>. The dialog shows a QR code and the manual key; the eight backup codes appear after the code is verified.",
"<strong>Add the entry to the authenticator app:</strong>",
"<strong>Save the recovery codes.</strong> Store all eight safely in a password manager, encrypted note or secure printed copy. Each works once if your authenticator is unavailable.",
"<strong>Confirm by typing the current 6-digit code</strong> from the app into the \"Verification code\" field of the setup dialog and submit. Codes refresh every 30 seconds, so if it expires while you're typing, just enter the next one.",
"<strong>Save the backup codes.</strong> After verification, store all eight safely in a password manager, encrypted note or secure printed copy. Each works once if your authenticator is unavailable.",
"<strong>Done.</strong> 2FA is now active. Next time you log in, the dashboard asks for the password first; once it's accepted it asks for the current 6-digit code."
],
"setupStep4Sub": [
@@ -261,17 +261,17 @@
"<em>Manual fallback</em> (when scanning isn't possible — e.g. setting up on the same phone you opened the dashboard with): tap <em>Add account</em> → <em>Enter setup key</em>. Type any name (e.g. <em>Proxmox Monitor</em>), paste the Base32 string from the dialog, leave <em>Type</em> as <em>Time-based</em>, save."
],
"testTitle": "Test before logging out",
"testBody": "Keep your current session open and test a new login in a private window <em>immediately</em> after setup. If the code is rejected, check the server and phone clocks before logging out of the working session. If access is already lost, use a recovery code or edit <code>auth.json</code> from the host shell.",
"testBody": "Keep your current session open and test a new login in a private window <em>immediately</em> after setup. If the code is rejected, check the server and phone clocks before logging out of the working session. If access is already lost, use a backup code or edit <code>auth.json</code> from the host shell.",
"lostTitle": "Lost authenticator",
"lostIntro": "Three escape hatches, in order of how disruptive they are:",
"lostItems": [
"<strong>Use a recovery code.</strong> Enter one of the eight saved codes in the TOTP field. It works once; unused codes remain valid. After logging in, set up 2FA again from Settings to obtain eight new codes.",
"<strong>Use a backup code.</strong> Enter one of the eight saved codes in the TOTP field. It works once; unused codes remain valid. After logging in, open Security, choose <strong>Disable 2FA</strong> and then <strong>Enable 2FA</strong> to obtain eight new codes.",
"<strong>Restore the authenticator from cloud / backup.</strong> If your app has a cloud sync (Google, Microsoft, Authy, Apple Passwords via iCloud Keychain, Ente, 2FAS) install it on a new device, sign in, and the entries reappear. If your app uses an encrypted export file (Aegis, Raivo, FreeOTP+), install the app on the new device and import the file.",
"<strong>Disable 2FA from the host shell.</strong> When the previous options aren't available, edit <code>/root/.config/proxmenux-monitor/auth.json</code> on the Proxmox host (you need root SSH or console access), set <code>totp_enabled</code> to <code>false</code>, save, and restart the service:"
],
"lostShellOutro": "You can log in with username + password only, then re-enable 2FA from Settings.",
"disableTitle": "Disable 2FA",
"disableBody": "Open <strong>Security</strong> and choose <strong>Disable 2FA</strong>. <code>POST /api/auth/totp/disable</code> requires the current password and a valid TOTP or recovery code. It removes the TOTP secret and recovery codes. Remove the old entry from your authenticator app too.",
"disableBody": "Open <strong>Security</strong> and choose <strong>Disable 2FA</strong>. <code>POST /api/auth/totp/disable</code> requires the current password and a valid TOTP or backup code. It removes the TOTP secret and backup codes. Remove the old entry from your authenticator app too.",
"rejectedTitle": "The 6-digit code is always rejected",
"rejectedIntro": "TOTP is time-based — server clock and phone clock must agree to within ~30 s. Two checks:",
"rejectedItems": [
@@ -14,7 +14,7 @@
},
"intro": {
"title": "Off by default, single switch to enable",
"body": "AI rewriting is off by default. Enable it in <em>Settings → Notifications → Advanced: AI Enhancement</em>. If enrichment or rewriting fails, the dispatcher sends the original template. Each rewrite has a 25-second dispatch timeout; reaching it falls back to the template instead of waiting indefinitely."
"body": "AI rewriting is off by default. Enable it in <em>Settings → Notifications → Advanced: AI Enhancement</em>. If enrichment or rewriting fails, the dispatcher sends the original template. Rewrites in the event dispatch queue have a 25-second timeout; reaching it sends the template instead of waiting."
},
"howItWorks": {
"heading": "How it works",
@@ -109,7 +109,7 @@
],
"customNote": "Custom prompt mode uses a fixed cap of 500 output tokens regardless of detail level — the custom prompt is in your control and the cap protects against runaway responses.",
"sizingTitle": "Practical sizing",
"sizingBody": "Estimate usage as rewritten events × AI-enabled channels × input-plus-output tokens per call. For example, 50 events × one channel × (500 input + 300 output tokens) is 40,000 tokens per day, not a few thousand. Actual usage and charges depend on model, context, caching and provider limits. The <link>Detail level per channel</link> section shows how to use <code>brief</code> for chat instead of <code>standard</code>, while keeping detailed email reports."
"sizingBody": "Estimate usage as rewritten events × AI-enabled channels × input-plus-output tokens per call. For example, 50 events × one channel × (2,000 input + 300 output tokens) is about 115,000 tokens per day, since the default system prompt alone is roughly 1,500 tokens. Actual usage and charges depend on model, context, caching and provider limits. The <link>Detail level per channel</link> section shows how to use <code>brief</code> for chat instead of <code>standard</code>, while keeping detailed email reports."
},
"providers": {
"heading": "AI providers",
@@ -142,7 +142,7 @@
"items": [
"API key: <a>console.anthropic.com/settings/keys</a>",
"Examples from the bundled model list: <code>claude-haiku-4-5-20251001</code>, <code>claude-sonnet-4-6</code>, <code>claude-opus-4-6</code>.",
"Bundled recommendation: <strong><code>claude-haiku-4-5-20251001</code></strong>. This exact snapshot is the configured recommendation; the older Claude 3.5 entries shown in earlier documentation are no longer in the bundled list."
"Bundled recommendation: <strong><code>claude-haiku-4-5-20251001</code></strong>, a pinned snapshot rather than a moving alias."
]
},
"gemini": {
@@ -162,7 +162,7 @@
{
"endpoint": "/api/vms/<vmid>/backup",
"method": "POST",
"use": "Create a vzdump backup of a VM or LXC. Body fields, all optional unless the defaults do not match the storage layout: <code>storage</code> (a PVE storage), <code>mode</code> (<code>snapshot</code>, <code>suspend</code> or <code>stop</code>), <code>compress</code> (<code>zstd</code>, <code>lzo</code>, <code>gzip</code> or <code>none</code>), <code>protected</code> (<code>true</code> or <code>false</code>), <code>notes</code>, <code>notification</code> (<code>auto</code>, <code>always</code>, <code>failure</code> or <code>never</code>) and <code>pbs_change_detection</code> (<code>default</code>, <code>legacy</code> or <code>data</code>). Returns the PVE task UPID."
"use": "Create a vzdump backup of a VM or LXC. Body fields, all optional unless the defaults do not match the storage layout: <code>storage</code> (a PVE storage), <code>mode</code> (<code>snapshot</code>, <code>suspend</code> or <code>stop</code>), <code>compress</code> (<code>zstd</code>, <code>lzo</code>, <code>gzip</code> or <code>none</code>), <code>protected</code> (<code>true</code> or <code>false</code>), <code>notes</code> and <code>pbs_change_detection</code> (<code>default</code>, <code>legacy</code> or <code>data</code>). Returns the PVE task UPID."
},
{
"endpoint": "/api/vms/<vmid>/backups",
@@ -286,7 +286,7 @@
{
"endpoint": "/api/storage/smart/<disk>/test",
"method": "POST",
"use": "Start a SMART self-test. Body schema: <code>'{'\"type\":\"short\"|\"long\"'}'</code>."
"use": "Start a SMART self-test. Body schema: <code>'{'\"test_type\":\"short\"|\"long\"'}'</code>."
},
{
"endpoint": "/api/storage/smart/schedules",
@@ -73,13 +73,13 @@
"intro": "The AppImage is a self-mounting filesystem. <code>AppRun</code> at the root sets up the environment and execs <code>flask_server.py</code>:",
"consequencesIntro": "Two consequences of this layout:",
"consequences": [
"<strong>Bundled Python environment.</strong> The interpreter and Python packages are shipped inside the AppImage, avoiding installation into the host’s system Python environment. The application still uses host kernel interfaces and external host tools.",
"<strong>Bundled Python packages.</strong> Python packages ship inside the AppImage and run on the host's own Python 3.11 (PVE 8) or 3.13 (PVE 9) interpreter, without installing anything into the host's system Python. The application still uses host kernel interfaces and external host tools.",
"<strong>Hardware clients are bundled too.</strong> <code>ipmitool</code>, <code>lm-sensors</code> and <code>upsc</code> are included. Readings still depend on supported hardware, access to sensors and, for UPS data, a configured NUT server."
]
},
"flask": {
"heading": "Flask app structure",
"intro": "<code>flask_server.py</code> creates one <code>Flask(__name__)</code> instance with restricted CORS origins, registers nine blueprints directly and initializes terminal routes. The table highlights the main modules; audit, VM-backup and PBS blueprints are also registered. PVE-specific prewarmers run only on PVE hosts.",
"intro": "<code>flask_server.py</code> creates one <code>Flask(__name__)</code> instance with restricted CORS origins, registers ten blueprints directly and initializes terminal routes. The table highlights the main modules; PBS, Monitor links, audit and VM-backup blueprints are also registered. PVE-specific prewarmers run only on PVE hosts.",
"headerBlueprint": "Blueprint / module",
"headerPrefix": "Routes prefix",
"headerOwns": "Owns",
@@ -242,10 +242,10 @@
"Updates: pending package upgrades and security patches.",
"Logs: persistent / spike / cascade pattern detection in the system journal.",
"Memory: OOM killer activity, sustained high pressure.",
"Temperature: CPU and disk readings checked against monitoring thresholds; available sensors depend on the hardware.",
"CPU: usage and CPU temperature checked against the configurable thresholds; available sensors depend on the hardware.",
"Security: authentication failures, ban events, fail2ban jail status."
],
"afterIntro": "Findings use a stable <code>error_key</code>, category and severity. Existing records in <code>errors</code> are updated with <code>last_seen</code> and occurrence counts rather than duplicated. Notification delivery also has its own fingerprint and cooldown rules.",
"afterIntro": "Findings use a stable <code>error_key</code>, category and severity. Existing records in <code>errors</code> are updated in place (<code>last_seen</code>, severity, reason) rather than duplicated. Notification delivery also has its own fingerprint and cooldown rules.",
"cycleEnd": "Cleanup can auto-resolve stale errors using category <em>Suppression Duration</em> values and state-based rules, remove orphan records for resources that were removed, and prune <code>events</code> older than 30 days. The categories and dashboard are described in <link>Dashboard → Health Monitor</link>."
},
"notifications": {
@@ -264,9 +264,9 @@
"intro": "The <em>Terminal</em> tab in the dashboard is a thin <code>xterm.js</code> client wired to a server-side PTY through a WebSocket. Two transport modes:",
"items": [
"<strong>HTTP mode (default):</strong> the built-in Flask server with <code>flask-sock</code> handles WebSocket upgrade requests.",
"<strong>HTTPS / WSS mode:</strong> the TLS server uses <code>gevent.pywsgi.WSGIServer</code> with <code>geventwebsocket.handler.WebSocketHandler</code> for WebSocket connections over TLS."
"<strong>HTTPS / WSS mode:</strong> the TLS server uses <code>gevent.pywsgi.WSGIServer</code> with its default handler; <code>flask-sock</code> handles WebSocket connections over TLS."
],
"outro": "Terminal child processes inherit <code>User=root</code> from the service. With authentication enabled, opening a WebSocket requires a short-lived, single-use ticket obtained from the authenticated terminal-ticket endpoint with administrative scope. When authentication is disabled or declined, the handshake follows that unauthenticated mode.",
"outro": "Terminal child processes inherit <code>User=root</code> from the service. Opening a WebSocket requires a short-lived, single-use ticket obtained from the authenticated terminal-ticket endpoint with administrative scope.",
"proxyNote": "If you access the Monitor through a reverse proxy, make sure WebSocket forwarding is enabled (the <code>Upgrade</code> and <code>Connection</code> headers). Without it the terminal won't work."
},
"proxy": {
@@ -162,7 +162,7 @@
}
],
"reportTitle": "Network Latency Report (PDF)",
"reportIntro": "Both modes have a <strong>Report</strong> button beside the target selector. It generates a PDF of the measurements that you can attach to a troubleshooting request to your ISP.",
"reportIntro": "Both modes have a <strong>Report</strong> button beside the target selector. It opens a printable report of the measurements; save it as PDF from the browser's print dialog and attach it to a troubleshooting request to your ISP.",
"reportPreviewAlt": "First page of the Network Latency Report PDF — Executive Summary with the gauge, latency statistics, the latency graph and the threshold guide",
"reportPreviewCaption": "The first page of the Network Latency Report contains the executive summary, gauge, main statistics, time-series latency graph and threshold guide. Page 2 onwards contains the per-sample table and methodology.",
"downloadLabel": "Download sample Network Latency report (PDF)",
@@ -136,7 +136,7 @@
"configCaption": "Editing the sshd jail — pick a stricter <em>Max Retries</em> for SSH if you only ever log in from your own subnet, or extend <em>Ban Time</em> for the public-facing dashboard.",
"outro": "The full <em>What it installs / how it's configured / how to uninstall</em> walkthrough — including the manual install path, the SSH MaxAuthTries side effect, and the relationship with the <code>proxmenux-auth.log</code> journal — is in <link>ProxMenux → Security → Fail2Ban</link>.",
"calloutTitle": "Without Fail2Ban, this mechanism does not block IPs",
"calloutBody": "ProxMenux Monitor checks Fail2Ban’s banned IPs at the <em>application level</em> before handling Flask requests. It queries fail2ban-client and caches the result for 30 seconds; it does not read a SQL bans table. Without Fail2Ban, failed logins are recorded in <code>proxmenux-auth.log</code>, but this mechanism does not actively block IPs."
"calloutBody": "ProxMenux Monitor checks the IPs banned in Fail2Ban's <code>proxmenux</code> jail at the <em>application level</em> before handling Flask requests, caching the result for 30 seconds. Without Fail2Ban, failed logins are recorded in <code>proxmenux-auth.log</code> and the login endpoint is limited to 5 attempts per IP every 5 minutes, but no IP is banned."
},
"lynis": {
"heading": "Lynis Security Audit",
@@ -76,7 +76,7 @@
},
"thresholds": {
"heading": "Health Monitor Thresholds",
"intro": "The previous card sets <em>how long to stay quiet after a dismiss</em>; this one sets <strong>the value at which an alert is raised</strong>. Most threshold-based checks have adjustable <strong>Warning</strong> and <strong>Critical</strong> values. The table below explains exceptions such as the combined swap rule and the current RAM detector.",
"intro": "The previous card sets <em>how long to stay quiet after a dismiss</em>; this one sets <strong>the value at which an alert is raised</strong>. Most threshold-based checks have adjustable <strong>Warning</strong> and <strong>Critical</strong> values. The table below explains exceptions such as the combined swap rule.",
"whatForTitle": "What it is for",
"whatForIntro": "Defaults that ship with ProxMenux are sane for the average Proxmox host, but every environment has its own envelope:",
"whatForItems": [
@@ -85,7 +85,7 @@
"Choose drive-temperature thresholds using the drive’s specifications and observed operating conditions. Passive versus forced-air cooling alone does not determine a universally lower or higher safe limit.",
"A heavily-virtualized host that pegs CPU during builds should not page on every 80 % spike, but must still alert on sustained pressure."
],
"whatForOutro": "Supported threshold changes take effect <strong>on the next scan</strong>. The Health Monitor reads <code>/usr/local/share/proxmenux/health_thresholds.json</code> each cycle without a restart. Selected widgets, including disk temperature, use these values; some capacity bars retain separate visual cutoffs. See the RAM row below for a current runtime exception.",
"whatForOutro": "Supported threshold changes take effect <strong>on the next scan</strong>. The Health Monitor reads <code>/usr/local/share/proxmenux/health_thresholds.json</code> each cycle without a restart. Selected widgets, including disk temperature, use these values; some capacity bars retain separate visual cutoffs.",
"coloursTitle": "Status colours: how Warning and Critical render in the dashboard",
"coloursIntro": "Widgets that use the configured Warning/Critical pair follow the three-state classification below. Some visual indicators, including the PVE storage capacity bars, use their own cutoffs; do not infer a Health Monitor alert solely from their colour.",
"headerColour": "Colour",
@@ -125,7 +125,7 @@
"section": "Memory",
"warning": "85 %",
"critical": "95 %",
"gates": "Host RAM pressure. The configurable Critical default shown here is 95 %, but the current detector uses a hard-coded 90 % sustained RAM rule; changing that setting does not currently change this runtime branch."
"gates": "Host RAM pressure."
},
{
"section": "Swap (critical only)",
@@ -185,7 +185,7 @@
"section": "PVE storage",
"warning": "85 %",
"critical": "95 %",
"gates": "PVE-managed storages, including LVM, LVM-thin, ZFS-pool, RBD/Ceph and PBS. These are not all block-storage backends."
"gates": "Only PVE storages of type LVM, LVM-thin, ZFS-pool, RBD, CephFS and PBS. Directory, NFS and CIFS storages are covered by the host disk-space row."
},
{
"section": "ZFS pool",
@@ -218,7 +218,7 @@
"toggleTitle": "Conditional notification toggle",
"toggleBody": "The <code>lxc_updates_available</code> per-channel notification toggle in <strong>Notifications → Services</strong> only renders while detection is enabled. When you turn detection OFF, that row disappears from every channel's category list — but its stored preference is preserved in the DB, so re-enabling detection brings the toggle back at the value it had before.",
"purgeTitle": "What gets purged when you disable detection",
"purgeBody": "Turning the switch OFF immediately removes every <code>type=lxc</code> entry from <code>/usr/local/share/proxmenux/managed_installs.json</code>. LXC update counts on the Hardware tab clear on the next dashboard refresh. Turning it back ON repopulates the registry on the next detection cycle, or sooner with a manual API refresh."
"purgeBody": "Turning the switch OFF immediately removes every <code>type=lxc</code> entry from <code>/usr/local/share/proxmenux/managed_installs.json</code>. LXC update counts in the VMs & LXCs tab clear on the next dashboard refresh. Turning it back ON repopulates the registry on the next detection cycle, or sooner with a manual API refresh."
},
"storageExclusions": {
"heading": "Remote Storage Exclusions",
@@ -70,7 +70,7 @@
"items": [
"<strong>Device path</strong> — <code>/dev/sda</code>, <code>/dev/nvme0n1</code>.",
"<strong>Type badge</strong> — SATA / NVMe (and the relevant icon).",
"<strong>System badge</strong> — orange tag for disks identified as hosting the OS. Detection uses the mountpoints of <code>/</code> and <code>/boot</code>; physical disks hosting them receive the <em>System</em> tag. A missing tag does not prove a disk is safe to erase or repurpose.",
"<strong>System badge</strong> — orange tag for disks in use by the host: system mountpoints (<code>/</code>, <code>/boot</code>, <code>/usr</code>, <code>/var</code>…), active swap, ZFS pool members, LVM physical volumes, active RAID members or system partition labels. A missing tag does not prove a disk is safe to erase or repurpose.",
"<strong>Model</strong> — vendor + model string from <code>smartctl -i</code>.",
"<strong>Capacity</strong> — formatted human-readable.",
"<strong>Temperature</strong> — current °C, coloured by the disk-type threshold (NVMe runs warmer than SATA).",
@@ -112,7 +112,7 @@
"pdfPreviewAlt": "First page of the generated SMART Health Report PDF — Executive Summary with the PASSED ring + Disk Information block",
"pdfPreviewCaption": "First page of the SMART Health Report — Executive Summary with the PASSED ring and the full Disk Information block. The full PDF below has the SSD wear ring, every SMART attribute and the test history.",
"pdfDownloadLabel": "Download sample SMART report (PDF)",
"pdfSectionsIntro": "The report has six main sections:",
"pdfSectionsIntro": "The report includes these main sections:",
"pdfSections": [
"<strong>Executive Summary</strong> — large PASSED / FAILED verdict, plain-language disk health assessment paragraph (\"your disk is healthy / showing signs of wear / failing\"), and four quick stats (report timestamp, last-test type, test result, attributes checked).",
"<strong>Disk Information</strong> — model, serial, capacity, type (HDD / SSD / NVMe), family, form factor, interface (SATA 3.3 · 6.0 Gb/s, …), TRIM support, current temperature with the optimal threshold, power-on time, power cycles, SMART status, plus the headline counters (pending sectors, CRC errors, reallocated sectors).",
@@ -127,7 +127,7 @@
"historyImageCaption": "History tab — every retained SMART test for this disk. Per row: type, timestamp, \"X days ago\" tag, latest marker, download (raw <code>smartctl</code> output) and delete actions.",
"historyIntro": "The retained pool of SMART tests for this disk — both short and extended runs that completed. Each entry is the raw <code>smartctl</code> output captured at run time, plus the structured fields the Monitor parsed out for the dashboard. Per-row actions:",
"historyItems": [
"<strong>Download</strong> — saves the retained JSON snapshot with the <code>smartctl -a</code> data used by the report. Useful when vendor support needs the original diagnostic fields.",
"<strong>Download</strong> — saves that test's JSON snapshot (<code>smartctl -a --json</code> output, or <code>nvme smart-log</code> on NVMe when smartctl fails). Useful when vendor support needs the original diagnostic fields.",
"<strong>Delete</strong> — removes the test from history. The retention limit set in the Schedule tab (<em>Last 5 / 10 / 20</em>) deletes oldest-first automatically; this action is the manual override."
],
"scheduleTitle": "Tab 4 — Schedule",
@@ -1,16 +1,16 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: VMs & LXCs tab | ProxMenux Documentation",
"description": "The VMs & LXCs tab inventories every guest on the host with live CPU / memory / disk usage. Per-guest details show configuration, resources, backups, recent Proxmox log results, notes, and Start / Shutdown / Reboot / Stop controls."
"description": "The VMs & LXCs tab inventories every guest on the host with live CPU / memory / disk usage. Per-guest details show configuration, resources, backups, the console log of OCI containers, notes, and Start / Shutdown / Reboot / Force Stop controls."
},
"header": {
"title": "Dashboard: VMs & LXCs tab",
"description": "The full inventory of guests on the node. Four headline metrics across the top, a sortable list of every VM and LXC below, and a drill-in per guest with config, resources, backups, logs and the four lifecycle controls (Start / Shutdown / Reboot / Stop).",
"description": "The full inventory of guests on the node. Four headline metrics across the top, a sortable list of every VM and LXC below, and a drill-in per guest with config, resources, backups, the console log of OCI containers and the four lifecycle controls (Start / Shutdown / Reboot / Force Stop).",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "The control surface for guests",
"body": "Use this tab to control guest lifecycles. Lifecycle actions go through <code>POST /api/vms/&lt;vmid&gt;/control</code> with an explicit confirmation and the response is reflected back in the guest’s row. Force shutdown requires the dedicated Force Stop button."
"body": "Use this tab to control guest lifecycles. Lifecycle actions go through <code>POST /api/vms/&lt;vmid&gt;/control</code>; Reboot and Force Stop ask you to type the VMID to confirm, and the response is reflected back in the guest’s row. Force shutdown requires the dedicated Force Stop button."
},
"topRow": {
"heading": "Top row: four stat cards",
@@ -186,9 +186,9 @@
"source": "PVE RRD data (<code>pvesh get /nodes/&lt;node&gt;/qemu/&lt;id&gt;/rrddata</code>) condensed to a chart-friendly shape."
},
{
"section": "Recent Proxmox log results",
"endpoint": "/api/vms/<vmid>/logs",
"source": "<code>pvesh get /nodes/&lt;node&gt;/&lt;qemu|lxc&gt;/&lt;vmid&gt;/log --start 0 --limit 1000</code>. A command failure returns an empty list; this does not provide complete in-guest system logs."
"section": "OCI console log (Logs tab)",
"endpoint": "/api/lxc/<vmid>/console-log",
"source": "Console output of the image's main process, read from <code>/var/log/proxmenux/oci/&lt;vmid&gt;.console.log</code> on the host. Shown for OCI containers only."
},
{
"section": "Backups available for guest",
@@ -68,7 +68,7 @@
{
"category": "Storage",
"checks": "Proxmox storages, root filesystem",
"events": "Root or other monitored filesystems crossing configured space thresholds (85% warning / 95% critical by default); offline NFS export; CIFS authentication failure; full LVM-thin pool."
"events": "Root or other monitored filesystems crossing configured space thresholds (85% warning / 95% critical by default); unavailable PVE storages; stale or unexpectedly read-only NFS/CIFS mounts; LVM-thin and other pool storages crossing the same thresholds."
},
{
"category": "Disks & SMART",
@@ -98,7 +98,7 @@
{
"category": "System Updates",
"checks": "Pending updates, security updates, kernel / PVE version, system age",
"events": "Pending security or running-kernel updates; a system not updated for a long time. The Overview header shows an <em>Update Now</em> button when updates are pending. It runs the full ProxMenux update flow inline; closing it refreshes health with <code>?refresh=1</code> so the badge reflects the new state without waiting for the next cycle."
"events": "Pending security or running-kernel updates; a system not updated for a long time. The Updates category of the Health Status modal shows an <em>Update Now</em> button when updates are pending. It runs the full ProxMenux update flow inline; closing it refreshes health with <code>?refresh=1</code> so the badge reflects the new state without waiting for the next cycle."
},
{
"category": "Security & Certificates",
@@ -158,7 +158,7 @@
},
"dismiss": {
"heading": "Dismissing alerts and the Suppression Duration",
"intro": "Some events are noisy by nature — a <em>System Updates: pending updates available</em> stays true until you patch the host, and you don't want a notification every five minutes for a week. The <em>Update Now</em> button in the Overview header is the direct shortcut to resolve that specific case in place; for everything else, or when patching is deferred, the Health Monitor also offers two coupled silencing mechanisms:",
"intro": "Some events are noisy by nature — a <em>System Updates: pending updates available</em> stays true until you patch the host, and you don't want a notification every five minutes for a week. The <em>Update Now</em> button in the Updates category of the Health Status modal is the direct shortcut to resolve that specific case in place; for everything else, or when patching is deferred, the Health Monitor also offers two coupled silencing mechanisms:",
"step1": "<strong>Per-event Dismiss action</strong> in the modal. The Dismiss button opens a small dropdown with three options — <strong>24 hours</strong>, <strong>7 days</strong> or <strong>Permanently</strong> — letting you choose how long this specific alert stays silenced regardless of the category's default. Picking one calls <code>POST /api/health/acknowledge</code> with the <code>error_key</code> and the chosen <code>suppression_hours</code> (<code>-1</code> for permanent). The event moves to the Dismissed list with a timestamped <code>acknowledged_at</code>.",
"dropdownImageAlt": "Dismiss dropdown on a Health Monitor alert — 24 hours, 7 days or Permanently",
"dropdownImageCaption": "Per-event Dismiss dropdown. The chosen window applies to this single alert; without a per-event choice the category default is used. Permanent dismissals have an amber <em>Permanent</em> badge and normally do not re-fire. The critical CPU-temperature override described below is an exception.",
@@ -187,7 +187,7 @@
},
{
"finding": "ZFS pool DEGRADED / FAULTED",
"why": "ZFS pool-capacity checks explicitly allow dismissal. Other pool findings follow their own flag. Acknowledgment does not repair a degraded or faulted pool."
"why": "ZFS pool-state findings (DEGRADED, FAULTED, UNAVAIL) explicitly allow dismissal, as do pool-capacity checks. Acknowledgment does not repair a degraded or faulted pool."
},
{
"finding": "Disk I/O errors with SMART FAILED",
@@ -289,7 +289,7 @@
},
"rest": {
"heading": "REST endpoints",
"intro": "The modal actions are also available through the API for scripts, custom dashboards or chatbots. When Monitor authentication is enabled, calls need a valid bearer token, either from login or the API-token screen. Changes such as acknowledging alerts, saving suppression settings or cleaning orphan errors require full_admin scope; read_only receives 403. When authentication is disabled or declined, these decorators allow access without a token.",
"intro": "The modal actions are also available through the API for scripts, custom dashboards or chatbots. Calls need a valid bearer token, either from login or the API-token screen. Changes such as acknowledging alerts, saving suppression settings or cleaning orphan errors require full_admin scope; read_only receives 403.",
"headerEndpoint": "Endpoint",
"headerMethod": "Method",
"headerUse": "Use",
@@ -297,7 +297,7 @@
{
"endpoint": "/api/health",
"method": "GET",
"use": "Lightweight health probe returning JSON with <code>status</code>, <code>timestamp</code> and <code>version</code>. Suitable for Uptime Kuma keyword checks; when Monitor authentication is enabled, the client must send a bearer header."
"use": "Lightweight health probe returning JSON with <code>status</code>, <code>timestamp</code> and <code>version</code>. Suitable for Uptime Kuma keyword checks; the client must send a bearer header."
},
{
"endpoint": "/api/health/status",
+2 -2
View File
@@ -52,7 +52,7 @@
},
{
"name": "Terminal",
"description": "Browser shell for the host and supported VM/CT console access, powered by <code>xterm.js</code> over WebSockets. It follows the configured authentication mode: when authentication is disabled or declined, reachable clients can open a session without login. This description does not imply per-command auditing."
"description": "Browser shell for the host and supported VM/CT console access, powered by <code>xterm.js</code> over WebSockets. Sessions are not audited per command."
},
{
"name": "Security",
@@ -114,7 +114,7 @@
"heading": "REST API and integrations",
"intro": "The dashboard’s REST endpoints expose monitoring data as JSON over HTTP/HTTPS for Homepage widgets, Home Assistant sensors, Uptime Kuma probes and custom scripts. Grafana can use the separate Prometheus text exporter at <code>/api/prometheus</code>. Requests can be made with <code>curl</code>.",
"tokens": "Long-lived API tokens (365 days) are generated from <strong>Settings → API Access Tokens</strong> or via <code>POST /api/auth/generate-api-token</code>.",
"bearer": "Send tokens as <code>Authorization: Bearer …</code>. The public <code>/api/health</code> endpoint is suitable for external uptime probes without credentials. Routes under <code>/api/auth/*</code> include both public setup/login/status routes and protected account/token management routes; they are not all anonymous.",
"bearer": "Send tokens as <code>Authorization: Bearer …</code>. <code>/api/health</code> also expects the bearer header, so uptime probes need a read_only token. Routes under <code>/api/auth/*</code> include both public setup/login/status routes and protected account/token management routes; they are not all anonymous.",
"catalog": "The full endpoint catalog, token rotation guidance and security best-practices live in <linkApi>API Reference</linkApi>; ready-made examples for Homepage, Home Assistant, Grafana, Uptime Kuma and a generic cURL pattern are in <linkIntegrations>Integrations</linkIntegrations>."
},
"serviceControl": {
@@ -220,7 +220,7 @@
"heading": "n8n, Zapier and custom scripts",
"intro": "Workflow tools and scripts can <em>send</em> notifications through a POST to <code>/api/notifications/send</code>, for example after a CI failure or an overlong cron job. This is a direct send: it bypasses the event queue and fingerprint cooldown. It still uses channel formatting, optional AI rewriting and delivery to configured channels. Apply any required duplicate control in the caller.",
"n8nBody": "In n8n, use an <em>HTTP Request</em> node with POST, the URL above and the same JSON body as curl. Choose generic Header Auth credentials: set the header name to <em>Authorization</em> and its value to <code>Bearer YOUR_API_TOKEN</code>, replacing the placeholder. Connect a schedule, webhook or other preceding node to trigger the request.",
"severityBody": "Severity values are <code>INFO</code>, <code>WARNING</code> or <code>CRITICAL</code> in uppercase. The <code>data</code> object supplies event context. AI rewriting uses the rendered title and message plus supported enrichment; arbitrary fields are not guaranteed to appear in its prompt or output. See <link>Notifications → Event catalogue</link> for event semantics."
"severityBody": "Severity values are <code>INFO</code>, <code>WARNING</code> or <code>CRITICAL</code> in uppercase. The <code>data</code> object supplies event context and template fields. On this endpoint, AI rewriting receives only the title and message; fields in <code>data</code> are not sent to the provider. See <link>Notifications → Event catalogue</link> for event semantics."
},
"pveWebhook": {
"heading": "Native Proxmox VE webhook (inbound)",
@@ -171,7 +171,7 @@
"Open <a>account.microsoft.com/security</a> and enable two-step verification.",
"If your account offers <em>Advanced security options</em> → <em>App passwords</em>, choose <em>Create a new app password</em>. This option alone does not establish that your mail service accepts password-based SMTP.",
"If Microsoft generates an app password, copy it and verify that your SMTP service accepts it.",
"Only if your provider permits password-based SMTP, fill in its approved settings: <em>Host</em> <code>smtp.office365.com</code> for Exchange Online, <em>Port</em> <code>587</code>, <em>TLS Mode</em> <code>STARTTLS</code>, <em>Username</em> your mailbox address, and <em>Password</em> the permitted SMTP credential. Personal Outlook.com settings and authentication requirements are different; do not assume these credentials will work."
"Only if your provider permits password-based SMTP, fill in its approved settings: <em>SMTP host</em> <code>smtp.office365.com</code> for Exchange Online, <em>Port</em> <code>587</code>, <em>TLS mode</em> <code>STARTTLS</code>, <em>Username</em> your mailbox address, and <em>Password</em> the permitted SMTP credential. Personal Outlook.com settings and authentication requirements are different; do not assume these credentials will work."
],
"relayTitle": "Self-hosted SMTP relay",
"relayBody": "Point the Monitor at an SMTP relay you control, such as Postfix. The relay handles upstream authentication. Configure the Monitor’s authentication and TLS mode to match the relay; using a local relay does not itself disable encryption."
@@ -266,7 +266,7 @@
"howItems": [
"<strong>Per-channel opt-in.</strong> Off by default — Telegram doesn't silently batch your alerts. You enable it on the channels where you want a digest, leaving others on live delivery.",
"<strong>Delivery time</strong> in your local timezone. Defaults to 09:00 but you can pick any time; the dispatcher fires the digest within ~60 s of that minute.",
"<strong>Included in the digest:</strong> eligible generic events with severity <strong>INFO</strong>. Examples include <em>application update available</em>, <em>Tailscale update available</em>, <em>ProxMenux optimisation update available</em>, <em>APT security updates pending</em> and <em>rate-limit notice</em>. Backup results and other exempt action events remain live.",
"<strong>Included in the digest:</strong> eligible generic events with severity <strong>INFO</strong>. Examples include <em>application update available</em>, <em>Tailscale update available</em>, <em>ProxMenux optimisation update available</em> and <em>APT security updates pending</em>. Backup results and other exempt action events remain live.",
"<strong>What is never delayed:</strong>",
"<strong>Persistence.</strong> Pending events sit in a SQLite table (<code>digest_pending</code>) until the configured hour. The Monitor can restart freely without losing what the digest will eventually contain.",
"<strong>Empty days are silent.</strong> If nothing INFO-level happened, no digest is sent — the channel stays quiet rather than receiving a \"no events to report\" message."
@@ -301,7 +301,7 @@
{
"stage": "Cooldown",
"what": "After successful delivery, repeated fingerprints are suppressed and the state is saved in <code>notification_last_sent</code>. Base defaults for <code>CRITICAL</code>, <code>WARNING</code> and <code>INFO</code> are 86 400 s, as are <code>resources</code> and <code>updates</code>. Exceptions include 5 s for VM/CT actions and host shutdown/reboot, 10 s for backup/replication results, and 1 800–3 600 s for several health-state categories. Explicit event/group settings can override these values.",
"tunable": "Yes — explicit cooldown settings for an event type or group override the defaults; these are dispatcher configuration values."
"tunable": "Only through the settings API — a <code>cooldown.&lt;event_type&gt;</code> or <code>cooldown.&lt;group&gt;</code> key overrides the defaults; there is no control in the UI."
},
{
"stage": "Burst aggregation",
@@ -330,7 +330,7 @@
"<strong>Method and URL.</strong> <code>POST http://127.0.0.1:8008/api/notifications/webhook</code> when Monitor HTTPS is off. With HTTPS enabled, the target uses the separate HTTP loopback listener on port 8009. Both stay on the same host.",
"<strong>Body template.</strong> A JSON body using PVE's native Handlebars helpers — stored base64-encoded in the config file by PVE, but it expands to:",
"<strong>Matcher.</strong> A companion <code>matcher: proxmenux-matcher</code> block with <code>mode all</code> so every PVE notification reaches the target.",
"<strong>Private configuration.</strong> Setup writes the matching <code>webhook: proxmenux-webhook</code> block in <code>/etc/pve/priv/notifications.cfg</code>, including the shared secret encoded in base64. The public target references that secret to send X-Webhook-Secret. The block is not an empty stub."
"<strong>Private configuration.</strong> Setup writes the matching <code>webhook: proxmenux-webhook</code> block in <code>/etc/pve/priv/notifications.cfg</code> with a <code>secret</code> entry named X-Webhook-Secret, encoded in base64. The public target block holds only the body template, method and URL. The private block is not an empty stub."
],
"securityTitle": "How the receiver is secured",
"securityIntro": "The webhook receiver at <code>POST /api/notifications/webhook</code> applies different security layers depending on where the request comes from:",