complete i18n migration to /[locale]/ with EN+ES content

Full rewrite of the docs site under app/[locale]/ with next-intl
in localePrefix:"always" mode. Every page now exists at both
/en/<path> and /es/<path>; the root / shows a meta-refresh + JS
redirect to /<defaultLocale>/ so GitHub Pages serves something
on the apex URL.

Highlights:
- 107 doc pages migrated to file-per-page JSON namespaces under
  messages/en/ and messages/es/. Spanish content is fully
  translated (no copy-of-English placeholders).
- New documentation for the Active Suppressions section in the
  Settings tab and the per-event Dismiss dropdown in the Health
  Monitor modal.
- New screenshots: dismiss-duration-dropdown.png and an updated
  health-suppression-settings.png.
- Pagefind integrated for client-side search; index is built on
  every CI deploy (not committed).
- RSS feeds: per-locale at /<locale>/rss.xml plus root /rss.xml
  for backward compat.
- Removed the dead app/[locale]/guides/[slug]/ route — every
  guide now has its own static page and no markdown source
  remains.
- Fixed orphan link /guides/nvidia -> /guides/nvidia-manual in
  docs/hardware/nvidia-host.
- Removed obsolete components (footer2, calendar, drawer).

Verified locally with `npm ci && npm run build`: 2804 files in
out/, 231 pages indexed by pagefind, root redirect intact, both
locale roots and the new Active Suppressions docs render OK.
This commit is contained in:
MacRimi
2026-05-31 12:41:10 +02:00
parent 875910b4d7
commit 5ca3463bf6
649 changed files with 83958 additions and 11096 deletions
@@ -0,0 +1,12 @@
{
"meta": {
"title": "Code of Conduct | ProxMenux Documentation",
"description": "ProxMenux Code of Conduct and best practices for contributors, testers and users.",
"ogTitle": "Code of Conduct | ProxMenux Documentation",
"ogDescription": "Expectations around code responsibility, security disclosure and PR scope for the ProxMenux project."
},
"errors": {
"notFound": "Error: CODE_OF_CONDUCT.md file not found.",
"loadFailed": "Error: Unable to load the Code of Conduct content."
}
}
@@ -0,0 +1,293 @@
{
"meta": {
"title": "Contributing to ProxMenux | ProxMenux Documentation",
"description": "How to contribute to ProxMenux — branching model (main / develop / feature/*), pull request workflow, script header template with author attribution and optional sponsor link, the two-phase UI design policy, message functions, and the path from a feature branch to a stable release.",
"ogTitle": "Contributing to ProxMenux",
"ogDescription": "Branching model, workflow, script header attribution and the two-phase UI design policy contributors must follow."
},
"header": {
"title": "Contributing to ProxMenux",
"description": "ProxMenux is open to community contributions — new scripts, fixes for existing ones, dialog improvements, translations, integrations. This page is the formal door: how the repository is structured, the branching model and pull-request workflow, the script header with author attribution and optional sponsor link, and the design conventions every contribution must follow.",
"section": "About"
},
"twoPagesCallout": {
"title": "Two related pages, one project",
"body": "Don't confuse this page with <contributorsLink>Contributors</contributorsLink>: that one celebrates the people who already contribute (testers, reviewers, developers). This page is for <em>you</em> — the prospective contributor — and explains how to send a PR that will be merged."
},
"branching": {
"heading": "Branching model",
"intro": "ProxMenux uses a three-tier branching model:",
"headerBranch": "Branch",
"headerPurpose": "Purpose",
"rows": [
{
"branch": "main",
"purposeRich": "Stable, production-ready code. Only release-grade merges land here. This is what end users get when they install ProxMenux normally."
},
{
"branch": "develop",
"purposeRich": "Active development branch. All new work lands here first; it's the “beta” channel. Stable releases are cut from here into <code>main</code> when a release is ready."
},
{
"branch": "feature/*",
"purposeRich": "Short-lived branches per feature, fix or improvement. Created from <code>develop</code>, merged back into <code>develop</code> via a Pull Request after review."
}
],
"calloutTitle": "What this means for users",
"calloutBody": "End users tracking <code>main</code> get tested releases. Users who want the latest features early — and don't mind occasional rough edges — can follow <code>develop</code>. New features always pass through <code>develop</code> first; nothing reaches <code>main</code> without going through that cycle."
},
"workflow": {
"heading": "Pull request workflow",
"intro": "From idea to merged release in five steps:",
"step1Lead": "<strong>Create a feature branch from <code>develop</code></strong>:",
"step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
"step1Trail": "Use a descriptive branch name: <code>feature/zfs-arc-tuning</code>, <code>feature/fix-iommu-detection</code>, <code>feature/add-tailscale-script</code>.",
"step2Lead": "<strong>Work on your changes and push the branch:</strong>",
"step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
"step3": "<strong>Open a Pull Request against <code>develop</code></strong> (not against <code>main</code>). On the GitHub PR creation page, double-check the base branch is set to <code>develop</code>. Include in the description: what the script does, what it changes, and which Proxmox VE versions you tested it on.",
"step4": "<strong>After review, changes are merged into <code>develop</code>.</strong> A maintainer reviews for code quality, header conventions, and the two-phase UI policy. They may request changes — push more commits to the same branch and the PR updates automatically.",
"step5": "<strong>Stable releases are merged from <code>develop</code> into <code>main</code>.</strong> When the maintainers cut a release, <code>develop</code> gets fast-forwarded into <code>main</code> and tagged. Your contribution becomes part of the next stable version."
},
"scriptHeader": {
"heading": "Script header — metadata & description",
"intro": "Every script in ProxMenux opens with two adjacent comment blocks that together form the header. They are <strong>both required</strong> — together they let any reader know who wrote the script and what it does, all without opening the code itself.",
"bullets": [
"<strong>Top block — metadata.</strong> Author, optional GitHub / Sponsor links, maintainer, copyright, license, version, last-updated date. This is also where <em>contributor recognition</em> happens: when you write a new script, your name goes here, and you can optionally include a link to your personal page (GitHub) and a sponsor profile (Ko-fi, GitHub Sponsors, Buy Me a Coffee, etc.).",
"<strong>Bottom block — description.</strong> A short paragraph in plain English explaining what the script does. This is what users read <em>before</em> opening the code — it must be self-contained enough that someone who only sees the header understands the purpose of the script. List the main actions, the resources affected, any prerequisites."
],
"licenseCalloutTitle": "The license line is fixed — GPL-3.0",
"licenseCalloutBody": "ProxMenux is published under the <strong>GNU General Public License v3.0</strong>. Every script in the project ships under that same license; the <code>License</code> line in the header is always the GPL-3.0 reference shown in the example below — it's not a per-script choice. By contributing a script you agree to release it under GPL-3.0, which means anyone can read it, modify it and redistribute it (including modifications) as long as they keep it under the same license. The full text lives at <licenseLink>MacRimi/ProxMenux/LICENSE</licenseLink>.",
"templateCode": "#!/bin/bash\n\n# ==========================================================\n# ProxMenux - A menu-driven script for Proxmox VE management\n# ==========================================================\n# Author : Your Name\n# GitHub : github.com/yourhandle\n# Sponsor : ko-fi.com/yourhandle\n# Maintainer : MacRimi\n# Copyright : (c) 2026 MacRimi & contributors\n# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)\n# Version : 1.0\n# Last Updated: DD/MM/YYYY\n# ==========================================================\n# Description:\n# Short paragraph explaining what the script does.\n# Mention the main actions (e.g. \"creates a ZFS pool\",\n# \"configures IOMMU and reboots\", \"imports an ISO into a VM\"),\n# the resources it touches, and any prerequisites the user\n# should be aware of before running it.\n# ==========================================================",
"optionalNote": "The <code>GitHub</code> and <code>Sponsor</code> lines are optional — leave them out if you don't want to publish them. Everything else is required.",
"whyCalloutTitle": "Why this matters",
"whyCalloutBody": "Open-source contribution is voluntary work. Putting the contributor's name and (when provided) sponsor link directly in the source gives the people who build the scripts visible recognition every time someone reads the code — your authorship is preserved, not hidden under “the project”. The description block matters for a different reason: it's the first thing a future maintainer or curious user reads, and a clear description is often the difference between a script people trust and one they avoid."
},
"structure": {
"heading": "Project structure",
"intro": "Where each kind of script lives in the repository:",
"treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
"outro": "Every script sources <code>utils.sh</code> at startup to get the message functions, the spinner, color variables and the translation system. Shared helper libraries (in <code>scripts/global/</code>) are sourced explicitly by the scripts that need them."
},
"twoPhase": {
"heading": "The two-phase UI design policy",
"intro": "This is the most important convention in ProxMenux and the one PRs are most often asked to fix. Every script is divided into <strong>exactly two phases</strong>:",
"headerPhase": "Phase",
"headerPurpose": "Purpose",
"headerScreen": "Screen state",
"rows": [
{
"phaseRich": "<strong>Phase 1 — Selection</strong>",
"purposeRich": "Collect every user decision. Run any preparatory work needed (probes, scans, checks).",
"screenRich": "<code>dialog</code> overlays. If a probe between two menus takes more than a second or two, show a <code>msg_info</code> spinner so the user knows the script hasn't frozen, then call <code>stop_spinner</code> right before the next dialog."
},
{
"phaseRich": "<strong>Phase 2 — Execution</strong>",
"purposeRich": "Execute every operation. Display the full progress history accumulating on screen.",
"screenRich": "Visible <code>msg_info</code> / <code>msg_ok</code> messages; never <code>dialog</code>."
}
],
"principle": "The principle: <strong>collect everything first, then execute everything</strong>. The user sees a clean dialog-driven menu (Phase 1), then a clean log-style execution view (Phase 2). No mixing — no dialog appearing mid-execution, no progress noise during selection.",
"phase1Heading": "Phase 1 — typical pattern",
"phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
"phase1RulesIntro": "<strong>Rules for Phase 1:</strong>",
"phase1Rules": [
"If a <code>msg_info</code> spinner is currently running and you need to open a <code>dialog</code> or <code>whiptail</code> menu, call <code>stop_spinner</code> first — the spinner can't coexist with the overlay drawn by either tool. If no spinner is active, you don't need to call it.",
"Use <code>show_proxmenux_logo</code> + <code>msg_title</code> + <code>msg_info</code> when you need to give the user visual context for a long-running operation in Phase 1 (e.g. a probe that takes 5+ seconds). The function includes a screen clear, so don't call <code>clear</code> before it.",
"Don't call <code>show_proxmenux_logo</code> between dialog menus where there's nothing to display — clearing the screen for an empty terminal is just visual noise.",
"Store all decisions and probe results in variables or parallel arrays. The visible recap happens at the start of Phase 2, not in Phase 1."
],
"phase2Heading": "Phase 2 — typical pattern",
"phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
"phase2Rules": "<strong>Rules for Phase 2:</strong> always start with <code>show_proxmenux_logo + msg_title</code>; immediately recap Phase 1 results as <code>msg_ok</code> lines; never call <code>show_proxmenux_logo</code> again (it would clear accumulated progress); never call <code>dialog</code> in Phase 2 — if a runtime decision is truly unavoidable, use <code>whiptail</code> (see next section)."
},
"dialogVsWhiptail": {
"headingRich": "When to use <code>dialog</code> vs <code>whiptail</code>",
"intro": "Both tools draw text-mode user interfaces, but they behave very differently on screen — and ProxMenux uses them in two distinct phases for a reason.",
"headerTool": "Tool",
"headerWhen": "When to use it",
"headerEffect": "Effect on screen",
"rows": [
{
"toolRich": "<strong><code>dialog</code></strong>",
"whenRich": "<strong>Always in Phase 1.</strong> Every interactive selection — picking a VM, a disk, a filesystem, confirming an action — uses <code>dialog</code>. This is the default UI tool of ProxMenux.",
"effectRich": "Takes over the terminal: clears the screen, draws its overlay, and on close returns the terminal to its prior state. Fine in Phase 1 because nothing useful is showing yet."
},
{
"toolRich": "<strong><code>whiptail</code></strong>",
"whenRich": "<strong>Only in Phase 2, only when unavoidable.</strong> The typical case is a reboot prompt at the end of execution. Don't reach for <code>whiptail</code> to ask “continue?” mid-execution — that decision should have been made in Phase 1.",
"effectRich": "Lighter-weight overlay that <em>does not</em> clear the terminal context. The accumulated <code>msg_ok</code> / <code>msg_info</code> history of Phase 2 stays visible behind the dialog box. That's why it's the right choice when progress is already on screen."
}
],
"calloutTitle": "Why the split matters",
"calloutBody": "If you call <code>dialog</code> in the middle of Phase 2, every <code>msg_ok</code> line the user has been watching disappears. You wipe the audit trail. <code>whiptail</code> avoids that. So the rule isn't arbitrary — it's about preserving the user's view of what the script has done so far.",
"rebootHeading": "Reboot prompt — the canonical Phase 2 whiptail",
"rebootIntro": "When a script ends and a reboot may be required (e.g. IOMMU enabled, kernel parameters changed), the prompt at the end of Phase 2 uses <code>whiptail</code>. Always include a “No” branch that warns the user not to use the affected resource until they reboot:",
"rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
},
"messageFunctions": {
"heading": "Message functions reference",
"intro": "All defined in <code>utils.sh</code>. Use them as the default for any user-visible output — consistent visuals across scripts is the whole point. If your script needs a new function that doesn't fit the existing set (a new severity level, a new layout helper, etc.), propose it in your Pull Request — it'll be reviewed and added to <code>utils.sh</code> if it's broadly useful.",
"headerFunction": "Function",
"headerWhen": "When to use",
"headerSpinner": "Spinner",
"rows": [
{
"function": "msg_info \"text\"",
"whenRich": "Operation in progress.",
"spinner": "Starts"
},
{
"function": "stop_spinner",
"whenRich": "End of silent preparatory work in Phase 1 — kills spinner, clears the line.",
"spinner": "Stops"
},
{
"function": "msg_ok \"text\"",
"whenRich": "Operation succeeded. Also use for “feature enabled” even when a reboot is required.",
"spinner": "Stops"
},
{
"function": "msg_warn \"text\"",
"whenRich": "Actual warning or degraded state.",
"spinner": "Stops"
},
{
"function": "msg_error \"text\"",
"whenRich": "Fatal error.",
"spinner": "Stops"
},
{
"function": "msg_info2 \"text\"",
"whenRich": "Non-blocking advisory (cyan info line).",
"spinner": "Stops"
},
{
"function": "msg_success \"text\"",
"whenRich": "Final “Press Enter to return” prompt at the end of Phase 2.",
"spinner": "Stops"
},
{
"function": "msg_title \"text\"",
"whenRich": "Bold title with built-in spacing. Used at the start of Phase 2.",
"spinner": "—"
},
{
"function": "show_proxmenux_logo",
"whenRich": "Clears screen, shows the logo. Called <em>once</em> at the start of Phase 2 only.",
"spinner": "—"
}
]
},
"dialogConventions": {
"heading": "dialog conventions",
"bullets": [
"Always pass <code>--backtitle \"$BACKTITLE\"</code> to every <code>dialog</code> and <code>whiptail</code> call. <code>$BACKTITLE</code> is always <code>\"ProxMenux\"</code> — set once at the script header and never overridden. The user must always see the project name as the framing context, never the script's own title.",
"Always wrap titles and messages with <code>$(translate \"...\")</code>.",
"Always redirect <code>dialog</code> output with <code>2&gt;&amp;1 &gt;/dev/tty</code> — the captured stdout becomes the user's selection, while the dialog itself draws on the terminal.",
"Use the standard UI dimension variables (<code>$UI_MENU_H</code>, <code>$UI_MSG_W</code>, etc.) for consistent sizing across scripts.",
"Always check for empty / cancelled selections and handle them gracefully."
],
"exampleIntro": "Complete example — building a VM-selection menu and handling cancellation:",
"exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
},
"translation": {
"heading": "Translation policy",
"intro": "All user-visible strings must be wrapped with the <code>translate</code> function. ProxMenux translates them automatically into all supported languages — you write English, the user reads their native language.",
"code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
"bullets": [
"Write strings in English — translation is handled automatically by the build.",
"Keep strings concise. Avoid embedding variables inside long sentences where possible.",
"Do <strong>not</strong> translate variable names, paths or technical identifiers."
]
},
"variableStyle": {
"heading": "Variable & style conventions",
"bullets": [
"Use <code>UPPER_CASE</code> for script-level variables.",
"Use <code>lower_case</code> for local function variables (declare with <code>local</code>).",
"Quote all variable expansions: <code>\"$VAR\"</code> — not <code>$VAR</code>.",
"Use <code>[[ ]]</code> for conditionals, not <code>[ ]</code> (except where POSIX is required).",
"<code>show_proxmenux_logo</code> is the appropriate way to clear the screen — it includes the clear and shows the project logo so the user always has visual context. Call it once at the start of Phase 2 (and optionally before a long Phase 1 spinner block)."
],
"standardNamesIntro": "Standard variable names across the project:",
"standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
"redirectHeading": "Redirecting tool output during Phase 2",
"redirectIntro": "Phase 2 displays a clean log of <code>msg_info → msg_ok</code> lines accumulating on screen. If a tool you call (apt, mkfs, qm, pct, dd, etc.) writes its own output to stdout/stderr, it scrolls past your messages and breaks the visual flow — you end up with a chaotic terminal where the user can't tell the script's own progress lines from the underlying tool's noise.",
"withoutRedirectIntro": "<strong>Without redirect</strong> — what the user sees if you don't handle the noise:",
"withoutRedirectCode": " Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
"withRedirectIntro": "<strong>With redirect</strong> — what the same operation looks like when noise is sent elsewhere:",
"withRedirectCode": " Installing kernel package...\n✓ Kernel installed.\n Configuring kernel command line...\n✓ Configured.\n Refreshing boot loader...\n✓ Boot loader updated.",
"twoPatternsIntro": "Two patterns to choose from:",
"discardLead": "<strong>Discard the output</strong> when you don't need it — fastest, simplest:",
"discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
"logLead": "<strong>Send the output to a log file</strong> when you may want to inspect it later (debugging a failed install, checking what dpkg actually did). This is the preferred pattern for any apt operation:",
"logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
"referenceOutro": "The script <code>scripts/global/update-pve9_2.sh</code> is a reference implementation — every <code>apt-get</code> call sends output to a log file so the user only sees the clean <code>msg_info → msg_ok</code> flow, while the log on disk lets you reconstruct exactly what apt did if anything goes wrong."
},
"dosAndDonts": {
"heading": "Do's and Don'ts",
"doHeading": "✅ Do",
"doBullets": [
"<code>stop_spinner</code> before a <code>dialog</code> in Phase 1 only when a <code>msg_info</code> spinner is currently running.",
"Phase 2 starts with <code>show_proxmenux_logo + msg_title + msg_ok</code> recap of Phase 1 results.",
"Use <code>msg_ok</code> for successfully enabled features — even if a reboot is required.",
"Use <code>whiptail</code> (not <code>dialog</code>) for any post-execution prompt that must appear in Phase 2.",
"Always include a “No” branch in reboot dialogs that warns the user not to start the affected resource until rebooted.",
"Guard VM-only logic by checking <code>[[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]]</code> — controllers and NVMe PCIe can't be added to LXC containers.",
"Use <code>ensure_repositories</code> from <code>utils-install-functions.sh</code> instead of unconditional <code>apt-get update</code>.",
"Use parallel arrays in Phase 1 when each item needs multiple dialogs."
],
"dontHeading": "❌ Don't",
"dontBullets": [
"Call <code>dialog</code> while a spinner is active.",
"Skip the Phase 1 recap at the start of Phase 2.",
"Call <code>show_proxmenux_logo</code> a second time — it erases everything Phase 2 has printed.",
"Use <code>dialog</code> in Phase 2 (use <code>whiptail</code> for the rare unavoidable case).",
"Use bare <code>clear</code>.",
"Wrap <code>msg_title</code> in <code>echo \"\"</code> blank lines — it already includes spacing.",
"Use <code>msg_warn</code> to report a successfully enabled feature — that's an <code>msg_ok</code>.",
"Run unconditional <code>apt-get update</code> — use <code>ensure_repositories</code>."
]
},
"submitting": {
"heading": "Submitting your contribution",
"steps": [
"Fork <code>MacRimi/ProxMenux</code> on GitHub and clone your fork.",
"Create a <code>feature/*</code> branch from <code>develop</code> (see <em>Branching model</em> above).",
"Follow this guide for any new or modified scripts. Write the header with your name; add the optional sponsor line if you want.",
"Test your script on a real Proxmox VE instance — both Phase 1 (every dialog branch) and Phase 2 (every operation succeeds and rolls back cleanly on error).",
"Open a Pull Request <strong>against <code>develop</code></strong> with a clear description: what the script does, what changed, which Proxmox VE version it was tested on.",
"Make sure your contribution respects the <cocLink>Code of Conduct</cocLink>."
],
"securityOutro": "For security-sensitive issues, follow the disclosure flow in <securityLink>SECURITY.md</securityLink> rather than opening a public issue."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"kind": "external",
"url": "https://github.com/MacRimi/ProxMenux/blob/main/CONTRIBUTING.md",
"label": "CONTRIBUTING.md (full guide)",
"tail": " — the source of truth for every convention, including the advanced hardware patterns."
},
{
"kind": "internal",
"href": "/docs/about/contributors",
"label": "Contributors",
"tail": " — the people whose work has shaped ProxMenux releases. (Different page from this one.)"
},
{
"kind": "internal",
"href": "/docs/about/code-of-conduct",
"label": "Code of Conduct",
"tail": " — the standards every contributor agrees to follow."
},
{
"kind": "external",
"url": "https://github.com/MacRimi/ProxMenux/discussions",
"label": "GitHub Discussions",
"tail": " — ask before you build if you're not sure whether an idea fits, or to find collaborators on a larger feature."
}
]
}
}
@@ -0,0 +1,38 @@
{
"meta": {
"title": "Contributors | ProxMenux Documentation",
"description": "Recognition for the people who make ProxMenux possible — testers, reviewers and developers who shape each release.",
"ogTitle": "Contributors | ProxMenux Documentation",
"ogDescription": "Meet the contributors behind ProxMenux."
},
"header": {
"title": "Contributors",
"description": "The ProxMenux project grows and thrives thanks to the contribution of its collaborators. This is the well-deserved recognition of their work — testing builds before release, catching regressions, reviewing PRs and shaping the direction of new features.",
"section": "About"
},
"beyond": {
"title": "Beyond this list",
"body": "Many more people contribute via bug reports, feature ideas in Discussions, beta testing and translations. The full list of code contributors lives on the <extlink>GitHub contributors graph</extlink>. The page below highlights the people who have been most actively involved in testing and reviewing ProxMenux releases."
},
"testers": {
"heading": "Testers & reviewers",
"intro": "These were among the first to contribute to the project — testing, reporting issues and suggesting improvements that helped ProxMenux grow into what it is today.",
"roles": {
"testing": "Testing",
"testingReviewer": "Testing & reviewer"
},
"youtube": "YouTube"
},
"contribute": {
"heading": "Want to contribute?",
"intro": "Any contribution is welcome — code, testing, design, documentation, or just sharing your ideas:",
"tester": "<strong>Tester</strong> — try the <beta>beta channel</beta> and report what works and what doesn't before stable releases.",
"developer": "<strong>Developer</strong> — Bash + Next.js (TypeScript) + a bit of Python for the translation venv. PRs welcome on <gh>GitHub</gh>.",
"designer": "<strong>Designer</strong> — UI improvements, icons, screenshots for documentation.",
"ideas": "<strong>Ideas</strong> — open a thread in <disc>GitHub Discussions</disc> before opening a feature request issue."
},
"coc": {
"title": "Read the Code of Conduct first",
"body": "Before submitting code or reporting issues, give the <coclink>Code of Conduct & Best Practices</coclink> a quick read. It covers expectations around code responsibility, security disclosure and PR scope."
}
}
+94
View File
@@ -0,0 +1,94 @@
{
"meta": {
"title": "FAQ | ProxMenux Documentation",
"description": "Frequently asked questions about ProxMenux: what it is, install, compatibility (PVE 8+ only), customisation, updates, security, production use, system file safety, contributing, uninstall.",
"ogTitle": "FAQ | ProxMenux Documentation",
"ogDescription": "Frequently asked questions about ProxMenux installation, compatibility, security and contributing."
},
"header": {
"title": "Frequently Asked Questions",
"description": "Common questions about ProxMenux: what it is, who it's for, how to install / update / uninstall, compatibility, customisation, security and contributing. If your question isn't here, check the GitHub Discussions or open an issue.",
"section": "About"
},
"quickLinks": {
"title": "Quick links",
"installationLabel": "Installation",
"installationSuffix": " — the one-line install command + dependencies.",
"introductionLabel": "Introduction",
"introductionSuffix": " — what ProxMenux does, in 5 minutes.",
"uninstallLabel": "Uninstall",
"uninstallSuffix": " — clean removal.",
"issuesLabel": "GitHub Issues",
"discussionsLabel": "Discussions"
},
"q1": {
"question": "What is ProxMenux, and what is it used for?",
"p1Rich": "<strong>ProxMenux</strong> is an interactive menu-driven tool designed to make <strong>Proxmox VE</strong> accessible to all users, regardless of their technical experience. It simplifies command execution, allowing users to perform actions on their system without requiring advanced Linux knowledge.",
"p2": "For less experienced users, ProxMenux provides an intuitive way to run commands through a structured menu interface, reducing the need for manual terminal input. For seasoned admins, it cuts keystrokes for repetitive workflows (post-install hardening, GPU passthrough, OVF VM imports, ZFS snapshot rotations).",
"p3": "Proxmox VE is widely used for:",
"items": [
"Enterprise-grade virtualization",
"HomeLab and personal cloud solutions",
"Multimedia servers, automation, and more"
]
},
"q2": {
"question": "How do I install ProxMenux?",
"p1Rich": "Follow the <installlink>Installation Guide</installlink>. In short:",
"stableInstall": "bash -c \"$(wget -qLO - https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh)\"",
"p2": "Once installed, simply start it with:",
"menuCmd": "menu"
},
"q3": {
"question": "Is ProxMenux compatible with all Proxmox versions?",
"bodyRich": "<strong>No — ProxMenux requires Proxmox VE 8 or later.</strong> PVE 7 and earlier are not supported. If you're still on PVE 7, follow the official Proxmox upgrade procedure to 8.x first; ProxMenux can then handle the 8 → 9 jump for you via <upgradelink>Utilities → Upgrade PVE 8 to PVE 9</upgradelink>."
},
"q4": {
"question": "Can I customise ProxMenux?",
"p1Rich": "The core scripts can't be modified directly because they're hosted on GitHub and refreshed by the auto-update flow. What you <em>can</em> customise:",
"items": [
"The console banner via the <strong>FastFetch</strong> tool in the Post-Install options.",
"Which optional components are installed (Monitor, Fail2Ban, Lynis…) — pick during install or via the relevant menu later."
]
},
"q5": {
"question": "How do I update ProxMenux?",
"p1Rich": "When a new version is available, ProxMenux detects it on the next <code>menu</code> launch and prompts you to update. Accepting replaces the utility files and configurations in place. No manual download needed.",
"p2Rich": "Stable users get stable releases; beta users get beta releases. When a stable version is published, ProxMenux notifies beta users on the next launch and offers to switch automatically — see the <betalink>Beta Program</betalink> page."
},
"q6": {
"question": "Where can I report issues?",
"p1Rich": "Bug reports go on <issueslink>GitHub Issues</issueslink>. Include reproduction steps, error messages and (for Monitor-related issues) the output of <code>journalctl -u proxmenux-monitor -n 50</code>.",
"p2Rich": "For <strong>security</strong> issues, please <strong>do not publish them</strong>. Read the <coclink>Code of Conduct & Best Practices</coclink> for the responsible disclosure procedure."
},
"q7": {
"question": "Can I contribute to ProxMenux?",
"p1Rich": "<strong>Absolutely.</strong> ProxMenux is open source and collaborative. Contributions can be code (bash, Next.js / TypeScript, the translation Python venv), testing, documentation, design, or just ideas.",
"item1Rich": "Discuss ideas in <discusslink>GitHub Discussions</discusslink> before opening a feature request.",
"item2Rich": "For PRs, read the <coclink>Code of Conduct & Best Practices</coclink> first.",
"item3Rich": "See the <contriblink>Contributors page</contriblink> for current testers and reviewers."
},
"q8": {
"question": "Does ProxMenux modify critical system files?",
"p1Rich": "<strong>No.</strong> ProxMenux installs:",
"item1Rich": "Dependencies via apt: <code>dialog</code>, <code>curl</code>, <code>jq</code>, <code>git</code> (and <code>python3</code> + <code>googletrans</code> on the Translation install).",
"item2Rich": "The script tree at <code>/usr/local/share/proxmenux/</code>.",
"item3Rich": "The launcher at <code>/usr/local/bin/menu</code>.",
"item4Rich": "Optional: the Monitor systemd service at <code>proxmenux-monitor.service</code>.",
"p2Rich": "ProxMenux does <em>not</em> touch Proxmox's core configuration unless you explicitly ask for it via a dedicated menu (e.g. the network repair flow edits <code>/etc/network/interfaces</code> — but only after you confirm and a backup is taken)."
},
"q9": {
"question": "Is it safe to use ProxMenux in production?",
"bodyRich": "<strong>Yes.</strong> Since ProxMenux doesn't modify core Proxmox files unless explicitly asked, it can be used in production environments. As with any automation, test in a controlled environment first and have backups before running destructive flows (PVE 8 → 9 upgrade, disk format, VM destroy…)."
},
"q10": {
"question": "How do I uninstall ProxMenux?",
"p1Rich": "From inside ProxMenux: <strong>Settings → Uninstall ProxMenux</strong>. The uninstaller removes the script tree, the launcher and the Monitor service, optionally removes selected dependencies, and restores <code>/root/.bashrc</code> and <code>/etc/motd</code> backups taken at install time.",
"p2Rich": "Full step-by-step: <uninstalllink>Uninstall ProxMenux</uninstalllink>."
},
"q11": {
"question": "VirusTotal flags the install URL — is it safe?",
"p1Rich": "A 1/95 detection by heuristic engines (e.g. <em>Chong Lua Dao</em>) is a known false positive. The installer uses the standard <code>curl | bash</code> pattern and downloads legitimate binaries (like <code>jq</code> from its official GitHub release), which aggressive scanners flag based on <em>behaviour</em> rather than actual malicious code.",
"p2Rich": "ProxMenux is 100% open source and the install script is reviewable line by line: <scriptlink>install_proxmenux.sh</scriptlink>. More context in <issuelink>Issue #162</issuelink>."
}
}
+67
View File
@@ -0,0 +1,67 @@
{
"meta": {
"title": "About | ProxMenux Documentation",
"description": "About ProxMenux: project goals, contributors, FAQ and Code of Conduct. Open-source menu-driven management tool for Proxmox VE 8+, built and maintained by MacRimi with a small team of testers and contributors.",
"ogTitle": "About | ProxMenux Documentation",
"ogDescription": "About ProxMenux — open-source menu-driven management tool for Proxmox VE 8+."
},
"header": {
"title": "About",
"description": "Project info, FAQ, contributors and code of conduct. ProxMenux is an open-source menu-driven management tool for Proxmox VE 8+, built and maintained by MacRimi with the help of a small team of testers and contributors.",
"section": "About"
},
"callout": {
"title": "Open source, community-driven",
"body": "ProxMenux is GPL-3.0 licensed and developed in the open on GitHub. Every script is reviewable, every change traceable. Contributions — bug reports, ideas, code, testing — are welcome."
},
"section": {
"heading": "In this section",
"options": [
{
"icon": "HelpCircle",
"href": "/docs/about/faq",
"title": "FAQ",
"description": "Frequently asked questions: what ProxMenux is, install, compatibility, customisation, updates, security, production use, uninstall."
},
{
"icon": "Users",
"href": "/docs/about/contributors",
"title": "Contributors",
"description": "Recognition for the people who make ProxMenux possible — testers, reviewers and developers who shape each release."
},
{
"icon": "ScrollText",
"href": "/docs/about/code-of-conduct",
"title": "Code of Conduct",
"description": "Project values, code-responsibility expectations and contribution guidelines. Required reading before opening a PR or report."
}
]
},
"involved": {
"heading": "Get involved",
"intro": "Three places to engage with the project:",
"cards": [
{
"href": "https://github.com/MacRimi/ProxMenux/issues/new",
"title": "🐛 Report a bug",
"description": "GitHub Issues — include logs and reproduction steps."
},
{
"href": "https://github.com/MacRimi/ProxMenux/discussions",
"title": "💡 Suggest a feature",
"description": "GitHub Discussions — share ideas before opening a PR."
},
{
"href": "https://github.com/MacRimi/ProxMenux/pulls",
"title": "🔀 Submit a PR",
"description": "GitHub Pull Requests — read the Code of Conduct first."
}
]
},
"support": {
"heading": "Support the project",
"introRich": "If ProxMenux saves you time, the easiest way to help others discover it is to <starlink>give the repo a ⭐ on GitHub</starlink>. If you want to go further:",
"kofiLabel": "Support on Ko-fi",
"kofiOutro": " — buys the maintainer a coffee and keeps development going."
}
}
+175
View File
@@ -0,0 +1,175 @@
{
"meta": {
"title": "Create VMs on Proxmox VE — Synology, Windows, Linux, NAS Wizards | ProxMenux",
"description": "Create and configure virtual machines on Proxmox VE with ProxMenux. Dedicated wizards for NAS appliances (Synology DSM, TrueNAS, OpenMediaVault, UnRAID, etc.), Windows, Linux distros, and an external macOS installer. Sensible defaults for VM hardware, storage and networking.",
"ogTitle": "Create VMs on Proxmox VE — Synology, Windows, Linux, NAS Wizards",
"ogDescription": "ProxMenux wizards for creating Synology DSM, TrueNAS, OMV, UnRAID, Windows and Linux VMs on Proxmox VE.",
"ogImageAlt": "ProxMenux Create VM Menu",
"twitterTitle": "Create VMs on Proxmox VE | ProxMenux",
"twitterDescription": "Wizards for Synology, TrueNAS, OMV, UnRAID, Windows and Linux VMs on Proxmox VE."
},
"header": {
"title": "Create VM",
"description": "ProxMenux groups VM creation into an interactive dispatcher. Pick the operating system family and the matching wizard handles ISO selection, CPU, RAM, BIOS, network, storage and — optionally — GPU passthrough.",
"section": "Virtual Machines"
},
"intro": {
"title": "What this menu is for",
"body": "The Create VM menu is a router, not a single wizard. It asks which operating system family you want to install and loads the appropriate ISO selector and configurator. Default flows use sensible ProxMenux presets; Advanced flows expose every configurable option before the VM is created."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, select <strong>Create VM</strong>. You will see this:",
"imageAlt": "Create VM dispatcher with 3 ProxMenux options (NAS / Windows / Linux) followed by the Community Scripts section (macOS / Others)"
},
"families": {
"heading": "Three OS families",
"intro": "The three ProxMenux entries at the top of the menu share the same underlying engine and post-ISO flow — they just route to different ISO selectors and apply defaults tuned for each family. Pick the one that matches the guest you want to install.",
"routes": [
{
"key": "nas",
"title": "System NAS",
"icon": "HardDrive",
"href": "/docs/create-vm/system-nas",
"accent": "border-emerald-300 bg-emerald-50",
"iconBg": "bg-emerald-100 text-emerald-700",
"description": "Seven NAS operating systems as dedicated VMs. Most use the auto-ISO flow; Synology DSM runs the specialised loader wizard.",
"bullets": [
"Synology DSM (ARC / RR / TinyCore loaders)",
"TrueNAS SCALE and CORE (ZFS)",
"OpenMediaVault (Debian-based)",
"XigmaNAS (FreeBSD ZFS)",
"Rockstor (openSUSE / Btrfs), ZimaOS"
]
},
{
"key": "windows",
"title": "System Windows",
"icon": "MonitorCog",
"href": "/docs/create-vm/system-windows",
"accent": "border-blue-300 bg-blue-50",
"iconBg": "bg-blue-100 text-blue-700",
"description": "Windows 10, 11 and Server editions with Windows-friendly defaults (q35 + OVMF + TPM 2.0) and VirtIO drivers pre-mounted.",
"bullets": [
"UUP Dump for up-to-date ISOs",
"Or local ISO from /var/lib/vz/template/iso",
"TPM 2.0 added automatically",
"VirtIO drivers ISO attached to ide3",
"Guest agent channel enabled"
]
},
{
"key": "linux",
"title": "System Linux",
"icon": "Laptop",
"href": "/docs/create-vm/system-linux",
"accent": "border-amber-300 bg-amber-50",
"iconBg": "bg-amber-100 text-amber-700",
"description": "Curated catalogue of official Linux ISOs auto-downloaded from upstream, plus a local-ISO picker for anything else.",
"bullets": [
"Ubuntu (Desktop / Server, 20.0425.10)",
"Debian (Desktop / Netinst, 1113)",
"Fedora, Arch, Rocky, Mint, openSUSE",
"Alpine, Kali, Manjaro",
"Local ISO path for custom images"
]
}
]
},
"community": {
"title": "Community scripts (not documented here)",
"intro": "The two entries below the <em>Community Scripts</em> separator run code that is <strong>not part of ProxMenux</strong>, so they are intentionally left outside this documentation:",
"macosRich": "<strong>System macOS</strong> — runs the external <osxLink>OSX-PROXMOX</osxLink> installer. It clones the upstream repository, prepares the host and <strong>reboots automatically when finished</strong>. Refer to the project's own documentation.",
"othersRich": "<strong>System Others (Linux-based)</strong> — loads a curated list of community Linux-based installers (home-server OSes, router/firewall appliances, etc.). Each community script is maintained outside ProxMenux."
},
"afterPick": {
"heading": "What happens after you pick an OS",
"intro": "Once the ISO is selected, the dispatcher takes the same path regardless of OS family:",
"items": [
"<strong>Default vs Advanced.</strong> A confirmation dialog lets you accept ProxMenux presets or open the full configurator (CPU model/cores, RAM, BIOS/UEFI, NIC model, machine type).",
"<strong>Storage plan.</strong> You combine one or several virtual disks, imported disks and PCI passthrough devices (whole controller / NVMe) in the same VM.",
"<strong>Optional GPU passthrough.</strong> If a compatible GPU is detected on the host, ProxMenux offers to launch the GPU assistant after the VM is created — a reboot may be required.",
"<strong>VM creation.</strong> The VM is built, tagged, and a styled HTML description is attached to it for quick reference in the Proxmox UI."
],
"tipTitle": "Prefer Advanced for VMs you intend to keep",
"tipBody": "Default presets work well for quick tests. For a VM you intend to keep, the Advanced path lets you pick the right BIOS (SeaBIOS vs OVMF/UEFI), machine type (<code>i440fx</code> vs <code>q35</code>) and disk controller (VirtIO SCSI single vs SATA) up front — these are painful to change later."
},
"scripts": {
"heading": "Scripts involved",
"intro": "The dispatcher sources several shared component scripts not documented as individual pages. They are listed here for reference. Each sub-page links to the main script relevant to its flow.",
"headerScript": "Script",
"headerRole": "Role",
"rows": [
{
"path": "menus/create_vm_menu.sh",
"role": "Entry point dispatcher."
},
{
"path": "vm/select_nas_iso.sh",
"role": "ISO / appliance selector for NAS systems (Synology, TrueNAS, OMV, Rockstor, ZimaOS)."
},
{
"path": "vm/select_windows_iso.sh",
"role": "Windows ISO selector. Delegates to the UUP Dump builder when needed."
},
{
"path": "vm/select_linux_iso.sh",
"role": "Linux ISO selector for the Linux flow (mainstream distributions)."
},
{
"path": "vm/synology.sh",
"role": "Synology DSM flow: fetches loader and DSM image and prepares the VM profile."
},
{
"path": "vm/zimaos.sh",
"role": "ZimaOS flow: downloads the image and wires it into the VM definition."
},
{
"path": "vm/vm_configurator.sh",
"role": "Default vs Advanced wizard: CPU model/cores, RAM, BIOS, NIC, machine type."
},
{
"path": "vm/disk_selector.sh",
"role": "Storage plan: virtual disk, disk import, or Controller/NVMe passthrough."
},
{
"path": "vm/vm_creator.sh",
"role": "Final VM creation: applies the config, attaches storage, writes the HTML description."
},
{
"path": "vm/guest_agent_config.sh",
"role": "Optional QEMU guest agent setup hook, used by several flows."
}
]
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager",
"label": "Disk Manager",
"tail": " — attach existing physical disks or import disk images into VMs."
},
{
"href": "/docs/utils/UUp-Dump-ISO-Creator",
"label": "UUP Dump ISO Creator",
"tail": " — generate Windows install ISOs ready to use as boot media."
},
{
"href": "/docs/utils/import-vm",
"label": "Import VM from OVA / OVF",
"tail": " — bring in pre-built VMs from VMware / VirtualBox / ProxMenux exports."
},
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — pass a GPU into a freshly-created VM."
},
{
"href": "/docs/help-info/vm-ct-commands",
"label": "VM and CT Management commands",
"tail": " — qm reference for the CLI side."
}
]
}
}
@@ -0,0 +1,452 @@
{
"title": "Synology VM Creator Script",
"intro": {
"heading": "Introduction",
"intro": "ProxMenux provides an automated script that creates and configures a virtual machine (VM) to install Synology DSM (DiskStation Manager) on Proxmox VE. This script simplifies the process by downloading and adding one of the available loaders to the VM boot, giving you the option between four different choices:",
"loaders": [
{
"name": "AuxXxilium Arc",
"url": "https://github.com/AuxXxilium/arc",
"extra": ""
},
{
"name": "RedPill RR",
"url": "https://github.com/RROrg/rr",
"extra": ""
},
{
"name": "TinyCore RedPill M-shell",
"url": "https://github.com/PeterSuh-Q3/tinycore-redpill",
"extra": ""
}
],
"customLoader": "Custom Loader option to use a custom loader if you prefer to modify or create your own configuration",
"simplifiesIntro": "The script simplifies the VM creation process by offering the following options:",
"simplifies": [
"Selection of default or advanced configuration",
"Configuration of CPU, RAM, BIOS, and machine type",
"Choice between virtual disk or physical disk passthrough"
]
},
"config": {
"heading": "Default and Advanced Configuration",
"intro": "The script offers two configuration modes:",
"defaultHeading": "Default Configuration",
"defaultIntro": "If you select default configuration, the script will automatically apply the following values:",
"headerParam": "Parameter",
"headerValue": "Default Value",
"defaultRows": [
{
"param": "Machine Type",
"value": "q35"
},
{
"param": "BIOS Type",
"value": "OVMF (UEFI)"
},
{
"param": "CPU Type",
"value": "Host"
},
{
"param": "Core Count",
"value": "2"
},
{
"param": "RAM Size",
"value": "4096 MB"
},
{
"param": "Bridge",
"value": "vmbr0"
},
{
"param": "MAC Address",
"value": "Automatically generated"
},
{
"param": "Start VM on Completion",
"value": "No"
}
],
"defaultOutro": "If you want to customize the configuration, select the Advanced Settings option in the menu.",
"advancedHeading": "Advanced Configuration",
"advancedIntro": "If you select advanced configuration, the script will allow you to customize each parameter:",
"headerOptions": "Options",
"advancedRows": [
{
"param": "Machine Type",
"options": "q35 or i440fx"
},
{
"param": "BIOS Type",
"options": "OVMF (UEFI) or SeaBIOS (Legacy)"
},
{
"param": "CPU Type",
"options": "Host or KVM64"
},
{
"param": "Core Count",
"options": "Number of CPU cores"
},
{
"param": "RAM Size",
"options": "Amount of memory allocated to the VM"
},
{
"param": "Bridge",
"options": "Network bridge for connection"
},
{
"param": "MAC Address",
"options": "Custom MAC address"
},
{
"param": "VLAN",
"options": "VLAN tag (if used)"
},
{
"param": "MTU",
"options": "Maximum Transmission Unit size"
}
]
},
"diskSelection": {
"heading": "Disk Selection",
"intro": "Once the machine is configured, the script allows you to choose between two types of disks:",
"virtualHeading": "Virtual Disk",
"virtualItems": [
"The script lists the storage options available in Proxmox",
"The user selects the disk and size in GB",
"The virtual disk is automatically assigned to the VM. If more disks are configured, they will be added as <strong>SATA</strong> (e.g., sata0, sata1, etc.), up to a maximum of 6 virtual disks."
],
"physicalHeading": "Physical Disk Passthrough",
"physicalItems": [
"The script detects all available physical disks",
"The user selects the physical disk or disks they want to use.",
"The physical disk is directly assigned to the VM via passthrough. If more disks are configured, they will be added as <strong>SATA</strong> (e.g., sata0, sata1, etc.), up to a maximum of 6 physical disks."
]
},
"loaderInstall": {
"heading": "Loader Installation",
"intro1": "The script automatically downloads and extracts the loader from the developer's repository. If the download fails, the script will display an error message.",
"intro2Rich": "<strong>AuxXxilium Arc</strong>, <strong>RedPill RR</strong>, and <strong>TinyCore RedPill M-shell</strong>. Downloads and extracts automatically.",
"customRich": "For <strong>Custom Loader</strong>, the script searches for files in <code>/var/lib/vz/template/iso</code>. If multiple files are found, you will be prompted to select the desired file.",
"uploadIntro": "You can upload custom loaders from the local storage options:",
"imageAlt": "Add Custom Loader",
"imageCaption": "Add Custom Loader"
},
"vmCreation": {
"heading": "VM Creation",
"intro": "Once the loader is downloaded, the script creates the VM using the following commands:",
"items": [
"<code>qm create</code> Creates the virtual machine with the configured parameters",
"<code>qm importdisk</code> Imports the boot loader disk to the VM. For greater compatibility the loader is imported as an IDE disk",
"<code>qm set</code> Assigns configuration values such as CPU, RAM, and storage",
"<code>qm set -boot</code> Configures the boot order"
]
},
"stepGuide": {
"heading": "Step-by-Step Boot Loader Configuration Guide",
"intro": "While all loaders share similarities, each one has its own structure and configuration methods. This section provides a basic guide covering the 6 steps involved in setting up a Synology DSM loader. The exact steps may vary depending on the loader and any changes introduced by the developer. Therefore, understanding these common basic steps is crucial to correctly building and configuring the loader of your choice for proper Synology DSM functionality.",
"selectorHeading": "Select your loader type:",
"loaderButtons": {
"arc": "Arc Loader",
"rr": "RR Loader",
"tinycore": "TinyCore Loader"
}
},
"steps": [
{
"id": "step1",
"title": "Start the VM and Access the Main Menu",
"intro": "Once the VM is created, start it. The first time you boot the VM, you'll access the loader's main menu to select and configure the DSM model you want to build. Once the loader is created, this step will be skipped unless you manually force a reconfiguration from the boot monitor. All loaders also have the option to configure the loader via a web interface.",
"loaders": {
"arc": [
{
"htmlBefore": "<strong>Web interface</strong>, To access the web interface, simply open a web browser and enter the IP address shown in the VM's console output. For example, in our case: http://192.169.0.32.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_0_1.png",
"alt": "Arc Loader Web Interface",
"caption": "Arc Loader Web Interface"
},
{
"htmlBefore": "<strong>Terminal interface</strong>, Access it directly from the VM's console output.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_1_1.png",
"alt": "Arc Loader Terminal Interface",
"caption": "Arc Loader Terminal Interface"
}
],
"rr": [
{
"htmlBefore": "<strong>Web interface</strong>, To access the web interface, simply open a web browser and enter the IP address shown in the VM's console output, followed by port <strong>7681</strong>. For example, in our case: <code>http://192.169.0.33:7681</code>.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_0_2.png",
"alt": "RR Command Example",
"caption": "RR Loader Web Interface"
},
{
"htmlBefore": "<strong>Terminal interface</strong>, Access it directly from the VM's console output by typing <strong>menu.sh</strong> on the screen",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_1_1.png",
"alt": "RR Loader Interface",
"caption": "RR Loader Terminal Interface"
}
],
"tinycore": [
{
"htmlBefore": "<strong>Web interface</strong>, To access the web interface, simply open a web browser and enter the IP address shown in the VM's console output, followed by port <strong>7681</strong>. For example, in our case: <code>http://192.169.0.35:7681</code>.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_0_1.png",
"alt": "TinyCore Loader Interface",
"caption": "TinyCore Loader Web Interface"
},
{
"htmlBefore": "<strong>Terminal interface</strong>, Access it directly from the VM's console output. Keep an eye on the screen, as at some point it may prompt you to press a key to continue or ask if you want to change the language.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_1_1.png",
"alt": "TinyCore Loader Interface",
"caption": "TinyCore Loader Terminal Interface"
}
]
}
},
{
"id": "step2",
"title": "Select Model",
"intro": "After loading the menu, select the Synology DSM model you want to install. Depending on the loader, you may sometimes need to expand the options to see more models.",
"outro": "In our example, we'll choose the SA6400 model.",
"loaders": {
"arc": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_2_1.png",
"alt": "Arc Model Selection",
"caption": "Arc Model Selection"
}
],
"rr": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_2_1.png",
"alt": "RR Model Selection",
"caption": "RR Model Selection"
}
],
"tinycore": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_2_1.png",
"alt": "TinyCore Model Selection",
"caption": "TinyCore Model Selection"
}
]
}
},
{
"id": "step3",
"title": "Select DSM Version",
"intro": "After selecting the model, you need to choose the DSM version you want to install.",
"loaders": {
"arc": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_3_1.png",
"alt": "Arc Version Selection - Step 1",
"caption": "Arc Version Selection - Step 1"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_3_2.png",
"alt": "Arc Version Selection - Step 2",
"caption": "Arc Version Selection - Step 2"
}
],
"rr": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_3_1.png",
"alt": "RR Version Selection - Step 1",
"caption": "RR Version Selection - Step 1"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_3_2.png",
"alt": "RR Version Selection - Step 2",
"caption": "RR Version Selection - Step 2"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_3_3.png",
"alt": "RR Version Selection - Step 3",
"caption": "RR Version Selection - Step 3"
}
],
"tinycore": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_3_1.png",
"alt": "TinyCore Version Selection - Step 1",
"caption": "TinyCore Version Selection - Step 1"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_3_2.png",
"alt": "TinyCore Version Selection - Step 2",
"caption": "TinyCore Version Selection - Step 2"
}
]
}
},
{
"id": "step4",
"title": "Select Addons",
"intro": "This step allows you to add additional features or custom configurations to the loader.",
"loaders": {
"arc": [
{
"htmlBefore": "<strong>Arc</strong> gives you the option to configure automatically or manually adjust the settings. If automatic configuration is selected, the loader will start applying the necessary settings and will automatically reboot once the process is complete.",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_4_1.png",
"alt": "Arc Auto Configuration",
"caption": "Arc Auto Configuration"
},
{
"htmlBefore": "If we choose not to use automatic mode, we enter the menu to configure different options necessary for the loader:",
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_4_2.png",
"alt": "Arc Manual Configuration",
"caption": "Arc Manual Configuration"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_4_3.png",
"alt": "Arc SN/Mac Configuration",
"caption": "Arc SN/Mac Configuration"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_4_4.png",
"alt": "Arc Sata Portmap",
"caption": "Arc Sata Portmap (use the recommended option)"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_4_5.png",
"alt": "Arc Addons Selection",
"caption": "Arc Addons Selection"
}
],
"rr": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_4_1.png",
"alt": "RR Addon Step 1",
"caption": "RR Addon Step 1"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_4_2.png",
"alt": "RR Addon Step 2",
"caption": "RR Addon Step 2 - Press to add addons"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_4_3.png",
"alt": "RR Addon Step 3",
"caption": "RR Addon Step 3 - Select the one you want by clicking on it. If you want to add more, repeat the process from images 2.4.2 and 2.4.3"
}
],
"tinycore": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_4_1.png",
"alt": "TinyCore SN Configuration",
"caption": "TinyCore SN Configuration"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_4_2.png",
"alt": "TinyCore Random Option",
"caption": "TinyCore Random Option - The random option is recommended"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_4_3.png",
"alt": "TinyCore MAC Configuration",
"caption": "TinyCore MAC Configuration"
},
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_4_4.png",
"alt": "TinyCore VM MAC",
"caption": "TinyCore VM MAC - Choose to use your VM's MAC or a random one"
}
]
}
},
{
"id": "step5",
"title": "Build the Loader",
"intro": "Once you have selected the model, DSM version, and addons, proceed to build the loader. This process might take a few minutes depending on the loader and the selected configuration. To start, select the \"Build the Loader\" option.",
"loaders": {
"arc": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_5_1.png",
"alt": "Arc Build Loader",
"caption": "Arc Build Loader"
}
],
"rr": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_5_1.png",
"alt": "RR Build Loader",
"caption": "RR Build Loader"
}
],
"tinycore": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_5_1.png",
"alt": "TinyCore Build Loader",
"caption": "TinyCore Build Loader"
}
]
}
},
{
"id": "step6",
"title": "Boot the Loader",
"intro": "Once the loader has been built, it will prompt you to boot. The VM will restart with the configuration you've created and start the DSM installation.",
"loaders": {
"arc": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/arc/arc_1_6_1.png",
"alt": "Arc Boot Loader",
"caption": "Arc Boot Loader"
}
],
"rr": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/rr/rr_2_6_1.png",
"alt": "RR Boot Loader",
"caption": "RR Boot Loader"
}
],
"tinycore": [
{
"src": "https://macrimi.github.io/ProxMenux/vm/synology/tinycore/tinycore_3_6_1.png",
"alt": "TinyCore Boot Loader",
"caption": "TinyCore Boot Loader"
}
]
}
}
],
"dsmInstall": {
"heading": "Starting the DSM Installation",
"intro": "Once the loader is booted, you can find your Synology device using:",
"afterCode": "Follow the on-screen steps to complete the DSM installation.",
"setupAlt": "DSM Setup",
"setupCaption": "DSM Setup Screen",
"patience": "Please be patient The process may take a few minutes to complete. The progress percentage will update automatically as the setup progresses. A countdown will start once the installation is nearing completion.",
"finishAlt": "Installation Complete",
"finishCaption": "Installation Complete"
},
"tips": {
"heading": "Tips",
"introItem": "Keep in mind that available options may change depending on the loader version and developer updates. If you encounter issues during the loader creation process, consult the loader documentation:",
"docLinks": [
{
"label": "Arc Documentation",
"url": "https://github.com/AuxXxilium/arc"
},
{
"label": "RR Documentation",
"url": "https://github.com/RROrg/rr"
},
{
"label": "TinyCore Documentation",
"url": "https://github.com/PeterSuh-Q3/tinycore-redpill"
}
],
"olderModels": "Some older DSM models may have issues recognizing disks or the network card. It is recommended to use more recent models.",
"updateLabel": "Update:",
"updateBody": "Some loaders offer the option to update the loader directly from the menu.",
"importantLabel": "Important:",
"importantBody": "ProxMenux does not provide support for the different loaders."
}
}
@@ -0,0 +1,292 @@
{
"meta": {
"title": "Create VM: System Linux | ProxMenux Documentation",
"description": "Create Linux virtual machines on Proxmox VE with ProxMenux. Covers the curated official ISO catalogue (Ubuntu, Debian, Fedora, Arch, Rocky, Mint, openSUSE, Alpine, Kali, Manjaro), the unified storage plan, optional GPU passthrough and post-install tips.",
"ogTitle": "Create VM: System Linux | ProxMenux Documentation",
"ogDescription": "Create Linux VMs on Proxmox VE with ProxMenux. Curated ISO catalogue, unified storage plan, optional GPU passthrough and post-install tips.",
"ogImageAlt": "ProxMenux Linux VM menu"
},
"header": {
"title": "Create VM: System Linux",
"description": "Create a Linux VM on Proxmox VE. ProxMenux ships with a curated catalogue of official Linux ISOs ready to download, plus a local-ISO picker, and routes everything through the shared VM wizard, the unified storage plan and the optional GPU passthrough assistant.",
"section": "Virtual Machines"
},
"intro": {
"title": "What this script does",
"body": "The Linux selector offers two ProxMenux-managed sources of installation media: an official ISO from the curated list (auto-downloaded) or a local ISO you uploaded yourself. Whichever you pick, the rest of the flow is the shared wizard: CPU / RAM / BIOS → storage plan → optional GPU passthrough → VM creation."
},
"image": {
"alt": "ProxMenux Linux installation options",
"caption": "Linux installation options"
},
"config": {
"heading": "Default vs Advanced configuration",
"intro": "After the ISO is selected, ProxMenux asks whether to use the default VM profile or open the advanced wizard.",
"defaultHeading": "Default configuration",
"headerParam": "Parameter",
"headerValue": "Default value",
"defaultRows": [
{
"param": "Machine type",
"valueRich": "<code>q35</code>"
},
{
"param": "BIOS",
"value": "OVMF (UEFI)"
},
{
"param": "CPU type",
"value": "Host"
},
{
"param": "Cores",
"value": "2"
},
{
"param": "RAM",
"value": "4096 MB"
},
{
"param": "Bridge",
"valueRich": "<code>vmbr0</code>"
},
{
"param": "MAC address",
"value": "Auto-generated"
},
{
"param": "Start on completion",
"value": "No"
}
],
"advancedHeading": "Advanced configuration",
"advancedIntro": "The advanced wizard exposes every parameter individually:",
"headerOptions": "Options",
"advancedRows": [
{
"param": "Machine type",
"optionsRich": "<code>q35</code> or <code>i440fx</code>"
},
{
"param": "BIOS",
"options": "OVMF (UEFI) or SeaBIOS (Legacy)"
},
{
"param": "CPU type",
"options": "Host or KVM64"
},
{
"param": "Cores",
"options": "Number of CPU cores"
},
{
"param": "RAM",
"options": "Memory allocated to the VM"
},
{
"param": "Bridge",
"options": "Network bridge"
},
{
"param": "MAC address",
"options": "Custom MAC"
},
{
"param": "VLAN",
"options": "VLAN tag (optional)"
},
{
"param": "MTU",
"options": "MTU size"
}
]
},
"storagePlan": {
"heading": "Storage plan",
"body": "After CPU / RAM, ProxMenux opens the <strong>Storage Plan</strong> menu, where you can combine virtual disks, imported disks and PCI passthrough devices in the same VM, adding items one at a time and finishing when you are done.",
"virtualDiskTitle": "a. Add virtual disk",
"virtualDiskItems": [
"Lists the Proxmox storage volumes available on the host.",
"You pick the target storage and the size in GB.",
"The disk is attached to the VM as SATA (<code>sata0</code>, <code>sata1</code>, … up to 6)."
],
"importDiskTitle": "b. Add import disk",
"importDiskItems": [
"Detects physical disks that are safe to import (system and protected disks are hidden).",
"You select one or more disks via a checklist.",
"Imported disks are attached as SATA via <code>qm set</code>."
],
"pciTitle": "c. Add Controller or NVMe (PCI passthrough)",
"pciItems": [
"Detects SATA/SAS HBAs and NVMe devices on the host and lets you pass an <em>entire controller</em> into the VM. IOMMU must be enabled; the script offers to enable it and reboots if required.",
"A confirmation step warns about controller-wide risk (the whole card, including every disk on it, leaves the host).",
"The selected PCI devices are attached via <code>qm set hostpciN: …</code>."
],
"resetTitle": "Reset and finish",
"resetBody": "The menu also offers <strong>r</strong> (reset the current selection and start over) and <strong>d</strong> (finish and continue). You cannot finish with an empty plan."
},
"gpu": {
"heading": "Optional GPU passthrough",
"body": "After the storage plan, if a compatible GPU is detected on the host ProxMenux offers to launch the GPU passthrough assistant. See <gpuLink>Add GPU to a VM (Passthrough)</gpuLink> for how the assistant works — a host reboot may be required."
},
"autoFeatures": {
"heading": "Automatic VM features",
"efiTitle": "EFI disk",
"efiBody": "When OVMF (UEFI) is selected, ProxMenux creates a 4 MB EFI system disk on the storage you pick so the firmware has a place to store its variables.",
"isoTitle": "ISO mounting",
"isoBody": "The installation ISO is attached to <code>ide2</code> as a CD-ROM, ready for first boot.",
"guestTitle": "QEMU Guest Agent",
"guestBody": "The guest agent channel is enabled in the VM config. You still need to install the agent inside the guest — see the tips below."
},
"installOptions": {
"heading": "Linux installation options",
"officialHeading": "Official ISO (traditional install)",
"officialBody": "ProxMenux ships with a curated list of official Linux ISOs. Pick one and the script downloads it straight from the upstream mirror into <code>/var/lib/vz/template/iso</code>, then attaches it to the VM.",
"officialImageAlt": "Linux distribution selection",
"officialImageCaption": "Linux distribution selection",
"localHeading": "Local ISO",
"localBody": "Uses any Linux ISO already present in <code>/var/lib/vz/template/iso</code>. The script lists every <code>*.iso</code> it finds and lets you pick one.",
"localImageAlt": "Local ISO selection menu",
"localImageCaption": "Local ISO selection menu",
"distros": [
{
"name": "Ubuntu",
"variants": [
"25.10 Desktop",
"24.04 Desktop",
"22.04 Desktop",
"20.04 Desktop",
"25.10 Server",
"24.04 Server",
"22.04 Server",
"20.04 Server"
]
},
{
"name": "Debian",
"variants": [
"13 Desktop",
"12 Desktop",
"11 Desktop",
"13 Netinst",
"12 Netinst",
"11 Netinst"
]
},
{
"name": "Fedora",
"variants": [
"Workstation 42"
]
},
{
"name": "Arch Linux",
"variants": [
"latest"
]
},
{
"name": "Rocky Linux",
"variants": [
"9"
]
},
{
"name": "Linux Mint",
"variants": [
"22.1 Cinnamon"
]
},
{
"name": "openSUSE",
"variants": [
"Leap 15.6"
]
},
{
"name": "Alpine Linux",
"variants": [
"3.21"
]
},
{
"name": "Kali Linux",
"variants": [
"2026.1"
]
},
{
"name": "Manjaro",
"variants": [
"25.0 GNOME"
]
}
]
},
"endToEnd": {
"heading": "What the script does end-to-end",
"items": [
"Obtains the Linux ISO (official download or local file).",
"Applies the default or advanced CPU / RAM / BIOS / machine-type configuration.",
"Opens the storage plan and attaches the selected virtual disks, imported disks and PCI devices.",
"Creates the EFI disk when UEFI is selected.",
"Mounts the Linux ISO on <code>ide2</code>.",
"Sets the boot order (disk first, then ISO).",
"Enables the QEMU Guest Agent channel.",
"Optionally runs the GPU passthrough assistant.",
"Generates a styled HTML description attached to the VM.",
"Starts the VM if you chose to."
]
},
"postInstall": {
"heading": "Post-install tips",
"guestAgentHeading": "Install the QEMU Guest Agent inside the VM",
"guestAgentBody": "ProxMenux enables the guest agent channel in the VM config, but the agent itself has to be installed inside the guest. It enables graceful shutdown, filesystem freeze for consistent snapshots and accurate memory reporting in the Proxmox UI.",
"debian": "Debian / Ubuntu",
"fedora": "Fedora / Rocky / RHEL",
"arch": "Arch Linux",
"opensuse": "openSUSE",
"virtioHeading": "VirtIO support in Linux",
"virtioBody": "Modern Linux kernels (2.6.25+) include VirtIO disk and network drivers out of the box, so you can switch the disk interface to <code>virtio</code> or <code>virtio-scsi</code> in the Advanced wizard and the network adapter to <code>virtio</code> without any extra driver step.",
"virtioWarnTitle": "Very old distributions",
"virtioWarnBody": "If you are installing something predating the 2.6.25 kernel, VirtIO modules may not be available at install time. In that case keep SATA / SCSI or provide a driver disk.",
"trimHeading": "Enable TRIM / discard on SSD-backed storage",
"trimBody": "When the VM sits on SSD-backed Proxmox storage and the disk was attached with the <code>discard</code> flag, you can forward trim commands from inside the guest. Two options:",
"trimItems": [
"Run <code>fstrim -av</code> periodically (or enable the <code>fstrim.timer</code> unit on systemd distributions).",
"Or mount filesystems with the <code>discard</code> option in <code>/etc/fstab</code>."
],
"balloonHeading": "Memory ballooning",
"balloonBody": "The <code>virtio_balloon</code> driver ships with modern Linux kernels. Proxmox uses it to reclaim unused memory from the VM and show accurate utilisation in the UI — no guest-side configuration required."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/import-disk-image-vm",
"label": "Import Disk Image to VM",
"tail": " — attach an existing Linux .qcow2 / .img / .raw to a fresh VM."
},
{
"href": "/docs/utils/import-vm",
"label": "Import VM from OVA / OVF",
"tail": " — bring in a Linux VM exported from VMware / VirtualBox / Proxmox."
},
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — for Linux VMs that need GPU acceleration."
},
{
"href": "/docs/help-info/vm-ct-commands",
"label": "VM and CT Management commands",
"tail": " — qm CLI reference."
},
{
"href": "/docs/create-vm",
"label": "Create VM overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,138 @@
{
"meta": {
"title": "Create VM: System NAS | ProxMenux Documentation",
"description": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS. Umbrel OS is available via community script.",
"ogTitle": "Create VM: System NAS | ProxMenux Documentation",
"ogDescription": "Create NAS virtual machines on Proxmox VE with ProxMenux. Supports Synology DSM (loader), TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS.",
"ogImageAlt": "ProxMenux System NAS Menu"
},
"header": {
"title": "Create VM: System NAS",
"description": "ProxMenux supports seven NAS operating systems as dedicated VMs, plus an optional Umbrel OS path via a community script. Most systems share the same auto-ISO flow; Synology DSM uses a specialised loader wizard.",
"section": "Virtual Machines"
},
"intro": {
"title": "How the NAS selector works",
"body": "The NAS selector detects the latest stable release of each appliance (querying its upstream mirror), downloads the ISO — or builds the VM from a pre-packaged image — and then hands over to the generic ProxMenux VM wizard for CPU, RAM, disk and network configuration."
},
"image": {
"alt": "ProxMenux System NAS selector",
"caption": "System NAS selector"
},
"flowBadges": {
"loader": "Loader flow",
"auto-iso": "Auto-ISO flow",
"dedicated": "Dedicated script"
},
"labels": {
"base": "Base",
"fileSystem": "Filesystem",
"viewDetails": "View details"
},
"supported": {
"heading": "Supported NAS systems",
"cards": [
{
"name": "Synology DSM",
"tagline": "DiskStation Manager with the ARC / RR loader. Requires configuring the loader before first boot.",
"icon": "HardDrive",
"base": "Linux (custom)",
"fileSystem": "Btrfs, ext4",
"href": "/docs/create-vm/system-nas/synology",
"flow": "loader"
},
{
"name": "TrueNAS SCALE",
"tagline": "Debian-based TrueNAS with Docker / Kubernetes apps and ZFS as primary filesystem.",
"icon": "Database",
"base": "Debian Linux",
"fileSystem": "ZFS",
"href": "/docs/create-vm/system-nas/system-nas-others#truenas-scale",
"flow": "auto-iso"
},
{
"name": "TrueNAS CORE",
"tagline": "FreeBSD-based TrueNAS. Enterprise-grade ZFS storage with jails and plugins.",
"icon": "Database",
"base": "FreeBSD",
"fileSystem": "ZFS",
"href": "/docs/create-vm/system-nas/system-nas-others#truenas-core",
"flow": "auto-iso"
},
{
"name": "OpenMediaVault",
"tagline": "Lightweight Debian-based NAS with a modular plugin architecture. Great for older hardware.",
"icon": "Server",
"base": "Debian Linux",
"fileSystem": "ext4, XFS, Btrfs",
"href": "/docs/create-vm/system-nas/system-nas-others#openmediavault",
"flow": "auto-iso"
},
{
"name": "XigmaNAS",
"tagline": "FreeBSD-based NAS — the original successor to FreeNAS, focused on ZFS and simplicity.",
"icon": "Database",
"base": "FreeBSD",
"fileSystem": "ZFS, UFS",
"href": "/docs/create-vm/system-nas/system-nas-others#xigmanas",
"flow": "auto-iso"
},
{
"name": "Rockstor",
"tagline": "openSUSE-based NAS built around Btrfs. Rock-ons (Docker apps) extend functionality.",
"icon": "HardDrive",
"base": "openSUSE Leap",
"fileSystem": "Btrfs",
"href": "/docs/create-vm/system-nas/system-nas-others#rockstor",
"flow": "auto-iso"
},
{
"name": "ZimaOS",
"tagline": "Lightweight NAS OS focused on media, Docker apps and home automation. Uses its own installer.",
"icon": "MonitorIcon",
"base": "Debian / CasaOS",
"fileSystem": "ext4",
"href": "/docs/create-vm/system-nas/system-nas-others#zimaos",
"flow": "dedicated"
}
]
},
"umbrel": {
"title": "Community option: Umbrel OS",
"bodyRich": "The 8th entry in the NAS menu is <strong>Umbrel OS</strong>. It runs a <umbrelLink>community-scripts installer</umbrelLink> maintained outside ProxMenux, so it is not documented here. The installer handles the entire lifecycle and prints its default credentials at the end."
},
"zfsMem": {
"title": "ZFS memory rule of thumb",
"bodyRich": "If you pick a ZFS-based NAS (TrueNAS, XigmaNAS), allocate at least <strong>8 GB RAM</strong> to the VM — ZFS uses free memory as ARC cache and performance degrades noticeably below that. Rockstor (Btrfs) and OMV (ext4) are far less memory-hungry."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/create-vm/system-nas/synology",
"label": "Synology VM",
"tail": " — dedicated installer for Synology DSM (Xpenology) on Proxmox."
},
{
"href": "/docs/create-vm/system-nas/system-nas-others",
"label": "Other System NAS",
"tail": " — TrueNAS, OpenMediaVault, Rockstor, XigmaNAS and similar."
},
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — pass real physical disks to the NAS VM (recommended over virtual disks for production)."
},
{
"href": "/docs/help-info/zfs-commands",
"label": "ZFS Management commands",
"tail": " — useful if your NAS distribution uses ZFS underneath."
},
{
"href": "/docs/create-vm",
"label": "Create VM overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,400 @@
{
"meta": {
"title": "Create VM: Synology DSM | ProxMenux Documentation",
"description": "Create a Synology DSM virtual machine on Proxmox VE. ProxMenux downloads the loader of your choice (Arc, RR, TinyCore M-shell or a custom one), imports it as the VM's boot disk and prepares CPU, RAM and storage through the default or advanced wizard.",
"ogTitle": "Create VM: Synology DSM | ProxMenux Documentation",
"ogDescription": "Create a Synology DSM virtual machine on Proxmox VE with ProxMenux."
},
"header": {
"title": "Create VM: Synology DSM",
"description": "Create a Synology DSM virtual machine on Proxmox VE. ProxMenux downloads the loader of your choice (Arc, RR, TinyCore M-shell or a custom one), imports it as the VM's boot disk and prepares CPU, RAM and storage through the default or advanced wizard.",
"section": "Virtual Machines · NAS"
},
"loaderLabels": {
"arc": "Arc Loader",
"rr": "RR Loader",
"tinycore": "TinyCore Loader"
},
"whatThisDoes": {
"title": "What this does",
"bodyRich": "ProxMenux automates the VM-side of a Synology DSM install: it downloads one of the supported loaders, imports it into a new VM as an IDE boot disk, and applies the CPU / RAM / network / storage you pick. The rest — building the loader, choosing the DSM model, installing DSM — happens <strong>inside the VM</strong>, driven by the loader's own web or terminal interface. Those steps are community-maintained and change often, so this page gives you a working baseline."
},
"supportedLoaders": {
"heading": "Supported loaders",
"intro": "The script lets you choose between four loader sources:",
"loaders": [
{
"name": "AuxXxilium Arc",
"url": "https://github.com/AuxXxilium/arc"
},
{
"name": "RedPill RR",
"url": "https://github.com/RROrg/rr"
},
{
"name": "TinyCore RedPill M-shell",
"url": "https://github.com/PeterSuh-Q3/tinycore-redpill"
}
],
"customRich": "<strong>Custom Loader</strong> — drop your own loader image into <code>/var/lib/vz/template/iso</code> and the script will pick it up."
},
"config": {
"heading": "Default vs Advanced configuration",
"intro": "When you run the script it asks whether to use the ProxMenux default VM profile or open the advanced wizard. Default values are tuned for DSM and work for most installs.",
"defaultHeading": "Default configuration",
"headerParam": "Parameter",
"headerValue": "Default value",
"defaultRowsRich": [
{
"param": "Machine type",
"valueRich": "<code>q35</code>"
},
{
"param": "BIOS",
"valueRich": "OVMF (UEFI)"
},
{
"param": "CPU type",
"valueRich": "Host"
},
{
"param": "Cores",
"valueRich": "2"
},
{
"param": "RAM",
"valueRich": "4096 MB"
},
{
"param": "Bridge",
"valueRich": "<code>vmbr0</code>"
},
{
"param": "MAC address",
"valueRich": "Auto-generated"
},
{
"param": "Start on completion",
"valueRich": "No"
}
],
"advancedHeading": "Advanced configuration",
"advancedIntro": "The advanced wizard exposes every knob. You can freely change any of these:",
"headerOptions": "Options",
"advancedRowsRich": [
{
"param": "Machine type",
"optionsRich": "<code>q35</code> or <code>i440fx</code>"
},
{
"param": "BIOS",
"optionsRich": "OVMF (UEFI) or SeaBIOS (Legacy)"
},
{
"param": "CPU type",
"optionsRich": "Host or KVM64"
},
{
"param": "Cores",
"optionsRich": "Number of CPU cores"
},
{
"param": "RAM",
"optionsRich": "Memory allocated to the VM"
},
{
"param": "Bridge",
"optionsRich": "Network bridge"
},
{
"param": "MAC address",
"optionsRich": "Custom MAC"
},
{
"param": "VLAN",
"optionsRich": "VLAN tag (optional)"
},
{
"param": "MTU",
"optionsRich": "MTU size"
}
]
},
"storagePlan": {
"heading": "Storage plan",
"introRich": "After the CPU / RAM step, ProxMenux opens the <strong>Storage Plan</strong> menu, where you can <strong>combine</strong> virtual disks, imported disks and PCI passthrough devices in the same VM, adding items one at a time and finishing when you are done.",
"virtualHeading": "a. Add virtual disk",
"virtualItemsRich": [
"Lists the Proxmox storage volumes available on the host.",
"You pick the target storage and the size in GB.",
"The disk is attached to the VM as SATA (<code>sata0</code>, <code>sata1</code>, … up to 6)."
],
"importHeading": "b. Add import disk",
"importItemsRich": [
"Detects physical disks that are safe to import (system and protected disks are hidden).",
"You select one or more disks via a checklist.",
"Imported disks are attached as SATA via <code>qm set</code>."
],
"pciHeading": "c. Add Controller or NVMe (PCI passthrough)",
"pciItemsRich": [
"Detects SATA/SAS HBAs and NVMe devices on the host and lets you pass an <em>entire controller</em> into the VM. IOMMU must be enabled; the script offers to enable it and reboots if required.",
"A confirmation step warns about controller-wide risk (the whole card, including every disk on it, leaves the host).",
"The selected PCI devices are attached via <code>qm set hostpciN: …</code>."
],
"resetCalloutTitle": "Reset and finish",
"resetCalloutBodyRich": "The menu also offers <strong>r</strong> (reset the current selection and start over) and <strong>d</strong> (finish and continue). You cannot finish with an empty plan — Synology needs at least one disk to install DSM on."
},
"gpu": {
"heading": "Optional GPU passthrough",
"bodyRich": "After the storage plan, if the script detects a compatible GPU on the host it asks whether you want to pass it to this VM. See <link>Add GPU to a VM (Passthrough)</link> for how the assistant works — a host reboot may be required."
},
"loaderInstall": {
"heading": "Loader installation",
"intro1Rich": "<strong>Arc</strong>, <strong>RR</strong> and <strong>TinyCore M-shell</strong> are downloaded and extracted automatically from their upstream GitHub repositories. If the download fails the script aborts with a clear message.",
"intro2Rich": "For the <strong>Custom Loader</strong> option the script scans <code>/var/lib/vz/template/iso</code>. If more than one candidate is found you are prompted to pick the one you want.",
"uploadIntro": "You can upload custom loaders from Proxmox local storage:",
"imageAlt": "Add custom loader",
"imageCaption": "Add custom loader"
},
"vmCreation": {
"heading": "VM creation — what the script runs",
"introRich": "Once you confirm the loader, ProxMenux runs the equivalent of these <code>qm</code> commands:",
"itemsRich": [
"<code>qm create</code> — creates the VM with the selected CPU, RAM, BIOS and machine type.",
"<code>qm importdisk</code> — imports the loader as an <strong>IDE</strong> disk (maximum compatibility).",
"<code>qm set sataN: …</code> — attaches virtual disks and imported disks from the storage plan, plus the network interface.",
"<code>qm set hostpciN: …</code> — attaches any Controller / NVMe devices selected for PCI passthrough.",
"<code>qm set --boot</code> — sets the loader as the first boot device."
]
},
"stepByStep": {
"heading": "Step-by-step loader configuration",
"intro": "All loaders follow the same high-level pattern — start the VM, pick a model, pick a DSM version, pick add-ons, build, boot — but the screens and menus differ. The guide below walks through the six shared steps with screenshots for each loader. Exact options may change with new loader releases.",
"warnCalloutTitle": "Loaders are not maintained by ProxMenux",
"warnCalloutBody": "Arc, RR and TinyCore are community projects with their own release cadence. If a step looks different from the screenshots below, the loader has probably updated — check the loader's own documentation (links at the bottom of this page)."
},
"stepBadge": "Step",
"step1": {
"title": "Start the VM and access the main menu",
"intro": "Once the VM is created, start it. The first boot takes you to the loader's configuration interface where you pick and build the DSM model you want. After the loader has been built, subsequent boots skip this step unless you force a reconfiguration from the loader's own boot monitor. All three loaders support both a terminal UI and a web UI.",
"arc": {
"webRich": "<strong>Web interface.</strong> Open a browser and go to the IP shown in the VM console (in our example: <code>http://192.168.0.32</code>).",
"webAlt": "Arc loader web interface",
"webCaption": "Arc loader web interface",
"termRich": "<strong>Terminal interface.</strong> Use it directly from the VM console output.",
"termAlt": "Arc loader terminal interface",
"termCaption": "Arc loader terminal interface"
},
"rr": {
"webRich": "<strong>Web interface.</strong> Open a browser and go to the IP shown in the VM console followed by port <strong>7681</strong> (example: <code>http://192.168.0.33:7681</code>).",
"webAlt": "RR loader web interface",
"webCaption": "RR loader web interface",
"termRich": "<strong>Terminal interface.</strong> In the VM console type <code>menu.sh</code> to open it.",
"termAlt": "RR loader terminal interface",
"termCaption": "RR loader terminal interface"
},
"tinycore": {
"webRich": "<strong>Web interface.</strong> Open a browser and go to the IP shown in the VM console followed by port <strong>7681</strong> (example: <code>http://192.168.0.35:7681</code>).",
"webAlt": "TinyCore loader web interface",
"webCaption": "TinyCore loader web interface",
"termRich": "<strong>Terminal interface.</strong> Use it from the VM console. Keep an eye on it — at some point it may prompt you to press a key to continue or to change the language.",
"termAlt": "TinyCore loader terminal interface",
"termCaption": "TinyCore loader terminal interface"
}
},
"step2": {
"title": "Select model",
"introRich": "Pick the Synology DSM model you want to install. Depending on the loader you may need to expand the options to see the full list. In the screenshots below we use the <strong>SA6400</strong> model as an example.",
"arc": {
"alt": "Arc model selection",
"caption": "Arc model selection"
},
"rr": {
"alt": "RR model selection",
"caption": "RR model selection"
},
"tinycore": {
"alt": "TinyCore model selection",
"caption": "TinyCore model selection"
}
},
"step3": {
"title": "Select DSM version",
"intro": "After picking the model, choose the DSM version to install.",
"arc": [
{
"alt": "Arc version — step 1",
"caption": "Arc version selection — step 1"
},
{
"alt": "Arc version — step 2",
"caption": "Arc version selection — step 2"
}
],
"rr": [
{
"alt": "RR version — step 1",
"caption": "RR version selection — step 1"
},
{
"alt": "RR version — step 2",
"caption": "RR version selection — step 2"
},
{
"alt": "RR version — step 3",
"caption": "RR version selection — step 3"
}
],
"tinycore": [
{
"alt": "TinyCore version — step 1",
"caption": "TinyCore version selection — step 1"
},
{
"alt": "TinyCore version — step 2",
"caption": "TinyCore version selection — step 2"
}
]
},
"step4": {
"title": "Select addons",
"intro": "This step lets you add extra features or custom configuration to the loader.",
"arc": {
"autoRich": "<strong>Arc</strong> offers an automatic mode (recommended) and a manual mode. In automatic mode the loader applies sensible defaults and reboots on its own when done.",
"autoAlt": "Arc auto configuration",
"autoCaption": "Arc auto configuration",
"manualRich": "If you pick manual, you step through the options one by one:",
"manualAlt": "Arc manual configuration",
"manualCaption": "Arc manual configuration",
"snMacAlt": "Arc SN/MAC",
"snMacCaption": "Arc SN / MAC configuration",
"portmapAlt": "Arc SATA portmap",
"portmapCaption": "Arc SATA portmap (use the recommended option)",
"addonsAlt": "Arc addons",
"addonsCaption": "Arc addons selection"
},
"rr": [
{
"alt": "RR addon — step 1",
"caption": "RR addon — step 1"
},
{
"alt": "RR addon — step 2",
"caption": "RR addon — step 2: press to add an addon"
},
{
"alt": "RR addon — step 3",
"caption": "RR addon — step 3: click the addon you want. Repeat the previous two screenshots to add more."
}
],
"tinycore": [
{
"alt": "TinyCore SN configuration",
"caption": "TinyCore SN configuration"
},
{
"alt": "TinyCore random option",
"caption": "TinyCore random option (recommended)"
},
{
"alt": "TinyCore MAC configuration",
"caption": "TinyCore MAC configuration"
},
{
"alt": "TinyCore VM MAC",
"caption": "TinyCore — pick the VM's MAC or a random one"
}
]
},
"step5": {
"title": "Build the loader",
"introRich": "With the model, DSM version and addons chosen, pick <strong>Build the Loader</strong>. This can take a few minutes depending on the loader and the selected options.",
"arc": {
"alt": "Arc build loader",
"caption": "Arc — build loader"
},
"rr": {
"alt": "RR build loader",
"caption": "RR — build loader"
},
"tinycore": {
"alt": "TinyCore build loader",
"caption": "TinyCore — build loader"
}
},
"step6": {
"title": "Boot the loader",
"intro": "Once the loader is built, the VM reboots with the configuration you created and DSM installation begins.",
"arc": {
"alt": "Arc boot loader",
"caption": "Arc — boot loader"
},
"rr": {
"alt": "RR boot loader",
"caption": "RR — boot loader"
},
"tinycore": {
"alt": "TinyCore boot loader",
"caption": "TinyCore — boot loader"
}
},
"dsmInstall": {
"heading": "Starting the DSM installation",
"intro": "Once the loader has booted you can discover your DSM VM by opening:",
"afterCode": "Follow the on-screen steps to complete the DSM installation.",
"setupAlt": "DSM setup",
"setupCaption": "DSM setup screen",
"patience": "Be patient — the process can take several minutes. Progress updates automatically and a countdown appears as installation nears completion.",
"finishAlt": "Installation complete",
"finishCaption": "Installation complete"
},
"tips": {
"heading": "Tips",
"recentTitle": "Use recent DSM models",
"recentBody": "Some older DSM models have trouble recognising disks or the network card. Prefer recent models (e.g. SA6400) for a smoother first-boot experience.",
"updateTitle": "Updating the loader",
"updateBody": "Some loaders offer the option to update themselves directly from their configuration menu — you don't have to destroy and recreate the VM.",
"warnTitle": "ProxMenux does not support the loaders",
"warnBody": "ProxMenux automates the VM side. Loader issues (model not found, add-on failing to install, DSM refusing to boot) are out of scope here — use each loader's own issue tracker and documentation.",
"docsHeading": "Loader documentation",
"docLinks": [
{
"label": "Arc documentation",
"url": "https://github.com/AuxXxilium/arc"
},
{
"label": "RR documentation",
"url": "https://github.com/RROrg/rr"
},
{
"label": "TinyCore documentation",
"url": "https://github.com/PeterSuh-Q3/tinycore-redpill"
}
]
},
"related": {
"heading": "Related",
"itemsRich": [
{
"href": "/docs/create-vm/system-nas",
"label": "System NAS overview",
"tail": " — comparison of Synology vs TrueNAS / OMV / Rockstor / XigmaNAS."
},
{
"href": "/docs/create-vm/system-nas/system-nas-others",
"label": "Other System NAS",
"tail": " — non-Synology NAS distributions."
},
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — pass real disks to the Synology VM (recommended for storage performance)."
},
{
"href": "/docs/create-vm",
"label": "Create VM overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,297 @@
{
"meta": {
"title": "Create VM: Other NAS Systems | ProxMenux Documentation",
"description": "Create TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS virtual machines on Proxmox VE with ProxMenux. Covers default / advanced configuration, the new storage plan, optional GPU passthrough and per-system recommended specs.",
"ogTitle": "Create VM: Other NAS Systems | ProxMenux Documentation",
"ogDescription": "Create TrueNAS SCALE / CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS VMs on Proxmox VE with ProxMenux.",
"ogImageAlt": "ProxMenux NAS selector"
},
"header": {
"title": "Create VM: Other NAS Systems",
"description": "ProxMenux can create a ready-to-install VM for TrueNAS SCALE, TrueNAS CORE, OpenMediaVault, XigmaNAS, Rockstor and ZimaOS. This page covers the shared creation flow (default / advanced configuration, the new storage plan, optional GPU passthrough) plus per-system notes and recommended specs.",
"section": "Virtual Machines · NAS"
},
"intro": {
"title": "How these systems are created",
"bodyRich": "All six systems share the same ProxMenux wizard. The NAS selector picks the matching installer (auto-detecting the latest stable version for TrueNAS, OMV, XigmaNAS and Rockstor) and then hands over to the generic VM configurator and the storage plan. ZimaOS uses its own installer script (<code>vm/zimaos.sh</code>) but follows the same CPU / RAM / storage / optional-GPU sequence."
},
"config": {
"heading": "Default vs Advanced configuration",
"intro": "When a NAS is selected, ProxMenux asks whether to use the default VM profile or open the advanced wizard. The defaults are tuned for NAS workloads — more RAM than a plain Linux VM because ZFS-based systems need it for the ARC cache.",
"defaultHeading": "Default configuration",
"headerParam": "Parameter",
"headerValue": "Default value",
"defaultRowsRich": [
{
"param": "Machine type",
"valueRich": "<code>q35</code>"
},
{
"param": "BIOS",
"valueRich": "OVMF (UEFI)<note> — SeaBIOS for OpenMediaVault</note>"
},
{
"param": "CPU type",
"valueRich": "Host"
},
{
"param": "Cores",
"valueRich": "2"
},
{
"param": "RAM",
"valueRich": "8192 MB<note> — 4096 MB for ZimaOS</note>"
},
{
"param": "Bridge",
"valueRich": "<code>vmbr0</code>"
},
{
"param": "MAC address",
"valueRich": "Auto-generated"
},
{
"param": "Start on completion",
"valueRich": "No"
}
],
"advancedHeading": "Advanced configuration",
"advancedIntro": "The advanced wizard exposes every parameter individually:",
"headerOptions": "Options",
"advancedRowsRich": [
{
"param": "Machine type",
"optionsRich": "<code>q35</code> or <code>i440fx</code>"
},
{
"param": "BIOS",
"optionsRich": "OVMF (UEFI) or SeaBIOS (Legacy)"
},
{
"param": "CPU type",
"optionsRich": "Host or KVM64"
},
{
"param": "Cores",
"optionsRich": "Number of CPU cores"
},
{
"param": "RAM",
"optionsRich": "Memory allocated to the VM"
},
{
"param": "Bridge",
"optionsRich": "Network bridge"
},
{
"param": "MAC address",
"optionsRich": "Custom MAC"
},
{
"param": "VLAN",
"optionsRich": "VLAN tag (optional)"
},
{
"param": "MTU",
"optionsRich": "MTU size"
}
],
"zfsCalloutTitle": "ZFS and RAM",
"zfsCalloutBody": "TrueNAS SCALE / CORE and XigmaNAS are ZFS-based. ZFS uses free memory as ARC cache, so the 8 GB default is a minimum — bump it to 16 GB or more if you plan to store anything meaningful. OMV (ext4/XFS), Rockstor (Btrfs) and ZimaOS are far less memory-hungry."
},
"storagePlan": {
"heading": "Storage plan",
"intro": "After CPU / RAM, ProxMenux opens the Storage Plan menu, where you can combine virtual disks, imported disks and PCI passthrough devices in the same VM, adding items one at a time and finishing when you are done.",
"virtualHeading": "a. Add virtual disk",
"virtualItemsRich": [
"Lists the Proxmox storage volumes available on the host.",
"You pick the target storage and the size in GB.",
"The disk is attached to the VM as SATA (<code>sata0</code>, <code>sata1</code>, … up to 6)."
],
"importHeading": "b. Add import disk",
"importItemsRich": [
"Detects physical disks that are safe to import (system and protected disks are hidden).",
"You select one or more disks via a checklist.",
"Imported disks are attached as SATA via <code>qm set</code>."
],
"pciHeading": "c. Add Controller or NVMe (PCI passthrough)",
"pciItemsRich": [
"Detects SATA/SAS HBAs and NVMe devices on the host and lets you pass an <em>entire controller</em> into the VM. IOMMU must be enabled; the script offers to enable it and reboots if required.",
"A confirmation step warns about controller-wide risk (the whole card, including every disk on it, leaves the host).",
"The selected PCI devices are attached via <code>qm set hostpciN: …</code>."
],
"resetCalloutTitle": "Reset and finish",
"resetCalloutBodyRich": "The menu also offers <strong>r</strong> (reset the current selection and start over) and <strong>d</strong> (finish and continue). You cannot finish with an empty plan."
},
"gpu": {
"heading": "Optional GPU passthrough",
"bodyRich": "After the storage plan, if a compatible GPU is detected on the host, ProxMenux offers to launch the GPU passthrough assistant. See <link>Add GPU to a VM (Passthrough)</link> for how the assistant works — a host reboot may be required."
},
"autoFeatures": {
"heading": "Automatic VM features",
"efiTitle": "EFI disk",
"efiBody": "When OVMF (UEFI) is selected, ProxMenux automatically creates a 4 MB EFI disk on the storage you pick, formatted to match the storage type (raw for directory-based storage).",
"isoTitle": "ISO mounting",
"isoBodyRich": "The installation ISO is downloaded (if needed) and attached to <code>ide2</code> as a CD-ROM, ready for first boot.",
"guestTitle": "QEMU Guest Agent",
"guestBody": "The guest agent channel is enabled in the VM config. You still need to install the agent inside the guest after the NAS OS is up."
},
"endToEnd": {
"heading": "What the script does end-to-end",
"itemsRich": [
"Detects and downloads the latest stable ISO (or uses the fallback version if the upstream is unreachable).",
"Applies the default or advanced CPU / RAM / BIOS / machine type.",
"Opens the storage plan and attaches the selected virtual disks, imported disks and PCI devices.",
"Creates an EFI disk if UEFI is selected.",
"Mounts the installation ISO on <code>ide2</code>.",
"Sets the boot order (disk first, then ISO).",
"Enables the QEMU Guest Agent channel.",
"Optionally runs the GPU passthrough assistant.",
"Generates a styled HTML description attached to the VM.",
"Starts the VM if you chose to."
]
},
"perSystem": {
"heading": "Per-system notes",
"shellLabel": "Shell interface",
"webLabel": "Web interface"
},
"systems": {
"truenasScale": {
"id": "truenas-scale",
"title": "TrueNAS SCALE",
"icon": "Database",
"officialName": "TrueNAS SCALE",
"officialUrl": "https://www.truenas.com/truenas-scale/",
"description": "Debian-based TrueNAS with Docker / Kubernetes apps, Linux KVM and ZFS as the primary filesystem. The modern successor to FreeNAS for users who want ZFS plus a container ecosystem.",
"specs": [
"Recommended interface: SATA or SCSI (both support discard/trim)",
"Minimum RAM: 8 GB (16 GB+ recommended for real workloads)",
"Minimum CPU cores: 2 (4+ recommended)",
"UEFI (OVMF) boot recommended",
"VirtIO network adapter for best throughput"
],
"shellImg": "/vm/truenas/truenas-scale-shell.png",
"webImg": "/vm/truenas/truenas-scale-web.png",
"shellAlt": "TrueNAS SCALE shell interface",
"webAlt": "TrueNAS SCALE web interface"
},
"truenasCore": {
"id": "truenas-core",
"title": "TrueNAS CORE",
"icon": "Database",
"officialName": "TrueNAS CORE",
"officialUrl": "https://www.truenas.com/truenas-core/",
"description": "FreeBSD-based TrueNAS (the former FreeNAS). Mature ZFS storage with jails and plugins, but no Docker / Kubernetes. Being phased out in favour of SCALE but still widely deployed.",
"specs": [
"Recommended interface: SATA",
"Minimum RAM: 8 GB (16 GB+ recommended)",
"Minimum CPU cores: 2 (4+ recommended)",
"UEFI (OVMF) boot recommended",
"VirtIO network adapter for best throughput"
],
"shellImg": "/vm/truenas/truenas-core-shell.png",
"webImg": "/vm/truenas/truenas-core-web.png",
"shellAlt": "TrueNAS CORE shell interface",
"webAlt": "TrueNAS CORE web interface"
},
"openmediavault": {
"id": "openmediavault",
"title": "OpenMediaVault",
"icon": "Server",
"officialName": "openmediavault.org",
"officialUrl": "https://www.openmediavault.org",
"description": "Debian-based NAS with a modular plugin system. Light on resources and easy to run on modest hardware — a natural choice when you do not need ZFS.",
"specs": [
"Recommended interface: SATA or VirtIO",
"Minimum RAM: 2 GB (4 GB+ recommended)",
"Minimum CPU cores: 1 (2+ recommended)",
"BIOS: ProxMenux defaults to SeaBIOS for OMV (override in Advanced if needed)",
"VirtIO network adapter for best throughput"
],
"shellImg": "/vm/openmediavault/openmediavault-shell.png",
"webImg": "/vm/openmediavault/openmediavault-web.png",
"shellAlt": "OpenMediaVault shell interface",
"webAlt": "OpenMediaVault web interface"
},
"xigmanas": {
"id": "xigmanas",
"title": "XigmaNAS",
"icon": "Database",
"officialName": "xigmanas.com",
"officialUrl": "https://www.xigmanas.com",
"description": "FreeBSD-based NAS — the direct continuation of the original FreeNAS (0.7) codebase. Focused on ZFS and simplicity, with a lighter footprint than TrueNAS.",
"specs": [
"Recommended interface: SATA or SCSI",
"Minimum RAM: 4 GB (8 GB+ recommended for ZFS)",
"Minimum CPU cores: 2",
"UEFI (OVMF) boot recommended",
"VirtIO network adapter for best throughput"
]
},
"rockstor": {
"id": "rockstor",
"title": "Rockstor",
"icon": "HardDrive",
"officialName": "rockstor.com",
"officialUrl": "https://rockstor.com",
"description": "openSUSE Leap-based NAS built around Btrfs. Snapshots, subvolumes and the Rock-ons app framework (Docker) for media, file sharing and backup.",
"specs": [
"Recommended interface: SATA or VirtIO",
"Minimum RAM: 2 GB (4 GB+ recommended)",
"Minimum CPU cores: 2",
"UEFI (OVMF) boot recommended",
"VirtIO network adapter for best throughput"
],
"shellImg": "/vm/rockstor/rockstor-shell.png",
"webImg": "/vm/rockstor/rockstor-web.png",
"shellAlt": "Rockstor shell interface",
"webAlt": "Rockstor web interface"
},
"zimaos": {
"id": "zimaos",
"title": "ZimaOS",
"icon": "MonitorIcon",
"officialName": "zimaspace.com",
"officialUrl": "https://www.zimaspace.com/zimaos",
"description": "Lightweight NAS / home-server OS built on top of Debian, with a focus on media, Docker apps and home automation. ZimaOS uses a dedicated ProxMenux installer (vm/zimaos.sh) that downloads a pre-built image, but the VM profile follows the same flow as the other NAS systems.",
"specs": [
"Recommended interface: SATA or VirtIO",
"Default RAM: 4 GB (enough for media / self-hosted apps)",
"Minimum CPU cores: 2",
"UEFI (OVMF) boot",
"VirtIO network adapter for best throughput"
]
}
},
"related": {
"heading": "Related",
"itemsRich": [
{
"href": "/docs/create-vm/system-nas",
"label": "System NAS overview",
"tail": " — quick comparison across all NAS options."
},
{
"href": "/docs/create-vm/system-nas/synology",
"label": "Synology VM",
"tail": " — for the Synology DSM (Xpenology) flow."
},
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — recommended for NAS use cases (real disks > virtual disks)."
},
{
"href": "/docs/help-info/zfs-commands",
"label": "ZFS Management commands",
"tail": " — if you pick TrueNAS or another ZFS-backed distribution."
},
{
"href": "/docs/create-vm",
"label": "Create VM overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,259 @@
{
"meta": {
"title": "Create VM: System Windows | ProxMenux Documentation",
"description": "Create and configure Windows virtual machines on Proxmox VE with ProxMenux. Includes UUP Dump ISO and local ISO paths, default / advanced configuration, the unified storage plan, optional GPU passthrough, TPM 2.0 setup and VirtIO driver install.",
"ogTitle": "Create VM: System Windows | ProxMenux Documentation",
"ogDescription": "Create Windows VMs on Proxmox VE with ProxMenux. UUP Dump or local ISO, unified storage plan, optional GPU passthrough, TPM 2.0 and VirtIO drivers.",
"ogImageAlt": "ProxMenux Windows VM menu"
},
"header": {
"title": "Create VM: System Windows",
"description": "Create a Windows VM on Proxmox VE. ProxMenux handles ISO selection (UUP Dump or local), CPU / RAM / machine-type configuration, the unified storage plan, optional GPU passthrough, TPM 2.0 setup and VirtIO driver install.",
"section": "Virtual Machines"
},
"intro": {
"title": "What this script does",
"body": "The Windows flow asks where the ISO comes from (UUP Dump or a local copy already in <code>/var/lib/vz/template/iso</code>) and then runs the shared VM wizard. It applies Windows-friendly defaults — <code>q35</code> + OVMF + TPM 2.0 — attaches the VirtIO drivers ISO to a second CD-ROM slot, and leaves you with a VM ready to boot the Windows installer."
},
"image": {
"alt": "ProxMenux Windows installation options",
"caption": "Windows installation options"
},
"config": {
"heading": "Default vs Advanced configuration",
"intro": "After the ISO is selected, ProxMenux asks whether to use the default VM profile or open the advanced wizard. The default profile is tuned for modern Windows desktop and server editions.",
"defaultHeading": "Default configuration",
"headerParam": "Parameter",
"headerValue": "Default value",
"defaultRows": [
{
"param": "Machine type",
"valueRich": "<code>q35</code>"
},
{
"param": "BIOS",
"value": "OVMF (UEFI)"
},
{
"param": "CPU type",
"value": "Host"
},
{
"param": "Cores",
"value": "4"
},
{
"param": "RAM",
"value": "8192 MB"
},
{
"param": "Bridge",
"valueRich": "<code>vmbr0</code>"
},
{
"param": "MAC address",
"value": "Auto-generated"
},
{
"param": "TPM",
"value": "Enabled (v2.0)"
},
{
"param": "Start on completion",
"value": "No"
}
],
"advancedHeading": "Advanced configuration",
"advancedIntro": "The advanced wizard exposes every knob individually:",
"headerOptions": "Options",
"advancedRows": [
{
"param": "Machine type",
"optionsRich": "<code>q35</code> or <code>i440fx</code>"
},
{
"param": "BIOS",
"options": "OVMF (UEFI) or SeaBIOS (Legacy)"
},
{
"param": "CPU type",
"options": "Host or KVM64"
},
{
"param": "Cores",
"options": "Number of CPU cores"
},
{
"param": "RAM",
"options": "Memory allocated to the VM"
},
{
"param": "Bridge",
"options": "Network bridge"
},
{
"param": "MAC address",
"options": "Custom MAC"
},
{
"param": "VLAN",
"options": "VLAN tag (optional)"
},
{
"param": "MTU",
"options": "MTU size"
},
{
"param": "TPM",
"options": "Enable or disable TPM 2.0"
}
],
"tpmWarnTitle": "Windows 11 and Windows Server 2022 need TPM",
"tpmWarnBody": "Windows 11 and Windows Server 2022 refuse to install without a TPM 2.0 device attached to the VM. ProxMenux adds it by default; only disable it in Advanced if you know the target edition does not require it."
},
"storagePlan": {
"heading": "Storage plan",
"body": "After CPU / RAM, ProxMenux opens the <strong>Storage Plan</strong> menu, where you can combine virtual disks, imported disks and PCI passthrough devices in the same VM, adding items one at a time and finishing when you are done.",
"virtualDiskTitle": "a. Add virtual disk",
"virtualDiskItems": [
"Lists the Proxmox storage volumes available on the host.",
"You pick the target storage and the size in GB.",
"The disk is attached to the VM as SATA (<code>sata0</code>, <code>sata1</code>, … up to 6)."
],
"importDiskTitle": "b. Add import disk",
"importDiskItems": [
"Detects physical disks that are safe to import (system and protected disks are hidden).",
"You select one or more disks via a checklist.",
"Imported disks are attached as SATA via <code>qm set</code>."
],
"pciTitle": "c. Add Controller or NVMe (PCI passthrough)",
"pciItems": [
"Detects SATA/SAS HBAs and NVMe devices on the host and lets you pass an <em>entire controller</em> into the VM. IOMMU must be enabled; the script offers to enable it and reboots if required.",
"A confirmation step warns about controller-wide risk (the whole card, including every disk on it, leaves the host).",
"The selected PCI devices are attached via <code>qm set hostpciN: …</code>."
],
"resetTitle": "Reset and finish",
"resetBody": "The menu also offers <strong>r</strong> (reset the current selection and start over) and <strong>d</strong> (finish and continue). You cannot finish with an empty plan."
},
"gpu": {
"heading": "Optional GPU passthrough",
"body": "After the storage plan, if a compatible GPU is detected on the host ProxMenux offers to launch the GPU passthrough assistant. See <gpuLink>Add GPU to a VM (Passthrough)</gpuLink> for how the assistant works — a host reboot may be required."
},
"autoFeatures": {
"heading": "Automatic VM features",
"efiTitle": "EFI disk",
"efiBody": "When OVMF (UEFI) is selected, ProxMenux creates a 4 MB EFI system disk on the storage you pick and attaches it to the VM so the UEFI firmware has a place to store its variables.",
"tpmTitle": "TPM 2.0",
"tpmBody": "A virtual TPM 2.0 device is added automatically so Windows 11 / Server 2022 installers pass the hardware compatibility check.",
"isoTitle": "ISO mounting",
"isoBody": "The installation ISO is attached to <code>ide2</code>. The VirtIO drivers ISO is downloaded (if needed) and attached to <code>ide3</code>, ready for the <em>Load driver</em> step.",
"guestTitle": "QEMU Guest Agent",
"guestBody": "The guest agent channel is enabled in the VM config. The agent itself is installed inside Windows by running <code>virtio-win-guest-tools.exe</code> after setup."
},
"installOptions": {
"heading": "Windows installation options",
"intro": "ProxMenux offers two methods to obtain the Windows installation media:",
"uupTitle": "UUP Dump ISO Creator",
"uupLogoAlt": "UUP Dump logo",
"uupBody": "The <strong>UUP Dump ISO Creator</strong> script is a ProxMenux utility that builds a Windows ISO on the fly from Microsoft's Windows Update servers. It pulls clean, official installation files (including Insider Preview builds).",
"uupItems": [
"Access to the latest Windows builds.",
"Supports Insider Preview versions.",
"Clean, official Microsoft installation files.",
"Automatic ISO creation and mounting in the VM.",
"Supports Home, Pro and Enterprise editions."
],
"uupLearnMore": "Learn more about UUP Dump ISO Creator",
"localTitle": "Install with local ISO",
"localBody": "Uses a Windows ISO you have already uploaded to the host's local storage (<code>/var/lib/vz/template/iso</code>). The script lists every non-VirtIO ISO it finds and lets you pick one.",
"localImageAlt": "Local ISO selection menu",
"localImageCaption": "Local ISO selection menu"
},
"endToEnd": {
"heading": "What the script does end-to-end",
"items": [
"Obtains the Windows ISO (UUP Dump build or local copy).",
"Applies the default or advanced CPU / RAM / BIOS / machine-type configuration.",
"Opens the storage plan and attaches the selected virtual disks, imported disks and PCI devices.",
"Creates the EFI disk (UEFI installs) and attaches the TPM 2.0 device.",
"Mounts the Windows ISO on <code>ide2</code>.",
"Downloads and mounts the VirtIO drivers ISO on <code>ide3</code>.",
"Sets the boot order (disk first, then ISO).",
"Enables the QEMU Guest Agent channel.",
"Optionally runs the GPU passthrough assistant.",
"Generates a styled HTML description attached to the VM.",
"Starts the VM if you chose to."
]
},
"virtio": {
"heading": "VirtIO drivers during installation",
"body": "If you leave storage and networking at defaults (SATA + e1000), Windows will install without extra steps. However, the Proxmox storage plan always attaches virtual disks as SATA, which works out of the box. Where VirtIO becomes relevant is if, during the Advanced wizard, you pick VirtIO or SCSI for disks or VirtIO for the NIC — in that case Windows will not see those devices until the matching driver is loaded from the VirtIO ISO mounted at <code>ide3</code>.",
"warnTitle": "Without the VirtIO network driver there is no internet during install",
"warnBody": "If you picked VirtIO (<code>virtio</code>) as the network interface and do not load the driver during setup, Windows will not have internet access. That can block activation and Windows Update steps during first boot.",
"stepLabel": "Step",
"steps": [
{
"title": "Access the \"Where do you want to install Windows?\" screen",
"body": "During Windows setup, if no disks are shown, the storage driver for your selected interface (SCSI or VirtIO) is not loaded yet. Load it manually from the mounted VirtIO ISO.",
"img": "/vm/windows/virtio-step-1.png",
"caption": "Windows setup with no disks shown"
},
{
"title": "Click \"Load driver\"",
"bodyRich": "Click <strong>Load driver</strong> to browse the mounted VirtIO ISO and pick the storage driver that matches the interface you chose.",
"img": "/vm/windows/virtio-step-2.png",
"caption": "Click Load driver to browse the VirtIO ISO"
},
{
"title": "Browse to the correct driver folder",
"bodyRich": "On the VirtIO ISO navigate to the folder that matches the interface and Windows version — for example <code>viostor</code> for VirtIO SCSI, with subfolders per Windows edition (10 / 11 / Server).",
"img": "/vm/windows/virtio-step-3.png",
"caption": "Browse to the appropriate driver folder"
},
{
"title": "Select the driver",
"bodyRich": "Windows lists the available drivers. Pick the one that matches your setup (typically <strong>Red Hat VirtIO SCSI controller</strong>) and click <strong>Next</strong>.",
"img": "/vm/windows/virtio-step-4.png",
"caption": "Select the VirtIO driver that matches your disk interface"
},
{
"title": "(Optional) Install the network driver",
"bodyRich": "If you also picked VirtIO as the network interface, load the network driver from the <code>NetKVM</code> folder of the same ISO, selecting the subfolder for your Windows version. Without this step Windows installs without internet access.",
"img": "/vm/windows/virtio-step-5.png",
"caption": "Load the VirtIO network driver to enable internet during install"
}
],
"tipTitle": "Post-install: run virtio-win-guest-tools.exe",
"tipBody": "After Windows is installed, open the VirtIO ISO from File Explorer and run <code>virtio-win-guest-tools.exe</code>. It installs the remaining drivers (network, display, input, ballooning, QEMU Guest Agent) in one shot."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/utils/UUp-Dump-ISO-Creator",
"label": "UUP Dump ISO Creator",
"tail": " — generate up-to-date Windows installation ISOs on the Proxmox host."
},
{
"href": "/docs/disk-manager/import-disk-image-vm",
"label": "Import Disk Image to VM",
"tail": " — attach an existing Windows .vhdx / .vmdk to a fresh VM."
},
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — for Windows VMs with hardware-accelerated GPU."
},
{
"href": "/docs/help-info/vm-ct-commands",
"label": "VM and CT Management commands",
"tail": " — qm CLI reference."
},
{
"href": "/docs/create-vm",
"label": "Create VM overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,128 @@
{
"meta": {
"title": "Add Controller or NVMe to VM | ProxMenux Documentation",
"description": "PCI passthrough of a storage controller (SATA / SAS HBA) or NVMe device to a Proxmox VM using ProxMenux. Handles IOMMU enablement, conflict detection and qm set --hostpci wiring.",
"ogTitle": "Add Controller or NVMe to VM | ProxMenux Documentation",
"ogDescription": "Pass a whole SATA / SAS HBA or NVMe device into a Proxmox VM. ProxMenux handles IOMMU, conflict detection and hostpci wiring."
},
"header": {
"title": "Add Controller or NVMe to VM",
"description": "Pass a whole SATA / SAS host bus adapter (HBA) or NVMe device into a Proxmox VM via PCI passthrough. ProxMenux checks and — with your consent — enables IOMMU, enumerates the passthrough-eligible devices, filters out conflicts and wires the assignment with qm set --hostpci.",
"section": "Disk Manager · VM"
},
"intro": {
"title": "What this does (and does not) do",
"body": "This is <strong>device-level passthrough</strong>: the PCIe card leaves the host kernel's view and is bound to <code>vfio-pci</code>. The VM sees the controller itself — not the individual disks behind it — and loads its own driver for that exact model. Every disk attached to that controller follows it automatically, with native SMART data, full firmware features and no Proxmox layer in between."
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases with clear separation between \"collecting information, checking IOMMU and listing candidates\" and \"actually attaching the PCI device\". Until the final confirmation nothing is written to the VM config."
},
"iommu": {
"heading": "IOMMU groups — why the whole card leaves at once",
"body": "PCI passthrough is done per <strong>IOMMU group</strong>, which is the smallest unit the CPU's IOMMU can isolate. Everything inside a group moves together. If your SATA controller shares its IOMMU group with the USB controller, passing the SATA card to a VM also takes the USB ports with it — often undesirable.",
"outro": "ProxMenux shows the IOMMU group next to each device and warns you when a group carries more than just the controller you want. You can still proceed if the extra devices in the group are acceptable (all disk controllers, for example), or back out if they are not."
},
"prereqs": {
"heading": "Prerequisites",
"items": [
"<strong>CPU and motherboard support</strong> VT-d (Intel) or AMD-Vi, and it is enabled in firmware (BIOS/UEFI). ProxMenux can enable the kernel side for you, but it cannot flip the firmware switch.",
"The target VM is <strong>powered off</strong> before attaching PCI devices.",
"The controller/NVMe <strong>is not the one holding the Proxmox root filesystem</strong>. The script hides anything in use by the host.",
"Guest OS has drivers for the controller model. Linux covers virtually every HBA out of the box; Windows needs the vendor driver installed <em>before</em> you boot with the controller attached."
],
"warnTitle": "Live migration is not possible",
"warnBody": "A VM with PCI passthrough is tied to the node that physically holds the card. Live migration across nodes will fail. Plan backups / replication accordingly."
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick the target VM",
"bodyRich": "ProxMenux reads <code>qm list</code> and shows every VM. Pick the one that will receive the controller.",
"img": "/disk/nvme-passthrough/vm-selection.png",
"alt": "VM selection dialog",
"caption": "VM selection dialog"
},
{
"title": "IOMMU check",
"bodyRich": "If IOMMU is not enabled on the kernel cmdline, ProxMenux offers to enable it. It edits <code>/etc/kernel/cmdline</code> (for systemd-boot) or <code>/etc/default/grub</code> (for GRUB) and appends the correct parameter for your CPU:",
"items": [
"<code>intel_iommu=on</code> for Intel CPUs.",
"<code>amd_iommu=on</code> for AMD CPUs."
],
"outro": "A reboot is required after this change. The script prompts you to reboot now or later; the passthrough cannot continue until the new kernel cmdline is active.",
"img": "/disk/nvme-passthrough/iommu-warning.png",
"alt": "IOMMU Required dialog",
"caption": "IOMMU Required — offer to enable and reboot"
},
{
"title": "Device enumeration",
"body": "ProxMenux lists every storage controller (SATA / SAS HBA) and every NVMe device on the PCI bus. For each device it shows:",
"items": [
"PCI address (<code>00:17.0</code>, <code>01:00.0</code>, …).",
"Vendor / device description.",
"IOMMU group — and a ⚠ warning if the group is shared with other, unrelated devices.",
"The disks currently behind the controller (so you know what will follow it to the VM)."
],
"img": "/disk/nvme-passthrough/device-list.png",
"alt": "Controller / NVMe device enumeration",
"caption": "Controller / NVMe device enumeration with IOMMU group info"
},
{
"title": "Conflict detection",
"bodyRich": "The script blocks devices that are clearly unsafe: already assigned to another VM (via <code>hostpci</code> in that VM's config), in use by the host (root disk controller), or sitting in an IOMMU group whose other members the script cannot identify safely. Eligible devices are available for selection.",
"img": "/disk/nvme-passthrough/conflict-warning.png",
"alt": "Conflict detection warning",
"caption": "Conflict detection — device blocked with reason"
},
{
"title": "Attach and finalise",
"bodyRich": "For every selected device ProxMenux runs <code>qm set &lt;VMID&gt; --hostpciN &lt;pci-addr&gt;,pcie=1</code>, choosing the next free <code>hostpci</code> slot. If IOMMU was enabled during this session you are reminded to reboot before starting the VM.",
"img": "/disk/nvme-passthrough/assignment.png",
"alt": "Assignment summary",
"caption": "Assignment summary — hostpciN slots and PCI addresses attached"
}
]
},
"manual": {
"heading": "Manual equivalent"
},
"troubleshoot": {
"heading": "Troubleshooting",
"noGroupsTitle": "IOMMU enabled but no groups under /sys/kernel/iommu_groups/",
"noGroupsBody": "Reboot is required for the kernel cmdline to take effect. If the groups are still missing after reboot, VT-d / AMD-Vi is probably disabled in firmware — check the BIOS/UEFI setup.",
"busyTitle": "VM fails to start with \"hostpciN: device busy\"",
"busyBody": "Another process still holds the PCI device. Most common causes: a previous VM that crashed without releasing it, or the host kernel reclaimed it on the last boot. Run <code>lspci -nnk -s &lt;addr&gt;</code> to see which driver is bound; it should be <code>vfio-pci</code>. A full host reboot usually clears this.",
"noDisksTitle": "Guest sees the controller but not the disks",
"noDisksBody": "The controller model lacks an in-guest driver. Linux almost never hits this; Windows does — install the vendor driver (e.g. LSI / Broadcom for older SAS HBAs) while the card is detached, then reboot with the card attached.",
"sharedTitle": "Shared IOMMU group also exports an unrelated device",
"sharedBody": "Options: (a) move the card to a different PCIe slot to change its group, (b) enable <em>ACS override</em> in the kernel to split groups (security trade-off — research before applying), or (c) pick a different card in a cleaner group."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — alternative model: attach a physical disk via Proxmox without full PCIe passthrough."
},
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — same IOMMU / VFIO concepts applied to a GPU."
},
{
"href": "/docs/help-info/gpu-commands",
"label": "GPU Passthrough commands",
"tail": " — IOMMU verification commands also apply to controller / NVMe passthrough."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,142 @@
{
"meta": {
"title": "Format / Wipe Physical Disk | ProxMenux Documentation",
"description": "Secure physical disk wipe and format on Proxmox VE using ProxMenux. Four operation modes, strict safety filters (system / mounted / in-use disks blocked) and double confirmation including full path typing.",
"ogTitle": "Format / Wipe Physical Disk | ProxMenux Documentation",
"ogDescription": "Securely wipe or format a physical disk on Proxmox. Safe visibility rules, 4 operation modes, double confirmation."
},
"header": {
"title": "Format / Wipe Physical Disk",
"description": "Securely wipe or format a physical disk on the Proxmox host. ProxMenux only shows disks that are fully free (no system use, no guest reference, no mounts) and forces a double confirmation — yes/no plus typing the full disk path — before destroying any data.",
"section": "Disk Manager · Utilities"
},
"danger": {
"title": "Destructive tool",
"body": "Every operation here writes to the disk. There is no undo. ProxMenux applies strict safety filters and confirmations, but the responsibility for picking the right disk is yours. Read the disk path out loud twice before you type it."
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases with a triple-gate safety filter in between. The disk list, the operation mode and the file system details are all collected in Phase 1; nothing is written until Phase 2 passes a final re-validation right before executing."
},
"visibility": {
"heading": "Visibility rules",
"intro": "Before the menu even appears, ProxMenux filters the disk list. Only candidates that are provably safe are shown:",
"items": [
"<strong>Shown</strong> — disks <em>not</em> used by the host (root pool, swap, mounted, active ZFS/LVM/RAID) and <em>not</em> referenced by any VM/LXC config (running or stopped).",
"<strong>Hidden</strong> — host / system disks.",
"<strong>Hidden</strong> — disks referenced by a VM/LXC config."
],
"safetyTitle": "Safety at confirmation and execution",
"safetyItems": [
"Disks with stale / active metadata show detailed warnings <em>before</em> you confirm.",
"Disks used by a <strong>running</strong> VM are <strong>hard-blocked</strong> at confirmation.",
"Disks with mounted partitions are <strong>hard-blocked</strong> at execution (a fresh re-validation runs right before anything is written).",
"Two confirmations are always required: <em>yes/no</em> dialog + typing the full disk path exactly."
]
},
"modes": {
"heading": "Operation modes",
"intro": "After picking a disk you choose one of four modes. They differ in what they destroy and what they leave behind:",
"headerMode": "Mode",
"headerPart": "Partition table",
"headerData": "Data",
"headerUseCase": "Use case",
"rows": [
{
"mode": "1. Wipe all",
"part": "Destroyed",
"data": "Signatures wiped",
"useCase": "Starting fresh: everything on the disk goes, ready for a new layout."
},
{
"mode": "2. Remove FS labels",
"part": "Preserved",
"data": "Preserved",
"useCase": "Clears stale ZFS / LVM / RAID signatures so the disk stops being auto-claimed, without touching the data."
},
{
"mode": "3. Zero all data",
"part": "Preserved",
"data": "Destroyed (zeroed)",
"useCase": "Sanitise before handing the disk over, keeping the existing partition layout."
},
{
"mode": "4. Full format",
"part": "New GPT",
"data": "Destroyed",
"useCase": "Ready-to-use disk with a single new partition and a fresh filesystem."
}
],
"fullFormatOutro": "<strong>Full format</strong> continues with two extra dialogs:",
"fullFormatItems": [
"<strong>Filesystem</strong> — <code>ext4</code>, <code>xfs</code>, <code>exfat</code> (portable), or <code>btrfs</code>. Missing tools (for example <code>mkfs.btrfs</code>) abort with a clear message.",
"<strong>Label</strong> — optional filesystem label for identification."
]
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick a free disk",
"body": "ProxMenux lists every disk that passes the visibility filters above. Disks with ⚠ markers carry stale metadata and are shown with the details so you know what you are about to overwrite."
},
{
"title": "Pick an operation mode",
"bodyRich": "Choose between <strong>Wipe all</strong>, <strong>Remove FS labels</strong>, <strong>Zero all data</strong> or <strong>Full format</strong> according to the table above."
},
{
"title": "(Full format only) Pick filesystem and label",
"body": "ext4 / xfs / exfat / btrfs, plus an optional label."
},
{
"title": "Confirm twice",
"bodyRich": "ProxMenux shows a summary of what will happen. You accept with a yes/no dialog and <strong>type the full disk path</strong> exactly as shown (for example <code>/dev/sdc</code>). Anything else aborts."
},
{
"title": "Re-validation and execution",
"body": "Just before writing, the script re-checks the disk state. If a partition has been mounted or a VM started in the meantime, execution is aborted. Otherwise the chosen operation runs and a summary is printed at the end."
}
]
},
"manual": {
"heading": "Manual equivalents",
"body": "If you prefer to run the equivalent commands by hand:"
},
"troubleshoot": {
"notListedTitle": "Disk not listed in the menu",
"notListedBody": "It was filtered for safety. Common reasons: it is mounted (even at <code>/mnt/tmp</code>), it is an active ZFS / LVM / RAID member, it is referenced by a VM or LXC config, or it is your Proxmox root disk. Run <code>lsblk -f</code> and <code>cat /proc/mdstat</code> on the host to understand why.",
"busyTitle": "\"Disk may be busy\" / unmount failed",
"busyBody": "Something is still holding an open file on a partition of that disk — most often a container or a shell whose cwd is inside a mountpoint. Identify it with <code>lsof | grep /dev/sdX</code> or <code>fuser -vm /dev/sdX1</code>, stop it, then re-run the tool."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/smart-disk-test",
"label": "SMART Disk Health & Test",
"tail": " — check a disk before / after wiping to confirm it's healthy."
},
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — pass a freshly-formatted disk to a VM."
},
{
"href": "/docs/storage-share/host-local-disk",
"label": "Add local disk as Proxmox storage",
"tail": " — register a wiped disk as a Proxmox storage pool."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks commands",
"tail": " — lsblk, blkid, parted reference."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,110 @@
{
"meta": {
"title": "Import Disk Image to VM | ProxMenux Documentation",
"description": "Import a disk image file (.img / .qcow2 / .vmdk / .raw) into an existing Proxmox VM using ProxMenux. Per-image interface, SSD emulation and bootable flag, with qm importdisk under the hood.",
"ogTitle": "Import Disk Image to VM | ProxMenux Documentation",
"ogDescription": "Import .img / .qcow2 / .vmdk / .raw disk images into an existing VM with ProxMenux. Uses qm importdisk under the hood."
},
"header": {
"title": "Import Disk Image to VM",
"description": "Import a disk image file (.img, .qcow2, .vmdk or .raw) into an existing Proxmox VM. ProxMenux collects every decision up-front — target VM, Proxmox storage, source directory, interface, SSD emulation, boot order — and then runs qm importdisk for every selected image.",
"section": "Disk Manager · VM"
},
"intro": {
"title": "What this does",
"body": "Unlike <em>Import Disk to VM</em> (which attaches a raw physical disk), this flow takes a <strong>file</strong> sitting on the host — exported from another hypervisor, downloaded as a cloud image, extracted from a backup — and converts it into a proper Proxmox VM disk on the storage volume of your choice. The original file is preserved; ProxMenux copies it, it does not move it."
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases. Phase 1 collects every decision (VM, storage, source directory, images, per-image options) up-front via dialogs. Phase 2 runs <code>qm importdisk</code> for each selected image. Until Phase 2 begins, nothing is copied and the VM config is not touched."
},
"prereqs": {
"heading": "Prerequisites",
"items": [
"At least one VM defined on the host. The target VM should be <strong>powered off</strong>.",
"At least one image file of a supported format in the source directory. Supported: <code>.img</code>, <code>.qcow2</code>, <code>.vmdk</code>, <code>.raw</code>.",
"Enough free space on the target Proxmox storage to hold each imported disk.",
"ProxMenux looks for images in <code>/var/lib/vz/template/iso</code> by default. You can point it to any other directory on the host when it asks."
]
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick the target VM",
"bodyRich": "ProxMenux reads <code>qm list</code> and shows every VM. Pick the one that will receive the imported disk(s)."
},
{
"title": "Pick the Proxmox storage",
"bodyRich": "The list contains every storage that has the <code>images</code> content type enabled. If there is only one candidate it is auto-selected and the dialog is skipped."
},
{
"title": "Pick the source directory",
"bodyRich": "Choose the default directory (<code>/var/lib/vz/template/iso</code>) or type a custom path — typically where you downloaded / uploaded the image. The script rejects paths that do not exist."
},
{
"title": "Pick one or several images",
"bodyRich": "The directory is scanned for <code>.img</code> / <code>.qcow2</code> / <code>.vmdk</code> / <code>.raw</code> files. You can select several at once; each will go through the per-image options in the next step."
},
{
"title": "Per-image options",
"intro": "For every selected image ProxMenux asks:",
"items": [
"<strong>Interface</strong> — <code>scsi</code> (default), <code>virtio</code>, <code>sata</code> or <code>ide</code>. Matches how the guest will see the disk.",
"<strong>SSD emulation</strong> — only offered for non-VirtIO interfaces. Adds <code>ssd=1</code> so the guest advertises the disk as solid-state (useful for OS-level TRIM / alignment).",
"<strong>Bootable</strong> — if yes, ProxMenux adds the disk to the boot order so it becomes the primary boot device of the VM."
]
},
{
"title": "Import and attach",
"bodyRich": "ProxMenux runs <code>qm importdisk</code> for every image (converting format on the fly where needed), attaches the resulting disk to the next free slot (<code>scsiN</code>, <code>sataN</code>, …) with your chosen options and — if you marked any disk as bootable — updates the boot order. Progress shows in the terminal."
}
]
},
"manual": {
"heading": "Manual equivalent",
"body": "A single-image import maps to three <code>qm</code> commands:",
"warnTitle": "Image format conversion",
"warnBody": "When the target storage cannot hold the source format natively (for example, LVM storage cannot hold <code>.qcow2</code>), <code>qm importdisk</code> converts the image transparently. This can take several minutes for multi-GB images; plan accordingly and do not interrupt the script."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noImagesTitle": "\"No compatible disk images found\"",
"noImagesBody": "The script scanned the directory but found no <code>.img</code> / <code>.qcow2</code> / <code>.vmdk</code> / <code>.raw</code> file. Check the extension (case matters), that the file sits directly in the selected directory (no sub-directories are searched) and that permissions allow root to read it.",
"slowTitle": "Import is slow",
"slowBody": "VMDK → QCOW2 → raw conversions are CPU- and I/O-bound. Import speed depends on the source read speed, the target storage write speed and CPU for decompression. Prefer raw or qcow2 sources when possible.",
"uefiTitle": "Imported disk boots into UEFI shell",
"uefiBody": "The image was built for legacy (SeaBIOS) but the VM uses OVMF (or vice versa). Either switch the VM's BIOS in Proxmox to match the image, or rebuild the image in the correct mode before importing."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — same flow but for raw physical disks (passthrough)."
},
{
"href": "/docs/utils/import-vm",
"label": "Import VM from OVA / OVF",
"tail": " — when you have a full VM package, not just a disk image."
},
{
"href": "/docs/utils/UUp-Dump-ISO-Creator",
"label": "UUP Dump ISO Creator",
"tail": " — generate a Windows ISO if you need one for a fresh install."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks commands",
"tail": " — qm importdisk and qemu-img convert reference."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,115 @@
{
"meta": {
"title": "Import Disk to LXC | ProxMenux Documentation",
"description": "Attach a physical disk to an existing LXC container on Proxmox VE using ProxMenux. Handles filesystem detection / formatting, mount point, unprivileged → privileged conversion and persistent device paths.",
"ogTitle": "Import Disk to LXC | ProxMenux Documentation",
"ogDescription": "Attach a physical disk to an existing LXC container. Handles filesystem, mount point and unprivileged → privileged conversion."
},
"header": {
"title": "Import Disk to LXC",
"description": "Attach a physical disk to an existing LXC container on the Proxmox host. ProxMenux detects free disks, optionally formats them with a supported filesystem, and wires the partition to a mount point inside the container using persistent device paths.",
"section": "Disk Manager · LXC"
},
"intro": {
"title": "VM passthrough vs LXC passthrough",
"body": "LXC passthrough is <strong>not a raw block device</strong>. The container gets a <em>mount point</em> — i.e. a directory backed by a partition you pick on the host. Unlike a VM, the guest kernel is the host kernel, so the filesystem (ext4 / xfs / btrfs) is read and managed by Proxmox itself and then exposed to the container."
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases with clear separation between \"collecting information and decisions\" and \"actually changing the container config\". Until the final confirmation, nothing is mounted into the CT.",
"summary": "ProxMenux filters out the root disk, mounted disks, and disks already referenced by any VM/LXC config. Disks with active ZFS/LVM/RAID membership are hidden; stale signatures show a ⚠ label so you can wipe them before formatting."
},
"prereqs": {
"heading": "Prerequisites",
"items": [
"At least one LXC container defined on the host.",
"The container is <strong>privileged</strong>, or you accept the script's offer to convert it.",
"At least one physical disk not in use by the host or any other guest."
],
"warnTitle": "Privileged container required",
"warnBody": "Direct device passthrough to an LXC container only works if the container is <strong>privileged</strong>. If the script detects <code>unprivileged: 1</code> in the config it offers to convert it in place (edits <code>/etc/pve/lxc/&lt;CTID&gt;.conf</code>). Cancel if you cannot accept the security trade-off of a privileged container."
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick the target container",
"img": "/disk/select-container.png",
"caption": "Container selection menu",
"bodyRich": "ProxMenux lists every LXC container on the host (<code>pct list</code>). Pick the one that will receive the disk. If the container is unprivileged you are offered to convert it now."
},
{
"title": "Pick the physical disk",
"img": "/disk/disk-selection-ct.png",
"caption": "Free disks detected on the host (with ⚠ labels for stale metadata)",
"bodyRich": "Only safe candidates are shown. Unlike the VM flow, this script attaches <strong>one disk per run</strong> — run it again for each extra disk you want to add."
},
{
"title": "Format or reuse",
"intro": "The script inspects the disk:",
"items": [
"If it already carries a supported filesystem (ext4 / xfs / btrfs) you can reuse it as-is (existing files are preserved).",
"If it has no supported filesystem you are offered to format it. Pick ext4 / xfs / btrfs."
]
},
{
"title": "Pick the mount point",
"bodyRich": "Type the path where the container should see the disk, e.g. <code>/mnt/data</code> or <code>/mnt/disk_passthrough</code>. This is the path <em>inside</em> the container; the host already sees the partition under <code>/dev/disk/by-id/…</code>."
},
{
"title": "Attach and verify",
"img": "/disk/assignment-ct.png",
"caption": "Assignment to CT",
"bodyRich": "ProxMenux appends a fresh <code>mpN:</code> entry to the container config, skipping indexes already in use, and re-reads the config to confirm. If the container is running the mount is exec'd live; otherwise it takes effect on the next start.",
"extraImg": "/disk/result-point.png",
"extraAlt": "Mount point created successfully",
"extraCaption": "Mount point created and verified"
}
]
},
"manual": {
"heading": "Manual equivalent",
"body": "The script wraps <code>pct set</code>. A direct invocation for a single disk looks like:"
},
"important": {
"heading": "Important considerations",
"items": [
"<strong>One disk per run</strong>. Re-run the script for each additional disk.",
"Do <strong>not</strong> attach the same partition to several containers that might mount it simultaneously — concurrent writes corrupt the filesystem.",
"<strong>Old metadata</strong> (RAID / ZFS / LVM signatures) must be cleared manually before the script will let you format, otherwise <code>mkfs</code> refuses to overwrite. Use the <wipeLink>Format / Wipe Physical Disk</wipeLink> tool for that."
]
},
"troubleshoot": {
"heading": "Troubleshooting",
"unprivTitle": "\"Cannot continue with an unprivileged container\"",
"unprivBody": "You declined the conversion offer. Either re-run and accept the conversion, or convert the container manually by editing <code>/etc/pve/lxc/&lt;CTID&gt;.conf</code> and replacing <code>unprivileged: 1</code> with <code>unprivileged: 0</code>. You can also rebuild the container as privileged if you prefer not to convert in place.",
"permsTitle": "Permissions inside the container are wrong",
"permsBody": "Mounts from the host into a privileged container land as <code>root:root</code>. If the service inside the CT runs as a different user (e.g. <code>www-data</code> for Nextcloud), <code>chown</code>/<code>chmod</code> inside the container to match its UID/GID after the first mount."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/import-disk-vm",
"label": "Import Disk to VM",
"tail": " — equivalent flow for VMs."
},
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Points (Host ↔ CT)",
"tail": " — share host directories with a CT instead of attaching a whole disk."
},
{
"href": "/docs/help-info/vm-ct-commands",
"label": "VM and CT Management commands",
"tail": " — pct config / push / pull reference."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,113 @@
{
"meta": {
"title": "Import Disk to VM | ProxMenux Documentation",
"description": "Attach a physical disk to an existing Proxmox VM with ProxMenux. Safe disk detection (excludes system, mounted, in-use, ZFS/RAID/LVM), persistent /dev/disk/by-id paths and SATA / SCSI / VirtIO / IDE interfaces.",
"ogTitle": "Import Disk to VM | ProxMenux Documentation",
"ogDescription": "Attach a physical disk to an existing Proxmox VM. Uses persistent /dev/disk/by-id paths and supports SATA / SCSI / VirtIO / IDE."
},
"header": {
"title": "Import Disk to VM",
"description": "Attach a physical disk that already exists on the Proxmox host to an existing virtual machine. ProxMenux detects free disks, lets you pick the target VM, the bus type (SATA / SCSI / VirtIO / IDE) and attaches everything using persistent /dev/disk/by-id paths so the mapping survives reboots and device-order changes.",
"section": "Disk Manager · VM"
},
"intro": {
"title": "What this does",
"body": "This is a raw-disk passthrough: the guest OS sees the drive as a real block device (with its SMART data and native geometry). The disk is attached via its <code>/dev/disk/by-id/…</code> path — not <code>/dev/sdX</code> — so the assignment does not break if disk controllers enumerate devices in a different order on the next boot."
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases with clear separation between \"collecting information and decisions\" and \"actually attaching disks to the VM\". Until the final confirmation, the VM config is untouched.",
"summary": "ProxMenux filters out anything it cannot safely pass: the root disk, disks mounted on the host, members of an active ZFS/LVM/RAID pool and disks already referenced by any VM/LXC config. Disks with <em>stale</em> metadata (old ZFS / RAID / LVM signatures that are no longer in use) are shown with a ⚠ label but are not blocked."
},
"prereqs": {
"heading": "Prerequisites",
"items": [
"At least one VM defined on the host (the script dispatches straight to <code>qm list</code>).",
"The <strong>target VM is powered off</strong>. If it is running the script aborts with a message — live disk hot-add is outside the scope of this flow.",
"At least one physical disk on the host that is not in use by the host or any other guest."
]
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick the target VM",
"bodyRich": "ProxMenux lists every VM on the host (via <code>qm list</code>). Pick the one that will receive the disk. If the VM is running the script aborts and asks you to shut it down first."
},
{
"title": "Pick the physical disk(s) to attach",
"img": "/disk/disk-selection.png",
"caption": "Free disks detected on the host (with ⚠ labels for stale metadata)",
"body": "The script scans every host disk and shows only the ones that are safe to attach. The checklist lets you select one or several at once. Disks with old ZFS / LVM / RAID signatures still show up, labelled with ⚠ so you know they need a wipe before the guest can format them."
},
{
"title": "Pick the bus interface",
"img": "/disk/disk-assigment.png",
"caption": "Bus interface selection",
"intro": "Pick how the guest should see the disk:",
"items": [
"<strong>SCSI</strong> — modern default for Linux and Windows with VirtIO-SCSI drivers installed.",
"<strong>SATA</strong> — broad compatibility, works out of the box on virtually every guest.",
"<strong>VirtIO</strong> — paravirtualised block device, fastest but requires guest drivers.",
"<strong>IDE</strong> — for legacy guests that lack any of the above drivers."
]
},
{
"title": "Attach and verify",
"bodyRich": "ProxMenux attaches every selected disk with its best <code>/dev/disk/by-id/</code> path, skips slot indexes that are already in use in the VM config (<code>scsi0</code>, <code>sata0</code>, …) and re-reads the config to confirm the assignment. A summary is printed at the end."
}
]
},
"manual": {
"heading": "Manual equivalent",
"body": "The script is a wrapper around <code>qm set</code>. The exact command for a single disk looks like this:",
"migrationTitle": "Live migration is not possible",
"migrationBody": "A VM with a passthrough disk is <strong>tied to the host that exposes that disk</strong>. Live migration to another Proxmox node will fail because the target node does not see the same <code>/dev/disk/by-id/…</code> path. Use replication or backup/restore instead, or pick virtual disks on shared storage if you need mobility.",
"shareTitle": "Do not share a physical disk between VMs",
"shareBody": "Attaching the same physical disk to two VMs at the same time will corrupt data on next write. ProxMenux detects this situation and blocks it, but if you bypass the script (direct <code>qm set</code>), make sure only one guest ever mounts the disk."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noDisksTitle": "\"No disks available for this VM\"",
"noDisksIntro": "The script found disks, but every candidate was filtered out. Common reasons:",
"noDisksItems": [
"Every remaining disk is already referenced in the target VM's config.",
"Every remaining disk is mounted on the host or is part of an active ZFS / LVM / RAID.",
"The host only has the root disk installed."
],
"noDisksOutro": "Run <code>lsblk -f</code> on the host to review the state of each disk.",
"noVisibleTitle": "VM does not see the disk after boot",
"noVisibleBody": "If you picked <strong>SCSI</strong> or <strong>VirtIO</strong>, the guest needs the matching driver. On Linux that is kernel-native; on Windows you need the VirtIO ISO and a driver install (see the <winLink>Create VM: System Windows</winLink> page). Switching to SATA in the VM's hardware tab is a quick workaround to confirm the disk is physically attached."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/import-disk-image-vm",
"label": "Import Disk Image to VM",
"tail": " — same flow but for image files (qcow2 / vmdk / raw / img)."
},
{
"href": "/docs/disk-manager/import-disk-lxc",
"label": "Import Disk to LXC",
"tail": " — equivalent flow for LXC containers."
},
{
"href": "/docs/disk-manager/add-controller-nvme-vm",
"label": "Add Controller or NVMe to VM",
"tail": " — when you need full PCIe / NVMe passthrough rather than disk attach."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks commands",
"tail": " — qm importdisk and related shell reference."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,135 @@
{
"meta": {
"title": "Proxmox Disk Manager — Attach Disks to VMs / LXC, SMART Tests, Wipe | ProxMenux",
"description": "Manage physical disks on a Proxmox VE host with ProxMenux: pass disks through to VMs or LXC containers (qm set scsi/sata/virtio, pct mp), import qcow2 / vmdk / vdi disk images, pass through whole HBAs or NVMe controllers, safely wipe disks and run SMART self-tests.",
"ogTitle": "Proxmox Disk Manager — Attach Disks to VMs / LXC, SMART Tests, Wipe",
"ogDescription": "Attach disks to VMs / LXC, import disk images, PCI passthrough for controllers, safe wipe and SMART tests on Proxmox VE.",
"twitterTitle": "Proxmox Disk Manager | ProxMenux",
"twitterDescription": "Attach disks to VMs / LXC, import images, PCI passthrough, safe wipe and SMART tests."
},
"header": {
"title": "Disk Manager",
"description": "The Disk Manager menu groups the ProxMenux tools for handling physical disks on a Proxmox host: attach disks to VMs and LXC containers, import disk images, pass through a whole controller or NVMe device, wipe disks safely and run SMART health tests.",
"section": "Disk Manager"
},
"intro": {
"title": "What this menu is for",
"body": "Every option here operates on <strong>physical disks already visible to the Proxmox host</strong>. The menu is split in three groups — <strong>VM</strong> (attach disks or import images into a virtual machine), <strong>LXC</strong> (attach disks to a container), and <strong>Utilities</strong> (safe format, SMART health). Safety checks apply everywhere: system disks and disks already in use are hidden or blocked."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, select <strong>Disk Manager</strong>. You will see this:",
"imageAlt": "Disk Manager menu with VM, LXC and Utilities blocks"
},
"groups": {
"heading": "Three tool groups",
"intro": "The Disk Manager menu is organised in three groups — <strong>VM</strong>, <strong>LXC</strong> and <strong>Utilities</strong>. Click a card to jump straight to the tools in that group.",
"vmTitle": "VM",
"vmBody": "Tools that operate on existing virtual machines. The VM must be powered off; ProxMenux validates this before touching the config.",
"vmItems": [
"Import Disk to VM",
"Import Disk Image to VM",
"Add Controller or NVMe to VM"
],
"lxcTitle": "LXC",
"lxcBody": "Tools that operate on existing containers. Direct device passthrough needs a privileged container; the script offers to convert it if necessary.",
"lxcItems": [
"Import Disk to LXC"
],
"utilitiesTitle": "Utilities",
"utilitiesBody": "Host-side tools that operate on the disks themselves, independently of any VM or container.",
"utilitiesItems": [
"Format / Wipe Physical Disk",
"SMART Disk Health & Test"
]
},
"vm": {
"heading": "VM",
"intro": "Tools that operate on existing virtual machines. The VM must be powered off; ProxMenux validates this before touching the config.",
"options": [
{
"icon": "HardDrive",
"href": "/docs/disk-manager/import-disk-vm",
"title": "Import Disk to VM",
"description": "Attach an unassigned physical disk to an existing VM. Supports SATA / SCSI / VirtIO / IDE, uses persistent /dev/disk/by-id paths."
},
{
"icon": "FileDown",
"href": "/docs/disk-manager/import-disk-image-vm",
"title": "Import Disk Image to VM",
"description": "Import disk image files (.img / .qcow2 / .vmdk / .raw) into an existing VM. Two-phase flow, qm importdisk under the hood."
},
{
"icon": "Cpu",
"href": "/docs/disk-manager/add-controller-nvme-vm",
"title": "Add Controller or NVMe to VM",
"description": "PCI passthrough of a whole SATA / SAS HBA or NVMe device to a VM. Handles IOMMU enablement and conflict detection."
}
]
},
"lxc": {
"heading": "LXC",
"intro": "Tools that operate on existing LXC containers. Direct device passthrough requires a privileged container; the script offers to convert the container if needed.",
"options": [
{
"icon": "Boxes",
"href": "/docs/disk-manager/import-disk-lxc",
"title": "Import Disk to LXC",
"description": "Attach an unassigned physical disk to an existing LXC container as a mount point. Handles filesystem detection / format and privileged conversion."
}
]
},
"utilities": {
"heading": "Utilities",
"intro": "Host-side tools that operate on the disks themselves, independently of any VM or container.",
"options": [
{
"icon": "Eraser",
"href": "/docs/disk-manager/format-disk",
"title": "Format / Wipe Physical Disk (Safe)",
"description": "Secure disk wipe with strict safety controls: only fully free disks are shown and a double confirmation is always required."
},
{
"icon": "Activity",
"href": "/docs/disk-manager/smart-disk-test",
"title": "SMART Disk Health & Test",
"description": "Run SMART health checks and short / long self-tests on SATA, SAS and NVMe drives. Exports JSON for the Monitor."
}
]
},
"safety": {
"title": "Safety rules shared by every option",
"intro": "ProxMenux filters out anything that could harm the host:",
"items": [
"The <strong>system disk</strong> (root pool, swap, active ZFS / LVM / RAID members) is always hidden.",
"Disks <strong>mounted</strong> anywhere on the host are hidden or blocked at execution.",
"Disks <strong>referenced by a running VM or LXC</strong> cannot be reassigned or wiped.",
"Operations that can change the host state (IOMMU enable, wipe) require explicit confirmation."
]
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share",
"label": "Storage & Share Manager",
"tail": " — register storage in Proxmox itself (NFS / Samba / iSCSI / local) and share folders between host and CTs."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks commands",
"tail": " — block devices, LVM, pvesm, SMART reference."
},
{
"href": "/docs/help-info/zfs-commands",
"label": "ZFS Management commands",
"tail": " — for ZFS pools and datasets."
},
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — same IOMMU / VFIO concepts applied to GPUs."
}
]
}
}
@@ -0,0 +1,146 @@
{
"meta": {
"title": "SMART Disk Health & Test | ProxMenux Documentation",
"description": "Run SMART health checks and disk tests on Proxmox VE with ProxMenux. Supports SATA / SAS (smartmontools) and NVMe (nvme-cli). Short and long self-tests, JSON export for ProxMenux Monitor integration.",
"ogTitle": "SMART Disk Health & Test | ProxMenux Documentation",
"ogDescription": "SMART health checks and self-tests for SATA / SAS and NVMe drives on Proxmox. JSON export for the Monitor."
},
"header": {
"title": "SMART Disk Health & Test",
"description": "Read SMART data and trigger self-tests on the physical disks attached to the Proxmox host. ProxMenux auto-installs smartmontools for SATA / SAS and nvme-cli for NVMe, runs the action inside the drive firmware (long tests survive terminal close) and exports JSON results for the ProxMenux Monitor.",
"section": "Disk Manager · Utilities"
},
"intro": {
"title": "What this is for",
"body": "SMART (Self-Monitoring, Analysis and Reporting Technology) lets the drive itself report its health and run self-tests. This tool exposes that data without you needing to remember the right <code>smartctl</code> / <code>nvme</code> invocation, and persists the output as JSON so the Monitor can graph trends over time."
},
"howRuns": {
"heading": "How the script runs",
"body": "All actions here are non-destructive — SMART reads the drive firmware counters, and self-tests are queued inside the drive itself. No phase separation is needed. The flow is: dependency check → disk selection → action selection → tool invocation (smartctl or nvme-cli depending on the disk bus) → printed output plus JSON export for the Monitor."
},
"deps": {
"heading": "Dependencies",
"body": "The tool auto-installs what it needs on first run. SATA / SAS drives rely on <code>smartmontools</code>; NVMe drives rely on <code>nvme-cli</code>. Both:"
},
"actions": {
"heading": "Available actions",
"headerAction": "Action",
"headerWhat": "What it reads / runs",
"headerDur": "Duration",
"rows": [
{
"action": "Quick health status",
"whatRich": "Overall PASSED/FAILED + key attributes.<br /><code>smartctl -H</code> + <code>-A</code> (SATA/SAS) or <code>nvme smart-log</code> (NVMe).",
"dur": "Instant"
},
{
"action": "Full report",
"whatRich": "Complete SMART data, scrollable. <code>smartctl -x</code> for SATA/SAS or <code>nvme smart-log</code> + <code>id-ctrl</code> for NVMe.",
"dur": "Instant"
},
{
"action": "Short test",
"what": "Basic surface and electrical check, queued inside the drive firmware.",
"dur": "~2 minutes"
},
{
"action": "Long test",
"what": "Full scan of the entire surface. Runs on the drive hardware — persists even if you close the terminal.",
"dur": "Hours (disk size dependent)"
},
{
"action": "Check test progress",
"what": "Status of the active or most recent self-test.",
"dur": "Instant"
}
],
"tipTitle": "Long tests survive terminal close",
"tipBody": "A long test is queued <em>inside the drive</em> — it does not depend on the ProxMenux process staying alive. You can close the terminal, reboot the Proxmox host (the test picks up where it left off on some drives) or just come back later and use <strong>Check test progress</strong> to see the result."
},
"json": {
"heading": "JSON export for the Monitor",
"intro": "Every run writes a timestamped JSON file to <code>/usr/local/share/proxmenux/smart/&lt;disk&gt;/</code>. The structure is:",
"outro": "The ProxMenux Monitor picks these up to render health trends per disk; old files are rotated out automatically once the retention limit is reached."
},
"steps": {
"heading": "Step-by-step",
"stepLabel": "Step",
"list": [
{
"title": "Pick a disk",
"body": "ProxMenux lists every physical disk on the host with its model and size. Unlike the Format tool, this list is not filtered by safety — reading SMART is a non-destructive operation.",
"img": "/disk/smart/disk-selection.png",
"alt": "SMART disk selection menu",
"caption": "SMART disk selection menu"
},
{
"title": "Pick an action",
"body": "Choose between Quick health status, Full report, Short test, Long test or Check progress. The menu stays open after each action so you can chain several queries against the same disk.",
"img": "/disk/smart/action-menu.png",
"alt": "SMART action menu",
"caption": "SMART action menu (5 actions + cancel)"
},
{
"title": "(Long test only) Confirm background execution",
"body": "ProxMenux warns that the test will keep running after the terminal closes and shows where the JSON result will land. Accept to queue it.",
"img": "/disk/smart/long-test-warning.png",
"alt": "Long test confirmation dialog",
"caption": "Long test confirmation — runs in background, result saved to JSON"
},
{
"title": "Review results",
"bodyRich": "Status and report are printed to the terminal and written to JSON. For long tests, return later and run <strong>Check test progress</strong> on the same disk to see the outcome.",
"img": "/disk/smart/quick-status.png",
"alt": "Quick health status output",
"caption": "Quick health status output (SATA — smartctl -H + -A)"
}
]
},
"manual": {
"heading": "Manual equivalents",
"nvmeWarnTitle": "NVMe self-tests are drive-firmware dependent",
"nvmeWarnBody": "Not every NVMe drive supports the short/long self-test command. If a drive refuses the test, the SMART log and the ID controller data (<code>nvme smart-log</code> + <code>id-ctrl</code>) are still the most reliable health signal."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noSmartTitle": "\"Could not read SMART data from /dev/sdX\"",
"noSmartBody": "The disk is probably behind a RAID / SAS controller that does not pass SMART through. With megaraid-based cards, try <code>smartctl -d megaraid,N /dev/sdX</code>. For HBAs in IT mode the direct invocation works.",
"longTitle": "Long test never completes",
"longBody": "The test is queued on the drive firmware and pauses if the disk is under heavy load. Running it overnight on an idle system usually works. You can also check <code>smartctl -c</code> to see percentage remaining; if it is stuck at a fixed LBA, the disk is failing at that sector."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/format-disk",
"label": "Format / Wipe Physical Disk",
"tail": " — reuse a disk after confirming it's healthy."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks commands → SMART Disk Health",
"tail": " — copy-pasteable smartctl / nvme reference."
},
{
"href": "/docs/help-info/zfs-commands",
"label": "ZFS Management commands",
"tail": " — zpool scrub for the storage-layer equivalent of SMART tests."
},
{
"href": "/docs/monitor/dashboard/storage",
"label": "ProxMenux Monitor — Storage tab",
"tail": " — disk drill-in that consumes the JSON exported here (full SMART table, history, PDF report)."
},
{
"href": "/docs/monitor/dashboard/hardware",
"label": "ProxMenux Monitor — Hardware tab",
"tail": " — Storage Summary with model, capacity and negotiated link speed (current vs maximum on NVMe)."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,58 @@
{
"meta": {
"title": "External Repositories | ProxMenux Documentation",
"description": "ProxMenux integrates with selected external script repositories (community-scripts, ZimaOS) as alternatives in some menu sections. Each external script is clearly labelled with its source; bug reports go to the original maintainer.",
"ogTitle": "External Repositories | ProxMenux Documentation",
"ogDescription": "External script repositories integrated into ProxMenux as alternative options in menus."
},
"header": {
"title": "External Repositories",
"description": "ProxMenux integrates with selected external script repositories as alternative options in some menu sections. These scripts come from trusted third-party sources and are clearly labelled with their origin when shown in the menu.",
"section": "External Repositories"
},
"practice": {
"title": "What this means in practice",
"body": "When a menu option is backed by an external script (rather than ProxMenux's own code), the menu explicitly says where it's from and which repository it loads. ProxMenux acts as a launcher — it doesn't modify the external scripts. Issues with what an external script does belong to that repository's maintainer, not to ProxMenux."
},
"integrated": {
"heading": "Currently integrated",
"usedInLabel": "Used in:",
"items": [
{
"name": "community-scripts / ProxmoxVE",
"url": "https://community-scripts.github.io/ProxmoxVE/",
"description": "Spiritual successor to tteck's helper scripts. Large catalog of one-shot scripts to deploy LXCs (Home Assistant, Plex, Frigate, …), VMs, addons and PVE tweaks.",
"usedIn": "Helper Scripts launcher, Network (NIC offloading fix for Intel e1000e)"
}
]
},
"attribution": {
"heading": "Attribution & recognition",
"items": [
"Credit is always given to the original authors in the menu and in the documentation page that wraps the script.",
"A link to the source repository is shown — both before running the script and on the matching docs page.",
"Users are encouraged to support the developers of these external projects (give a ⭐, sponsor, file quality bug reports)."
]
},
"report": {
"title": "Where to report problems with external scripts",
"body": "If a script from one of these external repositories doesn't work as expected, <strong>report it directly to that repository</strong> — not to ProxMenux. ProxMenux just downloads and runs the script verbatim; it doesn't modify the source. The original maintainer is the right person to triage and fix it. ProxMenux issues are for problems with the launcher itself or with how ProxMenux integrates the external script."
},
"suggest": {
"heading": "Suggesting new external repositories",
"intro": "Found a script or repository that would fit nicely into a ProxMenux menu? Suggest it via:",
"discussionTitle": "💬 Open a Discussion",
"discussionBody": "Best for ideas — gets community input before becoming a feature request.",
"issueTitle": "🐛 Open an Issue",
"issueBody": "For specific feature requests with a clear scope."
},
"candidate": {
"title": "What makes a good integration candidate",
"items": [
"Open source with an active maintainer.",
"Idempotent / safe to run more than once.",
"Doesn't silently modify Proxmox core config.",
"Solves a problem ProxMenux doesn't already cover (avoids feature duplication)."
]
}
}
+677
View File
@@ -0,0 +1,677 @@
{
"meta": {
"title": "Glossary | ProxMenux Documentation",
"description": "Definitions of the technical terms used throughout the ProxMenux documentation — Proxmox concepts (VM, LXC, qm, pct, pmxcfs), virtualization fundamentals (KVM, IOMMU, VFIO, OVMF), storage (ZFS, ARC, LVM, vzdump, PBS), network (bridge, VLAN, nftables) and ProxMenux-specific terminology.",
"ogTitle": "Glossary | ProxMenux Documentation",
"ogDescription": "Quick reference for the technical terms used across the ProxMenux documentation."
},
"header": {
"title": "Glossary",
"description": "Definitions of the technical terms used throughout the ProxMenux documentation. Covers Proxmox concepts, virtualization fundamentals, storage, networking, Linux internals and ProxMenux-specific terminology.",
"section": "Glossary"
},
"callout": {
"title": "How to use this page",
"bodyRich": "Each entry has a category badge and a short definition. <em>See also</em> links jump to the doc page where the term is most relevant. Use the AZ navigation below to scroll directly to a letter."
},
"jumpHeading": "Jump to letter",
"seeAlsoLabel": "See also:",
"aliasesLabel": "also:",
"missingCallout": {
"title": "Missing a term?",
"leadRich": "If a term in the docs isn't defined here, open an issue or PR on <ext>GitHub</ext> — the glossary lives in <code>web/app/docs/glossary/page.tsx</code> as a simple data array."
},
"entries": [
{
"term": "ACS",
"aliases": [
"Access Control Services",
"ACS override"
],
"category": "Virtualization",
"definitionRich": "PCIe extension that prevents direct peer-to-peer traffic between devices, ensuring each device sits in its own IOMMU group. The <em>ACS override</em> kernel patch loosens this so devices in the same IOMMU group can be passed to different VMs — useful but a security trade-off.",
"seeAlso": [
{
"label": "Add Controller or NVMe to VM",
"href": "/docs/disk-manager/add-controller-nvme-vm"
}
]
},
{
"term": "ARC",
"aliases": [
"Adaptive Replacement Cache"
],
"category": "Storage",
"definitionRich": "ZFS's in-memory read cache. Holds recently and frequently used data blocks; size scales with available host RAM. Defaults are aggressive — Proxmox post-install lets you cap it.",
"seeAlso": [
{
"label": "Post-Install: Storage",
"href": "/docs/post-install/storage"
},
{
"label": "ZFS commands",
"href": "/docs/help-info/zfs-commands"
}
]
},
{
"term": "Bind mount",
"category": "Linux",
"definitionRich": "A Linux feature that exposes one part of the filesystem at another path. ProxMenux uses bind mounts to share host directories with LXC containers via <code>pct set -mpN</code>.",
"seeAlso": [
{
"label": "LXC Mount Points",
"href": "/docs/storage-share/lxc-mount-points"
}
]
},
{
"term": "Bond",
"aliases": [
"Network bond",
"Link aggregation"
],
"category": "Network",
"definitionRich": "Combines multiple physical network interfaces into one logical interface — for redundancy (active-backup), throughput (LACP / 802.3ad) or both. Configured in <code>/etc/network/interfaces</code>."
},
{
"term": "Bridge",
"aliases": [
"vmbrX",
"vmbr0",
"Linux bridge"
],
"category": "Network",
"definitionRich": "A virtual layer-2 switch on the host. <code>vmbr0</code> is the default Proxmox bridge that connects VMs and containers to the physical network. Multiple bridges (<code>vmbr1</code>, <code>vmbr2</code>...) isolate groups of guests.",
"seeAlso": [
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis"
}
]
},
{
"term": "Ceph",
"category": "Storage",
"definitionRich": "Distributed storage system tightly integrated with Proxmox for hyper-converged clusters. Provides object, block and file storage backed by OSDs (Object Storage Daemons). PVE 9 requires Ceph 19.x (Squid).",
"seeAlso": [
{
"label": "Upgrade PVE 8 to PVE 9",
"href": "/docs/utils/upgrade-pve8-pve9"
}
]
},
{
"term": "CT",
"aliases": [
"Container",
"LXC container"
],
"category": "Proxmox",
"definitionRich": "Short for \"container\" — Proxmox terminology for an LXC instance. Has a numeric CTID that maps to <code>/etc/pve/lxc/&lt;CTID&gt;.conf</code>. See also <strong>LXC</strong>.",
"seeAlso": [
{
"label": "VM and CT Management",
"href": "/docs/help-info/vm-ct-commands"
}
]
},
{
"term": "deb822",
"category": "Linux",
"definitionRich": "Modern format for APT repository sources, using <code>.sources</code> files with structured key/value blocks (Types, URIs, Suites, Components, Signed-By). Replaces the legacy single-line <code>.list</code> format. Standard from PVE 9 / Debian Trixie onward.",
"seeAlso": [
{
"label": "Upgrade PVE 8 to PVE 9",
"href": "/docs/utils/upgrade-pve8-pve9"
}
]
},
{
"term": "dGPU",
"aliases": [
"Discrete GPU"
],
"category": "Virtualization",
"definitionRich": "A standalone graphics card on its own PCIe slot (e.g. NVIDIA RTX, AMD Radeon). Contrasts with <strong>iGPU</strong>. Typically used for VFIO passthrough to a single VM, not for sharing across LXCs.",
"seeAlso": [
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough"
}
]
},
{
"term": "Dialog",
"category": "Linux",
"definitionRich": "ncurses-based tool for drawing menus, prompts and progress bars in a terminal. ProxMenux is built around dialog menus."
},
{
"term": "DKMS",
"aliases": [
"Dynamic Kernel Module Support"
],
"category": "Linux",
"definitionRich": "Framework that automatically rebuilds out-of-tree kernel modules (NVIDIA, ZFS, custom drivers) when the kernel is upgraded. Avoids modules being left behind after kernel updates.",
"seeAlso": [
{
"label": "Install Coral TPU (Host)",
"href": "/docs/hardware/install-coral-tpu-host"
}
]
},
{
"term": "Fail2Ban",
"category": "Linux",
"definitionRich": "Intrusion prevention service that watches log files for repeated authentication failures and bans the offending IPs at the firewall layer. ProxMenux ships pre-configured jails for SSH, the Proxmox UI and the Monitor.",
"seeAlso": [
{
"label": "Fail2Ban",
"href": "/docs/security/fail2ban"
}
]
},
{
"term": "Fastfetch",
"category": "Linux",
"definitionRich": "ASCII-art system info tool that runs on shell login (the \"system summary banner\"). Replaces the older <code>neofetch</code>; available as an opt-in option in ProxMenux Post-Install.",
"seeAlso": [
{
"label": "Post-Install: Optional",
"href": "/docs/post-install/optional"
}
]
},
{
"term": "GRUB",
"aliases": [
"GRand Unified Bootloader"
],
"category": "Linux",
"definitionRich": "Boot loader for most Linux distributions. Configuration lives in <code>/etc/default/grub</code> + <code>/boot/grub/</code>. Modified for IOMMU enablement, kernel parameters and EFI boot entries. Run <code>update-grub</code> after edits.",
"seeAlso": [
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands"
}
]
},
{
"term": "iGPU",
"aliases": [
"Integrated GPU"
],
"category": "Virtualization",
"definitionRich": "Graphics processor built into the CPU package (Intel UHD / Iris, AMD Radeon Vega in Ryzen APUs). Typically shared across multiple LXC containers via <code>/dev/dri</code> rather than passed through to a single VM.",
"seeAlso": [
{
"label": "Add GPU to LXC",
"href": "/docs/hardware/igpu-acceleration-lxc"
}
]
},
{
"term": "ifupdown / ifupdown2",
"category": "Network",
"definitionRich": "The classic Debian network configuration system that reads <code>/etc/network/interfaces</code>. <code>ifupdown2</code> is the rewritten version Proxmox uses by default — supports live reload via <code>ifreload -a</code>."
},
{
"term": "initramfs",
"category": "Linux",
"definitionRich": "Initial RAM filesystem the kernel uses at boot before the real root filesystem is mounted. Contains drivers needed early (storage, encryption, RAID). Rebuilt with <code>update-initramfs -u -k all</code> after VFIO, IOMMU or storage driver changes."
},
{
"term": "IOMMU",
"aliases": [
"Input/Output Memory Management Unit",
"VT-d",
"AMD-Vi"
],
"category": "Virtualization",
"definitionRich": "Hardware feature (Intel VT-d / AMD-Vi) that lets PCIe devices be safely assigned directly to guest VMs. Required for GPU and disk-controller passthrough. Must be enabled both in BIOS / UEFI and in the kernel command line (<code>intel_iommu=on</code> or <code>amd_iommu=on</code>).",
"seeAlso": [
{
"label": "Post-Install: Virtualization",
"href": "/docs/post-install/virtualization"
},
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough"
}
]
},
{
"term": "IOMMU group",
"category": "Virtualization",
"definitionRich": "The smallest unit of devices that the IOMMU can isolate from each other. All devices in a group must be passed through together — usually one device, but multi-function cards or shared root-port devices land in the same group. Listed via <code>find /sys/kernel/iommu_groups/ -type l | sort -V</code>."
},
{
"term": "iSCSI",
"aliases": [
"Internet SCSI"
],
"category": "Storage",
"definitionRich": "Network protocol that exposes block storage over IP — a remote disk appears as a local SCSI device. Registered as Proxmox storage via <code>pvesm add iscsi</code>.",
"seeAlso": [
{
"label": "Add iSCSI target as Proxmox storage",
"href": "/docs/storage-share/host-iscsi"
}
]
},
{
"term": "KVM",
"aliases": [
"Kernel-based Virtual Machine"
],
"category": "Virtualization",
"definitionRich": "Linux kernel module that turns the host into a hypervisor. Combined with <strong>QEMU</strong> for device emulation, it's the foundation Proxmox uses to run VMs."
},
{
"term": "LVM",
"aliases": [
"Logical Volume Manager"
],
"category": "Storage",
"definitionRich": "Linux storage stack that abstracts physical disks into volume groups (VG) of logical volumes (LV). Proxmox uses LVM-thin pools for VM disks by default. Concise tools: <code>pvs</code>, <code>vgs</code>, <code>lvs</code>.",
"seeAlso": [
{
"label": "Storage and Disks commands",
"href": "/docs/help-info/storage-commands"
}
]
},
{
"term": "LXC",
"aliases": [
"Linux Containers"
],
"category": "Linux",
"definitionRich": "OS-level virtualization technology — multiple isolated user-space instances share the host's kernel. Lighter and faster than VMs but less isolated. Proxmox manages LXC containers via the <code>pct</code> CLI.",
"seeAlso": [
{
"label": "VM and CT Management",
"href": "/docs/help-info/vm-ct-commands"
}
]
},
{
"term": "Lynis",
"category": "Linux",
"definitionRich": "Open-source security auditor (by CISOfy) that scans the host and prints a hardening score plus concrete remediation hints. ProxMenux installs the latest from upstream GitHub rather than the (older) Debian package.",
"seeAlso": [
{
"label": "Lynis",
"href": "/docs/security/lynis"
}
]
},
{
"term": "MAC address",
"aliases": [
"Hardware address"
],
"category": "Network",
"definitionRich": "48-bit identifier burnt into a NIC's firmware. Used by Proxmox <em>Persistent Network Names</em> to pin interface names (<code>eno1</code>, <code>enp3s0</code>) so they survive PCI re-enumeration.",
"seeAlso": [
{
"label": "Persistent interface names",
"href": "/docs/network/persistent-names"
}
]
},
{
"term": "MOTD",
"aliases": [
"Message of the Day"
],
"category": "Linux",
"definitionRich": "Text shown after SSH login. Stored in <code>/etc/motd</code>. ProxMenux Post-Install can add a banner here; the uninstaller restores the backup if you applied it."
},
{
"term": "NFS",
"aliases": [
"Network File System"
],
"category": "Storage",
"definitionRich": "Unix-native network file sharing protocol. Registered as Proxmox storage via <code>pvesm add nfs</code>; also usable as an LXC client / server via dedicated ProxMenux flows.",
"seeAlso": [
{
"label": "Storage & Share Manager",
"href": "/docs/storage-share"
}
]
},
{
"term": "nftables / iptables",
"category": "Network",
"definitionRich": "Linux firewall systems. <code>nftables</code> is the modern engine; <code>iptables</code> is the legacy front-end (still works as a translation layer). Proxmox's <code>pve-firewall</code> emits nftables rules from the cluster firewall config.",
"seeAlso": [
{
"label": "Network commands",
"href": "/docs/help-info/network-commands"
}
]
},
{
"term": "nouveau",
"category": "Linux",
"definitionRich": "Open-source NVIDIA driver bundled with the Linux kernel. Must be blacklisted before installing the proprietary NVIDIA driver, otherwise both load and the install fails.",
"seeAlso": [
{
"label": "NVIDIA installation guide",
"href": "/guides/nvidia"
}
]
},
{
"term": "no-subscription repo",
"category": "Proxmox",
"definitionRich": "Free Proxmox repository for users without an enterprise subscription. Less polished QA than the enterprise repo (slightly riskier for production) but free. Set up automatically by the ProxMenux Post-Install.",
"seeAlso": [
{
"label": "Post-Install: Basic Settings",
"href": "/docs/post-install/basic-settings"
}
]
},
{
"term": "OVA / OVF",
"aliases": [
"Open Virtualization Format"
],
"category": "Virtualization",
"definitionRich": "DMTF-standard packaging formats for portable VMs. <strong>OVA</strong> is a single TAR archive; <strong>OVF</strong> is a directory with an XML descriptor + external VMDK files. Importable on VMware, VirtualBox and Proxmox.",
"seeAlso": [
{
"label": "Export VM to OVA / OVF",
"href": "/docs/utils/export-vm"
},
{
"label": "Import VM from OVA / OVF",
"href": "/docs/utils/import-vm"
}
]
},
{
"term": "OVMF",
"aliases": [
"UEFI firmware",
"Open Virtual Machine Firmware"
],
"category": "Virtualization",
"definitionRich": "UEFI firmware implementation for VMs. Set with <code>qm set &lt;vmid&gt; -bios ovmf</code>. Required for Windows 11, Secure Boot, and most modern OS installs. Pair with an <code>efidisk0</code> to persist EFI variables.",
"seeAlso": [
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough"
}
]
},
{
"term": "PBS",
"aliases": [
"Proxmox Backup Server"
],
"category": "Proxmox",
"definitionRich": "Standalone product from Proxmox for incremental, deduplicated, encrypted VM / CT backups. Recommended over plain vzdump when you have a separate machine to host it on."
},
{
"term": "pct",
"category": "Proxmox",
"definitionRich": "CLI tool for managing LXC containers in Proxmox: <code>pct list / start / stop / shutdown / config / enter / exec / push / pull / destroy</code>.",
"seeAlso": [
{
"label": "VM and CT Management",
"href": "/docs/help-info/vm-ct-commands"
}
]
},
{
"term": "pmxcfs",
"aliases": [
"Proxmox Cluster Filesystem"
],
"category": "Proxmox",
"definitionRich": "FUSE-based virtual filesystem mounted at <code>/etc/pve/</code>. Replicates configuration changes across all cluster nodes in real time. Editing a file under <code>/etc/pve/</code> propagates automatically."
},
{
"term": "pveam",
"aliases": [
"Proxmox VE Appliance Manager"
],
"category": "Proxmox",
"definitionRich": "CLI for managing the local catalog of CT templates. <code>pveam update</code> refreshes the index; <code>pveam available</code> lists templates; <code>pveam download &lt;storage&gt; &lt;template&gt;</code> downloads one."
},
{
"term": "pveproxy",
"category": "Proxmox",
"definitionRich": "The HTTPS service that serves the Proxmox web UI on port 8006 and the web terminal. Restarted automatically during major upgrades — which is why ProxMenux refuses to run the PVE 8 → 9 upgrade from the web terminal."
},
{
"term": "pvesm",
"aliases": [
"Proxmox Storage Manager"
],
"category": "Proxmox",
"definitionRich": "CLI tool for managing Proxmox storage. <code>pvesm status</code> shows all configured storages; <code>pvesm add &lt;type&gt;</code> registers new ones (NFS, Samba, iSCSI, dir, ZFS, LVM, …).",
"seeAlso": [
{
"label": "Storage and Disks commands",
"href": "/docs/help-info/storage-commands"
}
]
},
{
"term": "Privileged container",
"category": "Linux",
"definitionRich": "LXC container where the root user inside the container <em>is</em> root on the host (UIDs not shifted). Required for hardware passthrough (USB devices, GPU sharing) and Samba / NFS server inside the CT. Less secure than unprivileged — use only when needed."
},
{
"term": "ProxMenux Monitor",
"category": "ProxMenux",
"definitionRich": "Optional web dashboard installed alongside ProxMenux. Serves real-time host stats (CPU / RAM / disk / network), VM and LXC overview, login + 2FA, on TCP port <code>8008</code>.",
"seeAlso": [
{
"label": "ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor"
}
]
},
{
"term": "qcow2",
"aliases": [
"QEMU Copy-On-Write v2"
],
"category": "Storage",
"definitionRich": "Default VM disk image format on Proxmox directory storage. Supports thin provisioning, snapshots, and copy-on-write. Convert with <code>qemu-img convert -O qcow2 ...</code>."
},
{
"term": "qm",
"aliases": [
"QEMU Manager"
],
"category": "Proxmox",
"definitionRich": "CLI tool for managing VMs in Proxmox: <code>qm list / start / stop / shutdown / config / set / destroy / importdisk / migrate</code>. Sister command of <code>pct</code> for containers.",
"seeAlso": [
{
"label": "VM and CT Management",
"href": "/docs/help-info/vm-ct-commands"
}
]
},
{
"term": "Q35",
"category": "Virtualization",
"definitionRich": "Modern QEMU machine type emulating an Intel Q35 chipset with PCIe support. Recommended over the older i440FX for VMs that need PCIe passthrough or modern guest OS support. Set with <code>qm set &lt;vmid&gt; -machine q35</code>."
},
{
"term": "QEMU",
"category": "Virtualization",
"definitionRich": "Generic, open-source machine emulator and virtualizer. Combined with KVM in Proxmox to run VMs at near-native speed."
},
{
"term": "rclone",
"category": "Linux",
"definitionRich": "Command-line tool that talks to ~50 cloud storage providers (Google Drive, Dropbox, OneDrive, Mega, S3, …). Used in the Proxmox cloud-backup guide to mount a personal cloud as a directory the host can write vzdump archives to.",
"seeAlso": [
{
"label": "Backup to Personal Cloud",
"href": "/guides/backup_cloud"
}
]
},
{
"term": "Samba / SMB / CIFS",
"category": "Storage",
"definitionRich": "Microsoft's file-sharing protocol family. <strong>SMB</strong> is the protocol; <strong>Samba</strong> is the open-source Linux implementation; <strong>CIFS</strong> is an older SMB dialect. Registered as Proxmox storage via <code>pvesm add cifs</code>.",
"seeAlso": [
{
"label": "Storage & Share Manager",
"href": "/docs/storage-share"
}
]
},
{
"term": "SeaBIOS",
"category": "Virtualization",
"definitionRich": "Open-source legacy BIOS implementation used by QEMU. Default firmware for new VMs unless you switch to OVMF. Suitable for older OSes and simple Linux installs that don't need UEFI."
},
{
"term": "smartctl / SMART",
"aliases": [
"Self-Monitoring, Analysis and Reporting Technology"
],
"category": "Storage",
"definitionRich": "Built-in disk diagnostics that report drive health, error counts and self-test results. <code>smartctl</code> (from <code>smartmontools</code>) is the CLI; for NVMe drives, the <code>nvme-cli</code> package adds NVMe-specific commands.",
"seeAlso": [
{
"label": "SMART Disk Health & Test",
"href": "/docs/disk-manager/smart-disk-test"
},
{
"label": "Storage commands → SMART section",
"href": "/docs/help-info/storage-commands"
}
]
},
{
"term": "systemd / systemctl / journalctl",
"category": "Linux",
"definitionRich": "Modern init system used by Debian / Proxmox. <code>systemctl</code> manages services (start / stop / enable / status). <code>journalctl</code> reads the binary log written by <code>systemd-journald</code>."
},
{
"term": "sysctl",
"category": "Linux",
"definitionRich": "Kernel parameter management. Reads <code>/etc/sysctl.conf</code> + <code>/etc/sysctl.d/*.conf</code> at boot. ProxMenux Post-Install ships a curated sysctl tuning profile.",
"seeAlso": [
{
"label": "Post-Install: Network",
"href": "/docs/post-install/network"
}
]
},
{
"term": "trixie",
"category": "Linux",
"definitionRich": "Codename for Debian 13, the OS base for Proxmox VE 9. Predecessor: <em>bookworm</em> (Debian 12 / PVE 8).",
"seeAlso": [
{
"label": "Upgrade PVE 8 to PVE 9",
"href": "/docs/utils/upgrade-pve8-pve9"
}
]
},
{
"term": "udev",
"category": "Linux",
"definitionRich": "Linux device manager. Reacts to hardware events and creates / removes entries under <code>/dev</code>. Custom rules in <code>/etc/udev/rules.d/</code> persistently map MAC addresses to interface names, set up NVIDIA device nodes on driver load, etc."
},
{
"term": "UID / GID idmap",
"aliases": [
"UID shift"
],
"category": "Linux",
"definitionRich": "In <strong>unprivileged</strong> LXC containers, UIDs and GIDs are shifted by <code>+100000</code> on the host. Container UID 0 = host UID 100000, container UID 1000 = host UID 101000, etc. Affects file ownership on bind mounts.",
"seeAlso": [
{
"label": "LXC Mount Points",
"href": "/docs/storage-share/lxc-mount-points"
}
]
},
{
"term": "Unprivileged container",
"category": "Linux",
"definitionRich": "LXC container where root inside is mapped to an unprivileged UID on the host (UID shift +100000). Safer than privileged but can't do hardware passthrough or run kernel-level services. Default for most use cases."
},
{
"term": "VFIO",
"aliases": [
"Virtual Function I/O"
],
"category": "Virtualization",
"definitionRich": "Linux kernel framework for safe userspace device drivers — used to bind PCIe devices to VMs for direct passthrough. Enabled by loading the <code>vfio</code>, <code>vfio_iommu_type1</code> and <code>vfio_pci</code> kernel modules, configured via <code>/etc/modprobe.d/vfio.conf</code>.",
"seeAlso": [
{
"label": "Post-Install: Virtualization",
"href": "/docs/post-install/virtualization"
}
]
},
{
"term": "VirtIO",
"category": "Virtualization",
"definitionRich": "Family of paravirtualized device drivers (network, storage, balloon, GPU) that run faster than emulated legacy hardware (e.g. e1000 NICs, IDE disks). The guest needs the matching VirtIO driver — kernel-native on Linux, separate ISO install on Windows."
},
{
"term": "VLAN",
"aliases": [
"Virtual LAN"
],
"category": "Network",
"definitionRich": "802.1Q tags that segment one physical network into multiple logical networks. Configured per-bridge or per-NIC in <code>/etc/network/interfaces</code>."
},
{
"term": "VM",
"aliases": [
"Virtual Machine"
],
"category": "Proxmox",
"definitionRich": "A full machine emulation managed by Proxmox via QEMU/KVM. Has a numeric VMID that maps to <code>/etc/pve/qemu-server/&lt;VMID&gt;.conf</code>. Heavier than LXC containers but fully isolated.",
"seeAlso": [
{
"label": "VM and CT Management",
"href": "/docs/help-info/vm-ct-commands"
}
]
},
{
"term": "vzdump",
"category": "Proxmox",
"definitionRich": "Proxmox's built-in backup tool for VMs and CTs. <strong>Not incremental</strong> — every backup is a full snapshot. Configure modes (snapshot / suspend / stop), compression (zstd / pigz / lzo), retention and notification per job.",
"seeAlso": [
{
"label": "Backup and Restore commands",
"href": "/docs/help-info/backup-commands"
}
]
},
{
"term": "ZFS",
"aliases": [
"Zettabyte File System"
],
"category": "Storage",
"definitionRich": "Combined filesystem and volume manager known for snapshots, send/receive replication, end-to-end checksums, compression and self-healing. Memory-hungry (see <strong>ARC</strong>) but extremely robust.",
"seeAlso": [
{
"label": "ZFS Management commands",
"href": "/docs/help-info/zfs-commands"
}
]
}
]
}
@@ -0,0 +1,120 @@
{
"meta": {
"title": "Add Coral TPU to LXC | ProxMenux Documentation",
"description": "Pass a Google Coral TPU (USB or M.2 / PCIe) into a Proxmox LXC container. ProxMenux writes the right dev / cgroup / mount entries for each variant, boots the container, and installs the Edge TPU runtime inside so apps like Frigate can use the accelerator."
},
"header": {
"title": "Add Coral TPU to LXC",
"description": "Share a Google Coral TPU (USB Accelerator or M.2 / Mini-PCIe) with a Proxmox LXC container. ProxMenux handles the LXC config and the inside-container Edge TPU runtime install. Coral is TPU-only: for GPU / iGPU sharing (Quick Sync, VA-API, NVENC) in the same container, run Add GPU to LXC separately.",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "Writes the passthrough config into <code>/etc/pve/lxc/&lt;ctid&gt;.conf</code> — different entries depending on whether the host has a <strong>USB Accelerator</strong>, a <strong>M.2 / PCIe Coral</strong>, or both. Then it starts the container and installs Google's latest <code>libedgetpu</code> runtime inside it. iGPU / GPU passthrough is handled by a separate script (<lxcGpuLink>Add GPU to LXC</lxcGpuLink>) — this one focuses on the TPU."
},
"whenUse": {
"heading": "When to use this",
"body": "Typical use case: running <frigateLink>Frigate</frigateLink>, Agent DVR, Blue Iris + CodeProject.AI, or any other object-detection app inside an LXC and wanting the Coral TPU to do the ML inference instead of the CPU. With Coral, inference latency drops from ~100 ms to ~5 ms per frame and CPU load stays near zero."
},
"prereqs": {
"title": "Before you start",
"drivers": "<strong>Coral drivers already installed on the host</strong>. This script does not install them; it only configures passthrough to the container. Run <hostLink>Install Coral TPU on the Host</hostLink> first if you haven't.",
"driversCheck": "ls /dev/apex_* 2>/dev/null ; lsusb | grep -E '1a6e:089a|18d1:9302'",
"container": "<strong>An existing LXC container</strong>, ideally running a <strong>Debian / Ubuntu</strong>-based distro. The inside-container install uses <code>apt-get</code>; Alpine / Arch containers are not currently supported by this script.",
"downtime": "<strong>Be OK with a brief downtime</strong> of the container. The script stops it to apply config changes, then starts it back up to install drivers inside. No host reboot needed."
},
"hostPrep": {
"title": "Host must be prepared first",
"body": "If you run this script before installing Coral drivers on the host (the <code>gasket</code>/<code>apex</code> kernel module for M.2, the <code>libedgetpu</code> runtime for USB), the LXC config is still written but the container won't find the device at runtime. Order matters: <strong>host install → LXC passthrough → in-container app</strong>."
},
"running": {
"heading": "Running the script",
"body": "Open ProxMenux on the host, go to <strong>Hardware: GPUs and Coral-TPU → Add Coral TPU to LXC</strong>.",
"imageAlt": "Menu entry for 'Add Coral TPU to LXC' inside Hardware: GPUs and Coral-TPU"
},
"howRuns": {
"heading": "How the script runs",
"body": "One decision upfront (which container?), then the script handles USB and PCIe paths independently based on what it finds on the host. If both are present, both get passed."
},
"walkthrough": {
"heading": "Walking through the flow",
"pick": {
"title": "Pick the LXC container",
"body": "A dialog shows every LXC on the host (from <code>pct list</code>). Pick the one that should get the Coral. Running or stopped, it doesn't matter — the script handles both (stops it briefly to write config, then starts it back up to install drivers)."
},
"gpuHint": {
"title": "GPU passthrough suggestion (optional)",
"body": "If the host has a GPU (Intel iGPU, AMD, NVIDIA) and the chosen container does NOT have GPU passthrough configured, the script shows a one-time dialog suggesting you run <lxcGpuLink>Add GPU to LXC</lxcGpuLink> first. Coral is most often paired with hardware video decode (Quick Sync, VA-API, NVENC) for apps like Frigate. You can say yes (exits, run the GPU script, then come back) or no (continues with TPU-only setup)."
},
"usb": {
"title": "Write LXC config — USB path",
"body": "If a USB Accelerator is present, the script does two things: (1) writes a udev rule on the host so the device gets a stable name <code>/dev/coral</code> whatever USB port it's in, and (2) bind-mounts the <strong>whole</strong> <code>/dev/bus/usb</code> tree into the container.",
"whyTitle": "Why mount /dev/bus/usb instead of /dev/coral?",
"whyBody": "The USB device node path (e.g. <code>/dev/bus/usb/001/005</code>) changes when you replug the accelerator into a different port. Earlier versions of the script bind-mounted the <code>/dev/coral</code> symlink, which pointed at an old path and broke. Mounting the whole USB tree means the container sees whatever the current path is, so a replug just works."
},
"pcie": {
"title": "Write LXC config — M.2 / PCIe path",
"body1": "If a M.2 / PCIe Coral is present on the host and <code>/dev/apex_0</code> exists (the apex kernel module is loaded), the script uses the modern Proxmox <code>dev</code> API which handles cgroup2 permissions automatically for both privileged and unprivileged containers:",
"body2": "If the host hasn't booted yet with the apex module loaded (you just ran <hostLink>Install Coral on Host</hostLink> and haven't rebooted), <code>/dev/apex_0</code> doesn't exist yet. The script falls back to classic cgroup2 + bind mount with <code>create=file</code> so the entries are valid even when the device hasn't materialised:",
"rebootTitle": "Reboot the host first if you just installed Coral drivers",
"rebootBody": "The fallback cgroup2 + mount will be written, but the device only actually exists after a host reboot loads the <code>apex</code> module. If you haven't rebooted, reboot now before starting the container."
},
"drivers": {
"title": "Start the container + install Coral runtime inside",
"body": "Config changes in Proxmox LXC take effect on the next start — so the script starts the container, waits up to 15 seconds for <code>pct exec</code> to respond, then drops a bash script inside that:",
"items": [
"Runs <code>apt-get update</code>.",
"Installs the Coral repository prerequisites: <code>gnupg</code>, <code>curl</code>, <code>ca-certificates</code>.",
"Imports Google's Coral GPG key to <code>/etc/apt/keyrings/coral-edgetpu.gpg</code> (modern path, same as the host installer uses) and adds the <code>coral-edgetpu-stable</code> APT repository with <code>signed-by=</code>.",
"Installs the latest <code>libedgetpu1-std</code> (default). If you have a M.2 Coral, you'll be prompted to pick between <code>libedgetpu1-std</code> (standard) and <code>libedgetpu1-max</code> (max performance, runs hotter)."
],
"noIgpuTitle": "Why no iGPU drivers here?",
"noIgpuBody": "Earlier versions of this script also installed Intel <code>va-driver-all</code>, <code>intel-opencl-icd</code> and friends so the same container could do Quick Sync video decode alongside Coral inference. That doubled-up responsibility caused confusing failures when the user only wanted Coral. The iGPU side is now the exclusive job of <lxcGpuLink>Add GPU to LXC</lxcGpuLink> — run it first if you also want hardware video decode in the container.",
"debianTitle": "Debian / Ubuntu containers only",
"debianBody": "The in-container install uses <code>apt-get</code> directly. Alpine, Arch or RHEL-based containers are not currently supported — the install step will fail and leave the LXC with the passthrough config but no drivers inside. For those distros, install the Coral runtime manually following Google's <coralLink>official guide</coralLink> after the LXC config step."
},
"summary": {
"title": "Summary",
"body": "The script prints a checklist at the end summarising what was enabled (Coral USB, Coral M.2) with ✓ or ⚠ marks depending on whether the hardware was actually detected. The container stays running — you can jump straight into Frigate / CodeProject.AI / your app config."
}
},
"manual": {
"heading": "Manual equivalent",
"body": "If you want to see exactly what goes into the LXC config, or apply it by hand:",
"usbHeading": "USB Coral",
"pcieHeading": "M.2 / PCIe Coral",
"runtimeHeading": "Inside the container — Coral runtime"
},
"verification": {
"heading": "Verification",
"body": "Enter the container and check the Coral is visible:"
},
"troubleshoot": {
"heading": "Troubleshooting",
"apexTitle": "Container started but /dev/apex_0 missing inside",
"apexBody": "Host apex module isn't loaded. On the host: <code>lsmod | grep apex</code> — if empty, run <code>modprobe apex</code>, or reboot if you just installed Coral drivers. Once the host has <code>/dev/apex_0</code>, restart the container: <code>pct stop &lt;ctid&gt; &amp;&amp; pct start &lt;ctid&gt;</code>.",
"replugTitle": "USB Coral disappears after replug in a different port",
"replugBody": "This is exactly why the script mounts <code>/dev/bus/usb</code> instead of the <code>/dev/coral</code> symlink. If you're hitting this, check your LXC config has <code>lxc.mount.entry: /dev/bus/usb dev/bus/usb ...</code> and not a reference to <code>/dev/coral</code> directly. Old configs from earlier script versions may need updating — re-run the script on the same container and the config gets refreshed.",
"alpineTitle": "In-container install fails on an Alpine container",
"alpineBody": "The script uses <code>apt-get</code>, which Alpine doesn't have. The LXC passthrough config is still valid — just install the Coral runtime manually with <code>apk add</code> following Google's guide for Alpine, or use a Debian-based container if you don't need the smaller footprint.",
"frigateTitle": "Frigate says 'Coral EdgeTPU detected but not available'",
"frigateBody": "Almost always a permissions issue inside the container. Frigate runs as root by default; check the root user is in the <code>plugdev</code> group inside the container (for USB), and that the process can read <code>/dev/apex_0</code> (for M.2). <code>ls -l /dev/apex_0</code> from inside the container should show group <code>apex</code> — if not, add the GID alignment to <code>/etc/group</code> or switch the container to privileged mode.",
"logsTitle": "Check both host and container logs",
"logsBody": "On the host: <code>journalctl -u pvedaemon | grep -i coral</code>. Inside the container: check the app logs (Frigate: <code>/config/logs/</code>, CodeProject.AI: its own log directory). The classic error pattern is \"Coral detected, runtime loaded, but inference engine can't claim it\" — that's permissions 9 out of 10 times."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Install Coral TPU (Host)",
"href": "/docs/hardware/install-coral-tpu-host",
"tail": " — required prerequisite for M.2 / PCIe Coral cards before passing into a CT."
},
{
"label": "Add GPU to LXC",
"href": "/docs/hardware/igpu-acceleration-lxc",
"tail": " — same pattern for GPUs (often paired with a Coral TPU in Frigate setups)."
}
]
}
}
@@ -0,0 +1,178 @@
{
"meta": {
"title": "Add GPU to VM (Passthrough) | ProxMenux Documentation",
"description": "Pass an Intel, AMD or NVIDIA GPU through to a Proxmox VM with near-native performance. ProxMenux handles host preparation (VFIO modules, driver blacklist, kernel cmdline), VM configuration (hostpci, audio function, IOMMU group siblings), vendor-specific workarounds (NVIDIA Code 43, AMD reset bug, ROM dump) and switch-mode conflicts with LXCs."
},
"header": {
"title": "Add GPU to VM (Passthrough)",
"description": "Give one of your GPUs to a virtual machine with near-native performance. ProxMenux detects Intel / AMD / NVIDIA, validates IOMMU, analyses the GPU's IOMMU group to pass every sibling device together, configures VFIO on the host, writes the right hostpci lines into the VM config, and applies vendor-specific fixes where needed.",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "Everything the <pveLink>official Proxmox PCI passthrough wiki</pveLink> walks you through manually — IOMMU enablement, VFIO modules, driver blacklisting, vendor ID discovery, <code>hostpci</code> setup, ROM dumps on AMD, KVM hiding on NVIDIA — done in one run with sanity checks at every step. The script is also aware of the <em>other</em> things on your host: if the same GPU is already assigned to an LXC or another VM, it offers to migrate cleanly instead of silently breaking the existing setup."
},
"who": {
"heading": "Who is this for?",
"body": "You have a physical GPU in your Proxmox host and you want a <strong>virtual machine</strong> (Windows gaming, macOS, a headless GPU compute node, a VM-based media server) to use it directly. Passing a GPU to a VM is not the same as passing it to an LXC — VMs need the kernel to treat the GPU as a VFIO device (essentially \"the host won't touch it\"), which means the host cannot use that GPU for anything else while the VM is running. For <em>LXC</em> transcoding / compute, use <lxcLink>Add GPU to LXC</lxcLink> instead — it shares the GPU and does not need VFIO."
},
"prereqs": {
"title": "Before you start",
"gpu": "<strong>A supported GPU</strong> physically installed. The script detects Intel, AMD and NVIDIA via <code>lspci</code>.",
"gpuCheck": "lspci | grep -iE 'VGA|3D|Display'",
"iommu": "<strong>IOMMU virtualization</strong> available in BIOS/UEFI (Intel VT-d or AMD-Vi). If it's off at the firmware level, no amount of Linux config fixes it — you have to enable it in the BIOS first. The script detects this and offers to enable it on the OS side.",
"q35": "The target VM uses <strong>q35</strong> machine type. Older <code>i440fx</code> does not reliably support PCIe passthrough and the script will refuse to proceed.",
"q35Check": "qm config '<'vmid'>' | grep machine",
"moreGpus": "Preferably <strong>more than one GPU</strong> in the host, or console access on another output (IPMI, KVM-over-IP, serial). Once you pass the only GPU to a VM, the host console goes dark. With two NVIDIA GPUs you can pass one to a VM and keep the other on the host — the script handles this per-BDF (see <em>NVIDIA</em> in the vendor notes below).",
"nvidiaInstalled": "If you're on a Proxmox that already installed the NVIDIA driver via <nvidiaLink>NVIDIA Drivers on the Host</nvidiaLink>: the GPU you pass to the VM gets unbound from the host <code>nvidia</code> driver and rebound to <code>vfio-pci</code>. The <code>nvidia</code> module stays loaded so any <strong>other</strong> NVIDIA GPU you have on the host keeps working with <code>nvidia-smi</code>."
},
"pickOne": {
"title": "VM passthrough vs LXC sharing — pick one per GPU",
"body": "A GPU bound to <code>vfio-pci</code> for VM passthrough cannot simultaneously be used by the host or an LXC. If you have two GPUs, you can dedicate one to each path. If you have only one, choose:",
"vmItem": "<strong>VM route (this page):</strong> full hardware access, but exclusively for the VM that owns the GPU while it's running.",
"lxcItem": "<strong>LXC route (<lxcLink>Add GPU to LXC</lxcLink>):</strong> shared with the host and other containers, great for transcoding, no VFIO magic needed."
},
"running": {
"heading": "Running the installer",
"body": "Open ProxMenux on the host, go to <strong>Hardware: GPUs and Coral-TPU → Add GPU to VM</strong>.",
"imageAlt": "Menu entry for 'Add GPU to VM' inside Hardware: GPUs and Coral-TPU"
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has three phases with clear separation between \"collecting information and decisions\" and \"actually applying changes\". Until the final confirmation, nothing on your host or VM has been touched."
},
"walkthrough": {
"heading": "Walking through the flow",
"detect": {
"title": "Detect GPUs and check IOMMU",
"body": "The script lists every GPU it finds. If IOMMU isn't already enabled in the running kernel cmdline, you'll get a yes/no prompt to append <code>intel_iommu=on</code> (or <code>amd_iommu=on</code>) + <code>iommu=pt</code> to the right boot file — <code>/etc/kernel/cmdline</code> on ZFS (systemd-boot) or <code>/etc/default/grub</code> on LVM/ext4. If you accept and the kernel cmdline changes, the script flags that the reboot prompt at the end will be required.",
"tipTitle": "Already ran post-install?",
"tipBody": "If you previously enabled <postLink>VFIO IOMMU support</postLink> from the post-install scripts, IOMMU is already on and this step silently passes. Good.",
"imageAlt": "List of detected GPUs with vendor and PCI address"
},
"preflight": {
"title": "Pick a GPU and run pre-flight checks",
"intro": "Once you pick the GPU, the script runs a series of checks that can each block further progress:",
"items": [
"<strong>Not in SR-IOV.</strong> If the device is a Virtual Function or a Physical Function with active VFs, passthrough would clash with SR-IOV usage. Blocked.",
"<strong>Single-GPU warning.</strong> If this is the only GPU in the host, you get a scary dialog reminding you that after reboot the console goes dark — make sure you have SSH or web-UI access from another machine.",
"<strong>AMD reset method.</strong> AMD GPUs have a long history of not resetting cleanly between VM stops and starts. The script checks <code>/sys/bus/pci/devices/&lt;pci&gt;/reset_method</code>: if the card is an APU without FLR it <em>blocks</em> (practically unusable); a dedicated AMD card without FLR is also blocked; anything with an unknown reset mode warns but lets you continue with explicit override.",
"<strong>Not in D3cold.</strong> Some AMD cards report <code>D3cold</code> power state while idle, which makes them invisible during VM startup. Blocked until you wake the GPU.",
"<strong>IOMMU group analysis.</strong> Reads <code>/sys/kernel/iommu_groups/</code> to find every non-bridge device in the GPU's group. <em>All of them</em> will be passed to the VM together — if your motherboard groups the GPU with a network card, the network card goes too."
],
"audioIntro": "<strong>Audio companion.</strong> Two paths, depending on where the audio lives:",
"audioDgpu": "<strong>Discrete GPU (NVIDIA / AMD):</strong> HDMI audio sits on the same card as function <code>.1</code> of the GPU's PCI slot. Auto-included. This audio device was never used by the host, so no one loses anything.",
"audioIgpu": "<strong>Intel iGPU (or any GPU without a <code>.1</code> sibling):</strong> the HDMI / analog audio lives on the chipset at a different slot (<code>00:1f.3</code> typically). The script scans the host, lists every PCI audio controller with its current driver (<code>snd_hda_intel</code>, etc.), and asks you which one(s) to pass through. Default is <strong>none</strong> — you explicitly opt in."
},
"pickVm": {
"title": "Pick the target VM",
"body": "You're shown the list of VMs on the host and pick one. The script checks the VM is q35 — BIOS/i440fx machine types are refused because PCIe passthrough on them is unreliable. If you have a q35 VM with the GPU already assigned (partially or fully), the existing entry is reused instead of being duplicated.",
"imageAlt": "VM list with name, ID and status shown as a picker"
},
"switchMode": {
"title": "Switch mode — handling the GPU already being elsewhere",
"intro": "The script scans every VM config and every LXC config on the host looking for the GPU you picked. Three possible outcomes:",
"items": [
"<strong>GPU is free.</strong> Nothing to do, continue.",
"<strong>GPU is in a different VM.</strong> You're offered to remove it from that other VM before assigning it here. If you decline, the script aborts — two VMs can't share an exclusive VFIO assignment.",
"<strong>GPU is in an LXC (shared mode).</strong> You're offered to remove the LXC passthrough configuration (<code>lxc.cgroup2.devices.allow</code> + <code>lxc.mount.entry</code> lines). The LXC won't see the GPU anymore, but the VM will — this is the \"switch mode\" mechanic that gives this menu entry its secondary label."
],
"imageAlt": "Dialog offering to remove the GPU from an LXC before assigning it to the VM",
"smartTitle": "Audio siblings are cleaned up smartly too",
"smartBody": "If the source VM had extra audio devices attached alongside the GPU, the script removes <strong>only the ones that are now orphan</strong> — i.e. audio entries whose display sibling is also being removed. Audio tied to a different GPU that stays in the VM is kept untouched. This matters when you detach an Intel iGPU (which shares chipset audio) from a VM that also has a discrete NVIDIA / AMD card still passed through: the dGPU's HDMI audio (<code>02:00.1</code>) stays, the chipset audio (<code>00:1f.3</code>) leaves."
},
"audioPick": {
"title": "(If no .1 sibling) Pick which audio controllers to include",
"body": "Only happens for Intel iGPU and similar split-audio setups. A checklist shows every PCI audio controller on the host (excluding any already in the GPU's IOMMU group), labelled with its current driver. Select the ones you want — or none, if the VM doesn't need audio from the host hardware.",
"imageAlt": "Checklist dialog with every host PCI audio controller (BDF + driver) when the GPU has no .1 sibling audio",
"warnTitle": "Don't tick audio the host relies on",
"warnBody": "If the host currently uses an audio controller for anything — for example, the Proxmox shell beeping, or a VM you've already passed it to — ticking it here means the host (and any other VM sharing it) loses access after reboot. When in doubt, leave this empty and you can always re-run the script later to add audio if needed."
},
"summary": {
"title": "Review the confirmation summary",
"body": "A final dialog shows exactly what's about to change on the host and in the VM. This is the last off ramp — if anything looks wrong (an extra device in the IOMMU group you didn't expect, the wrong GPU, the wrong VM), cancel here and nothing has been touched yet.",
"imageAlt": "Summary dialog listing host changes (VFIO/blacklist files) and VM config changes (hostpci lines) before applying"
},
"hostApply": {
"title": "Host changes are applied",
"intro": "Phase 2 runs non-interactively. Host-side the script can touch:",
"items": [
"<code>/etc/modules</code> — adds <code>vfio</code>, <code>vfio_iommu_type1</code>, <code>vfio_pci</code> (plus <code>vfio_virqfd</code> on kernels &lt; 6.2).",
"<code>/etc/modprobe.d/vfio.conf</code> — for AMD / Intel, sets <code>options vfio-pci ids=&lt;vendor:device,...&gt; disable_vga=1</code> so VFIO claims the GPU early at boot. For NVIDIA the file only adds <code>softdep nvidia pre: vfio-pci</code> (plus <code>_drm</code>/<code>_modeset</code>/<code>_uvm</code>) — actual binding is per-BDF via the udev rule below. On AMD, also adds <code>softdep</code> lines forcing <code>vfio-pci</code> to load before <code>radeon</code> / <code>amdgpu</code>.",
"<code>/etc/modprobe.d/iommu_unsafe_interrupts.conf</code> and <code>kvm.conf</code> — sensible workarounds that most Windows / macOS VMs need (<code>allow_unsafe_interrupts=1</code>, <code>ignore_msrs=1</code>).",
"<code>/etc/modprobe.d/blacklist.conf</code> — blacklists the open-source companion drivers (<code>nouveau</code>, <code>amdgpu</code>, <code>radeon</code>, <code>i915</code>) that would otherwise grab the GPU before VFIO. The proprietary <code>nvidia</code> module is <strong>never blacklisted</strong> — it stays available for any OTHER NVIDIA GPU you keep on the host.",
"<code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> + <code>/etc/proxmenux/vfio-bind.bdfs</code> — <strong>NVIDIA only</strong>. Per-BDF binding state. The udev rule applies <code>ATTR'{'driver_override'}'=\"vfio-pci\"</code> at the PCI ADD event for each tracked Bus:Device.Function, so only the GPU(s) you've explicitly passed go to VFIO. This is what makes multi-GPU NVIDIA work — your other NVIDIA cards keep their <code>nvidia</code> driver and stay usable on the host.",
"<strong>AMD only.</strong> Dumps the GPU ROM from sysfs (<code>/sys/bus/pci/.../rom</code>) or the ACPI VFCT table to <code>/usr/share/kvm/vbios_&lt;card&gt;.bin</code>. The VM references it via <code>romfile=</code> so cards that misreport their own VBIOS still initialise correctly.",
"<strong>NVIDIA only.</strong> Stops and disables host NVIDIA services that could probe / lock the GPU at boot (<code>nvidia-persistenced</code>, <code>nvidia-powerd</code>, <code>nvidia-fabricmanager</code>). The <code>nvidia</code> module itself is left loaded so other NVIDIA GPUs on the host keep working with <code>nvidia-smi</code>.",
"<code>update-initramfs -u -k all</code> — only runs if any of the above actually changed."
]
},
"vmApply": {
"title": "VM config is applied via qm set",
"body": "The VM config at <code>/etc/pve/qemu-server/&lt;vmid&gt;.conf</code> is updated via <code>qm set</code> (never by direct <code>sed</code>):",
"after1": "A <code>x-vga=1</code> flag is added for every vendor <strong>except</strong> Intel iGPU — Intel integrated GPUs don't have dedicated VRAM for a pre-boot console, so that flag causes hangs.",
"after2": "Additional <code>hostpciN</code> lines are appended if the GPU's IOMMU group contains other devices you need to pass together."
},
"reboot": {
"title": "Reboot if host config was touched",
"body": "If Phase 2 changed anything at the kernel-module / cmdline / blacklist level, you'll be prompted to reboot. Reboot is mandatory before starting the VM — otherwise the GPU is still held by the host driver and VFIO can't claim it.",
"imageAlt": "Summary screen showing what was changed, followed by a reboot prompt"
}
},
"vendors": {
"heading": "Vendor-specific notes",
"nvidiaHeading": "NVIDIA",
"nvidiaBody": "NVIDIA consumer drivers detect that they're running in a VM and refuse to initialise with the infamous <em>\"Code 43\"</em> error. ProxMenux's workaround: hide KVM from the guest (<code>hidden=1</code>), set a spoofed hypervisor vendor ID <code>NV43FIX</code> in the <code>args</code> line, and pass <code>kvm=off</code>. This has worked reliably on GeForce drivers for years. On datacenter / Tesla / Quadro cards this isn't needed — those drivers are licensed for virtualisation.",
"nvidiaMultiHeading": "Multi-GPU NVIDIA support",
"nvidiaMultiBody": "Hosts with two or more NVIDIA GPUs are first-class. You can pass one card to a VM and keep the other(s) on the host for <code>nvidia-smi</code>, LXC GPU sharing, or any host-side workload. ProxMenux binds VFIO <strong>per-BDF</strong> (Bus:Device.Function) via a udev rule rather than globally blacklisting the <code>nvidia</code> module — so each card's destination is independent of the others, even when both GPUs are the same model and share the same <code>vendor:device</code> ID. The host nvidia driver stays loaded; only the specific BDFs you select get redirected to <code>vfio-pci</code>.",
"amdHeading": "AMD",
"amdBody": "The \"AMD reset bug\" means some cards crash when the VM stops and can't re-initialise without a host reboot. ProxMenux pre-screens for this by reading the PCI reset method, but cannot fix it after the fact. If you hit it, the community fix is the <vendorResetLink>vendor-reset</vendorResetLink> kernel module. The script doesn't install it automatically — the module is a DKMS build you add yourself if you see reset failures. Also on Windows guests, the <em>RadeonResetBugFix</em> service is the common userspace workaround.",
"intelHeading": "Intel iGPU",
"intelBody": "Intel iGPU passthrough is flaky but possible on UHD 630+ generations with <sriovLink>i915-sriov-dkms</sriovLink> for SR-IOV. For a single \"give the iGPU to one VM\" case, the script binds it exactly like a dedicated GPU, but skips <code>x-vga=1</code> (iGPUs don't carry a pre-boot VBIOS). You'll lose host console output — plan accordingly."
},
"verification": {
"heading": "Verification"
},
"troubleshoot": {
"heading": "Troubleshooting",
"code43Title": "Code 43 in Windows (NVIDIA)",
"code43Body": "The KVM hiding args didn't apply. Check <code>qm config &lt;vmid&gt; | grep -E \"cpu|args\"</code> — you should see <code>hidden=1</code> and <code>hv_vendor_id=NV43FIX</code>. If missing, re-run the script and re-select the same VM.",
"amdResetTitle": "AMD GPU works once, fails on VM restart",
"amdResetBody": "The AMD reset bug. Solutions (in order): (1) reboot the host — GPU will be usable again for one more VM cycle; (2) install the <code>vendor-reset</code> DKMS module and add <code>softdep amdgpu pre: vendor-reset</code>; (3) inside Windows, install the <em>RadeonResetBugFix</em> service.",
"stuckBootTitle": "VM stuck booting / GPU not detected",
"stuckBootBody": "Confirm VFIO actually holds the GPU on boot: <code>lspci -nnk -d vendor:device</code> must show <code>Kernel driver in use: vfio-pci</code>. If it still shows the vendor driver, the blacklist didn't take effect — check <code>/etc/modprobe.d/blacklist.conf</code> and <code>dmesg | grep vfio</code>, and regenerate initramfs: <code>update-initramfs -u -k all</code> then reboot.",
"darkTitle": "Host console goes dark after reboot and I can't SSH in",
"darkBody": "You passed the primary GPU through before having alternate access. Boot into a recovery shell (rescue ISO, IPMI), remove the lines from the VM config (<code>/etc/pve/qemu-server/&lt;vmid&gt;.conf</code>), and remove the vfio options:",
"logTitle": "Check the install log",
"logBody": "Every run writes to <code>/tmp/add_gpu_vm.log</code>. Attach it when asking for help on GitHub."
},
"revert": {
"heading": "Reverting manually",
"intro": "There isn't a dedicated \"remove GPU from VM\" shortcut in ProxMenux today. To detach cleanly:"
},
"related": {
"heading": "Related",
"items": [
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — install drivers on the host first if you also want the GPU usable from there."
},
{
"label": "Add GPU to LXC",
"href": "/docs/hardware/igpu-acceleration-lxc",
"tail": " — alternative model: share the GPU with multiple containers instead of dedicating it to a VM."
},
{
"label": "Switch GPU Mode (VM ↔ LXC)",
"href": "/docs/hardware/switch-gpu-mode",
"tail": " — flip the same GPU between modes without re-doing all the wiring."
},
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands",
"tail": " — lspci, IOMMU verification, qm set hostpci reference."
}
]
}
}
@@ -0,0 +1,185 @@
{
"meta": {
"title": "Add GPU to LXC | ProxMenux Documentation",
"description": "Share an Intel, AMD or NVIDIA GPU with an LXC container for hardware-accelerated transcoding (Plex / Jellyfin / Frigate), OpenCL / CUDA workloads, and Mesa video acceleration. ProxMenux handles device nodes, GID alignment, and distro-specific driver install inside the container."
},
"header": {
"title": "Add GPU to LXC",
"description": "Share one or more GPUs with a Proxmox LXC container. The host keeps using the GPU normally — the container just gets access through device nodes. Works with Intel iGPUs (Quick Sync / VA-API), AMD cards (Mesa / ROCm), and NVIDIA (CUDA / NVENC).",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "Adds <code>dev&lt;N&gt;</code> entries to the LXC config (<code>/etc/pve/lxc/&lt;ctid&gt;.conf</code>) so the container sees <code>/dev/dri/*</code>, <code>/dev/kfd</code> or <code>/dev/nvidia*</code> — whichever applies to your GPU. Then it boots the container, detects the distro inside, and installs the matching userspace drivers (Mesa, intel-media-driver, NVIDIA runtime…) so apps like Plex, Jellyfin or Frigate actually use the GPU for transcoding. GIDs (<code>video</code>, <code>render</code>) are aligned between host and container so permissions match."
},
"compare": {
"heading": "LXC sharing vs VM passthrough",
"intro": "LXC containers share the host kernel, so they can <em>share</em> the host's GPU without taking it over. That's a big difference from VMs: with <vmLink>VM passthrough</vmLink> the GPU is exclusive to one VM and the host can't use it. With LXC, multiple containers plus the host can all hit the same GPU at once.",
"headerFeature": "Feature",
"headerLxc": "LXC (this page)",
"headerVm": "VM",
"rows": [
{
"feature": "Host keeps using the GPU?",
"lxc": "Yes",
"vm": "No — exclusive to the VM"
},
{
"feature": "Multiple containers sharing one GPU?",
"lxc": "Yes",
"vm": "No"
},
{
"feature": "Requires IOMMU / VFIO on the host?",
"lxc": "No",
"vm": "Yes"
},
{
"feature": "Reboot required?",
"lxc": "Usually no (just restart the CT)",
"vm": "Yes, always"
},
{
"feature": "Supports running any OS?",
"lxc": "Only Linux (LXC is Linux-only)",
"vm": "Windows, macOS, any Linux"
}
]
},
"prereqs": {
"title": "Before you start",
"gpu": "<strong>A GPU on the host</strong> — Intel iGPU, AMD dGPU or APU, or an NVIDIA card. The script auto-detects all three via <code>lspci</code>.",
"gpuCheck": "lspci | grep -iE 'VGA|3D|Display'",
"vfio": "<strong>The GPU is NOT bound to vfio-pci.</strong> If the GPU is currently assigned to a VM via passthrough, it's invisible to the host kernel driver and the LXC can't use it. The script detects this and offers to run <switchLink>Switch GPU Mode</switchLink> for you.",
"nvidia": "<strong>For NVIDIA only:</strong> the NVIDIA host driver must already be installed — ProxMenux needs to match the container's userspace libs to the host version. If you haven't done it yet, run <nvidiaLink>Install NVIDIA Drivers on the Host</nvidiaLink> first.",
"nvidiaCheck": "nvidia-smi",
"container": "<strong>An existing LXC container.</strong> The script operates on a container you already created — it doesn't create one. The container should ideally be <strong>privileged</strong> (unprivileged works but needs UID/GID mapping which the script does not configure)."
},
"unpriv": {
"title": "Works on both privileged and unprivileged containers",
"body": "The script writes <code>dev&lt;N&gt;</code> entries to the LXC config and, on unprivileged containers, aligns the <code>video</code> and <code>render</code> GIDs between host and container so the GPU device nodes are reachable from inside without you having to hand-edit <code>lxc.idmap</code>."
},
"running": {
"heading": "Running the installer",
"body": "Open ProxMenux on the host, go to <strong>Hardware: GPUs and Coral-TPU → Add GPU to LXC</strong>.",
"imageAlt": "Menu entry for 'Add GPU to LXC' inside Hardware: GPUs and Coral-TPU"
},
"howRuns": {
"heading": "How the script runs",
"body": "Two phases: all the decisions upfront, then all the changes in one go. Nothing on your container is touched until you confirm."
},
"walkthrough": {
"heading": "Walking through the flow",
"detect": {
"title": "Detect host GPUs",
"body": "The script scans <code>lspci</code> for VGA / 3D / Display controllers matching Intel, AMD or NVIDIA. For NVIDIA it also verifies the <code>nvidia</code> kernel module is loaded and <code>nvidia-smi</code> works — the host driver version it reports will be used to pick the right <code>.run</code> installer for the container.",
"tipTitle": "NVIDIA not ready?",
"tipBody": "If NVIDIA is detected but the module isn't loaded, the script won't offer the NVIDIA path. Run <nvidiaLink>Install NVIDIA Drivers on the Host</nvidiaLink> first (and reboot), then come back."
},
"pickCt": {
"title": "Pick an LXC container",
"body": "You'll see a list of every LXC on the host with its ID and name. Pick the one that should get the GPU. The container can be running or stopped — the script handles both (stops it briefly during config, restarts it, and leaves it in its original state at the end).",
"imageAlt": "Dialog listing existing LXC containers to choose from"
},
"selectGpu": {
"title": "Select the GPU(s) to add",
"body": "If more than one GPU is present, you get a checklist. You can add multiple to the same container (e.g. an Intel iGPU for Quick Sync + an AMD dGPU for ROCm). If only one GPU is detected, it's auto-selected.",
"imageAlt": "Checklist showing detected GPUs (Intel / AMD / NVIDIA) with vendor and PCI address"
},
"preflight": {
"title": "Pre-flight checks",
"imageAlt": "Dialog offering to run Switch GPU Mode when the selected GPU is still bound to vfio-pci for VM passthrough",
"intro": "Three checks, any of which can block or redirect you:",
"items": [
"<strong>SR-IOV.</strong> If the selected GPU is a Virtual Function (VF) or a Physical Function with active VFs, LXC passthrough doesn't apply — the device is managed by the SR-IOV driver. Blocked.",
"<strong>Bound to vfio-pci.</strong> If the GPU is currently held by VFIO for VM passthrough, the host kernel can't create <code>/dev/dri/*</code> or <code>/dev/nvidia*</code> nodes for it. The script offers to run <switchLink>Switch GPU Mode</switchLink> which undoes the VFIO binding; you'll likely need a reboot before re-running Add GPU to LXC.",
"<strong>Already configured.</strong> If the container already has every dev node for the selected GPU, the script says so and exits cleanly. If it's partially configured, it continues with only the missing pieces."
]
},
"applyConfig": {
"title": "Apply the LXC config changes",
"body1": "The script stops the container, edits <code>/etc/pve/lxc/&lt;ctid&gt;.conf</code>, and adds <code>dev&lt;N&gt;</code> entries with the right GIDs for the selected GPUs. Using <code>dev:</code> entries (over the older <code>lxc.mount.entry</code> lines) is the modern Proxmox way — group permissions are set at config parse time instead of at mount time.",
"body2": "Example after Intel + NVIDIA on the same container:"
},
"installDrivers": {
"title": "Start the container and install drivers inside",
"body": "Once the config is written, the script starts the container, waits up to ~30 seconds for <code>pct exec</code> to respond, and then detects the container's distro from <code>/etc/os-release</code>. Based on that, it installs the right userspace packages.",
"headerDistro": "Distro",
"headerInt": "Intel / AMD",
"headerNvidia": "NVIDIA",
"rows": [
{
"distro": "Alpine",
"intel": "apk add mesa-va-gallium intel-media-driver libva-utils",
"nvidia": "apk add nvidia-utils"
},
{
"distro": "Arch / Manjaro",
"intel": "pacman -Sy intel-media-driver mesa libva-utils",
"nvidia": "pacman -Sy nvidia-utils"
}
],
"debianDistro": "Debian / Ubuntu / others",
"debianIntel": "apt-get install va-driver-all intel-opencl-icd vainfo",
"debianNvidia": "extract host <code>.run</code> → <code>pct push</code> → run with <code>--no-kernel-modules --no-dkms</code>",
"whyTitle": "Why the NVIDIA .run dance on Debian",
"whyBody": "Debian / Ubuntu don't ship NVIDIA packages with a version granular enough to match the host driver byte-for-byte. The userspace libs inside the container <strong>must match the kernel module version</strong> loaded on the host, or <code>nvidia-smi</code> fails with a version mismatch. ProxMenux solves this by using the exact same <code>.run</code> installer that was used for the host — extracted, tarred, pushed into the container with <code>pct push</code>, and run with <code>--no-kernel-modules --no-dkms</code> so only the userspace is touched."
},
"alignGids": {
"title": "Align GIDs and restore state",
"body1": "Device files on the host are owned by group <code>video</code> (GID 44) or <code>render</code> (GID 104). The container's distro may ship different GID numbers for those groups, which would make the GPU nodes unreachable from inside. The script rewrites <code>/etc/group</code> in the container so <code>video:44</code> and <code>render:104</code> match exactly.",
"body2": "Finally, it restores the container to its original state — if it was stopped when you started, it gets stopped again. If it was running, it stays running."
}
},
"vendors": {
"heading": "Vendor-specific notes",
"intelHeading": "Intel iGPU",
"intelBody": "Most common path — great for Plex / Jellyfin / Frigate hardware transcoding via <em>Quick Sync</em>. The container gets <code>/dev/dri/card0</code> (legacy) and <code>/dev/dri/renderD128</code> (modern render-only node — what apps actually use). No host-side changes needed; the <code>i915</code> driver on the host already created the nodes.",
"amdHeading": "AMD",
"amdBody": "Same DRI nodes as Intel for graphics / VA-API. If <code>/dev/kfd</code> exists on the host (AMD compute / ROCm kernel support), the script also adds it so containers can do OpenCL / ROCm workloads. Mesa VA drivers cover the video decode side.",
"nvidiaHeading": "NVIDIA",
"nvidiaBody": "Adds every <code>/dev/nvidia*</code> node the host exposes. The critical piece is <strong>driver-version matching</strong>: host module version and container userspace lib version must be identical, otherwise <code>nvidia-smi</code> inside the container fails. ProxMenux captures the host version at detection time and uses the same <code>.run</code> file to install the container userspace. For Debian containers the install bumps container memory to 2 GB temporarily (installer needs ~1.5 GB free to extract) and restores it afterwards.",
"updateTitle": "After you update the host NVIDIA driver, re-run this script",
"updateBody": "When you upgrade the NVIDIA driver on the host, the container's userspace libs stay on the old version and <code>nvidia-smi</code> inside the container breaks. ProxMenux's <nvidiaLink>NVIDIA host installer</nvidiaLink> detects containers with NVIDIA passthrough and offers to update them automatically — but if you skipped that prompt, just run Add GPU to LXC again on the same container and it'll refresh the userspace."
},
"verification": {
"heading": "Verification",
"body": "After the script finishes, log into the container and check the GPU is visible:"
},
"troubleshoot": {
"heading": "Troubleshooting",
"mismatchTitle": "nvidia-smi: Failed to initialize NVML: Driver/library version mismatch",
"mismatchBody": "Container userspace version ≠ host module version. Run Add GPU to LXC again on that container — the script extracts the current host <code>.run</code> and re-installs userspace matching.",
"denyTitle": "Permission denied on /dev/dri/renderD128 inside the container",
"denyBody": "Usually one of: (1) container is unprivileged without UID/GID mapping to host <code>render</code> group; (2) the user inside the container isn't in the <code>render</code> group. Fix: add the user to <code>render</code> inside the container (<code>usermod -aG render &lt;user&gt;</code>), or switch to privileged mode if the workload is trusted.",
"vainfoTitle": "vainfo says: VA-API version 1.xx; failed to initialize",
"vainfoBody": "The VA-API runtime is there but no suitable driver was installed. On Intel, install <code>intel-media-driver</code> (newer gens) or <code>i965-va-driver</code> (older gens). On AMD, <code>mesa-va-drivers</code>. Re-run the script if in doubt.",
"logTitle": "Install log",
"logBody": "Every run writes to <code>/tmp/add_gpu_lxc.log</code> on the host. Include it when asking for help on GitHub."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — required prerequisite for NVIDIA GPUs before passing them to a container."
},
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough",
"tail": " — alternative model when you need the GPU dedicated to a single VM."
},
{
"label": "Switch GPU Mode (VM ↔ LXC)",
"href": "/docs/hardware/switch-gpu-mode",
"tail": " — toggle the same GPU between LXC sharing and VM passthrough."
},
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands",
"tail": " — quick reference for related shell commands."
}
]
}
}
@@ -0,0 +1,191 @@
{
"meta": {
"title": "Install Coral TPU on the Host | ProxMenux Documentation",
"description": "Install Google Coral TPU drivers on a Proxmox VE host. ProxMenux auto-detects whether you have M.2 / Mini-PCIe or the USB Accelerator (or both) and runs only the install path that applies — gasket/apex kernel modules via DKMS for PCIe, libedgetpu1-std runtime for USB."
},
"header": {
"title": "Install Coral TPU on the Host",
"description": "Prepare the Proxmox host so a Coral TPU can later be passed to an LXC container. ProxMenux auto-detects whether you have a M.2 / Mini-PCIe card, a USB Accelerator, or both, and runs only the install path that applies — kernel-module build via DKMS for PCIe, Google's Edge TPU runtime for USB.",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "The Coral installer is <strong>unified and hardware-aware</strong>: you run one menu option and it figures out what you actually have. M.2 / Mini-PCIe cards need kernel modules (<code>gasket</code> + <code>apex</code>) built with DKMS so they survive kernel upgrades. USB Accelerators just need the Google Edge TPU runtime (<code>libedgetpu1-std</code>) from Google's own APT repository. Both types plugged in? Both paths run in sequence."
},
"which": {
"heading": "Which Coral do I have?",
"body": "The two kinds of Coral devices you can plug into a Proxmox host look very different and the host-side install is very different too. The script handles both, but it's good to know what you have before running anything:",
"headerForm": "Form factor",
"headerDetect": "Detection",
"headerInstall": "Install type",
"headerReboot": "Reboot?",
"pcieForm": "M.2 / Mini-PCIe",
"pcieFormSub": "(dual-edge TPU on an M.2 card)",
"pcieDetect": "PCI vendor <code>1ac1</code>",
"pcieInstall": "Kernel module (gasket + apex) via DKMS",
"pcieReboot": "Yes",
"usbForm": "USB Accelerator",
"usbFormSub": "(small plastic dongle)",
"usbDetect": "USB <code>1a6e:089a</code> (unprogrammed) / <code>18d1:9302</code> (programmed)",
"usbInstall": "User-space runtime (<code>libedgetpu1-std</code>) from Google APT repo",
"usbReboot": "No"
},
"prereqs": {
"title": "Before you start",
"coral": "<strong>A Coral TPU plugged into the host</strong> (M.2, Mini-PCIe or USB). No Coral means no install — the script just tells you nothing was detected and exits.",
"coralCheck": "lspci -d 1ac1: ; lsusb | grep -E '1a6e:089a|18d1:9302'",
"internet": "<strong>Internet access</strong> on the host — for PCIe the DKMS path clones a GitHub repo, for USB it adds a Google APT repo and downloads the <code>libedgetpu1-std</code> package.",
"headers": "<strong>Kernel headers available via APT</strong>. On Proxmox this means <code>proxmox-headers-$(uname -r)</code> must be installable — needed only for the PCIe/M.2 path, but the script fetches it automatically so you don't have to.",
"reboot": "<strong>Be OK with a reboot</strong> if you have PCIe hardware. The kernel module is built and loaded at the end, but a fresh boot is the clean way to confirm it comes up on its own."
},
"hostPrepTip": {
"title": "This only prepares the host",
"body": "Installing Coral here makes the host <em>ready</em> — the TPU is visible to the host kernel and can be handed to an LXC. To actually <em>use</em> it from a container (Frigate, DeepStack, etc.), the next step is <lxcLink>Add Coral TPU to an LXC</lxcLink>."
},
"running": {
"heading": "Running the installer",
"body": "Open ProxMenux on the host, go to <strong>Hardware: GPUs and Coral-TPU → Install/Update Coral TPU on Host</strong>.",
"imageAlt": "Menu entry for 'Install/Update Coral TPU on Host' inside Hardware: GPUs and Coral-TPU"
},
"howRuns": {
"heading": "How the script runs",
"body": "Hardware is detected first, so the install plan is shaped to your actual setup. Nothing is installed until you confirm."
},
"walkthrough": {
"heading": "Walking through the flow",
"detect": {
"title": "Hardware detection",
"body": "The script reads <code>/sys/bus/pci/devices/*/vendor</code> looking for <code>0x1ac1</code> (Global Unichip Corp., the silicon vendor of the Coral TPU chips) and runs <code>lsusb</code> looking for the USB Accelerator IDs. The USB device has <strong>two</strong> IDs depending on whether its firmware has been loaded yet:",
"items": [
"<code>1a6e:089a</code> — Global Unichip, <em>unprogrammed</em> state (before the Edge TPU runtime talks to it the first time).",
"<code>18d1:9302</code> — Google, <em>programmed</em> state (after the runtime loads firmware onto it)."
],
"outro": "If neither is found, you get an informative dialog and the script exits cleanly — no partial changes on the host."
},
"prompt": {
"title": "Pre-install prompt",
"body": "Before touching anything, a single dialog summarises what was detected and what will be installed. You can cancel here without any side effects.",
"imageAlt": "Pre-install dialog showing detected Coral hardware (M.2/PCIe count + USB count) and the list of steps the installer will run"
},
"pcie": {
"title": "PCIe path — gasket + apex kernel modules via DKMS",
"body": "Only runs if the script found a PCIe / M.2 Coral. It's the heavier of the two paths because it's compiling a kernel module for your exact running kernel.",
"items": [
"<strong>Cleanup.</strong> If a previous <code>gasket-dkms</code> install left dpkg in a broken state (typical after a PVE 9 kernel upgrade where DKMS autoinstall failed silently), force-purge it.",
"<strong>Install build deps:</strong> <code>git</code>, <code>dkms</code>, <code>build-essential</code>, <code>proxmox-headers-$(uname -r)</code>."
],
"cloneIntro": "<strong>Clone the driver source.</strong> Prefers the <feranickLink>feranick/gasket-driver</feranickLink> community fork (actively maintained, kernel 6.12+ ready). Falls back to <googleLink>google/gasket-driver</googleLink> if feranick is unreachable, applying kernel-specific patches:",
"kernelPatches": [
"Kernel 6.5+ : <code>no_llseek</code> removed upstream → <code>noop_llseek</code> substitution",
"Kernel 6.13+ : <code>MODULE_IMPORT_NS(DMA_BUF)</code> requires string literal"
],
"afterItems": [
"<strong>Stage sources under <code>/usr/src/gasket-1.0/</code>,</strong> generate <code>dkms.conf</code>, register with <code>dkms add</code>.",
"<strong>Build + install:</strong> <code>dkms build</code> then <code>dkms install</code>. If anything fails, the last 50 lines of <code>make.log</code> print to the terminal so you see the real error — no hunting in log files.",
"<strong>Create the <code>apex</code> group + udev rules</strong> (<code>/etc/udev/rules.d/99-coral-apex.rules</code>) so <code>/dev/apex_*</code> nodes get the right group on the next boot.",
"<strong>Load the modules:</strong> <code>modprobe gasket</code> + <code>modprobe apex</code>."
],
"imageAlt": "DKMS build progress + module load output for the gasket/apex kernel modules"
},
"usb": {
"title": "USB path — Edge TPU runtime from Google",
"body": "Only runs if a USB Accelerator was detected. Much simpler:",
"items": [
"<strong>Add Google's GPG key</strong> to <code>/etc/apt/keyrings/coral-edgetpu.gpg</code>.",
"<strong>Add the APT repository</strong> to <code>/etc/apt/sources.list.d/coral-edgetpu.list</code> with <code>signed-by=</code> pointing at the keyring (modern, non-deprecated format).",
"<strong>Install <code>libedgetpu1-std</code></strong> — the standard-performance Edge TPU runtime.",
"<strong>Reload udev</strong> so the rules shipped with the package apply to the USB device without having to unplug/replug."
],
"stdTitle": "Why libedgetpu1-std and not libedgetpu1-max?",
"stdBody": "The <code>max</code> variant overclocks the Coral and runs hotter. Fine for desktop use with airflow; not recommended inside small NUC / Mini-PC builds or passively cooled Proxmox hosts. If you really want it, install by hand afterwards: <code>apt install libedgetpu1-max</code>."
},
"reboot": {
"title": "Reboot prompt (only if PCIe ran)",
"body": "If the PCIe path ran, the script offers a reboot. The modules were <code>modprobe</code>'d already so in theory you can skip the reboot — but a clean boot is the right way to verify the module comes up on its own and <code>/dev/apex_0</code> appears with group <code>apex</code>. For USB-only installs, no reboot is suggested (the runtime and udev rules are active immediately).",
"imageAlt": "Final summary + reboot prompt after a PCIe install"
}
},
"reinstallUninstall": {
"heading": "Reinstall or uninstall",
"intro": "Running the installer on a host where Coral is already installed (PCIe via <code>gasket-dkms</code>, USB via <code>libedgetpu1-std</code>/<code>libedgetpu1-max</code>, or both) no longer drops straight into another fresh install. Instead, ProxMenux detects the existing setup and shows an action menu so you can decide what to do.",
"imageAlt": "Coral action menu with two choices — Reinstall / update Coral drivers, or Uninstall Coral drivers and configuration — shown when the installer detects a previous Coral install on the host",
"imageCaption": "The action menu only appears when at least one Coral component is already installed (DKMS gasket entry, <code>libedgetpu1-*</code> package, or live <code>/dev/apex_*</code> device nodes).",
"reinstallHeading": "Reinstall / update",
"reinstallBody": "Continues with the normal install flow — useful after a kernel upgrade if the DKMS rebuild didn't happen automatically, or to lift the runtime to a newer <code>libedgetpu1-*</code> from the Google Coral apt repo. The previous DKMS state is cleaned up first so a half-installed package from a failed earlier attempt doesn't block the new build.",
"uninstallHeading": "Uninstall — what gets removed",
"uninstallIntro": "Confirms with a yes/no dialog before doing anything (LXC containers with apex passthrough will lose access to <code>/dev/apex_*</code> after the next reboot — the warning makes that clear). Then it performs a full, idempotent rollback:",
"uninstallItems": [
"Unloads the <code>apex</code> and <code>gasket</code> kernel modules.",
"Removes every DKMS-registered <code>gasket/&lt;version&gt;</code> entry so the modules don't come back on the next kernel install.",
"Purges the <code>gasket-dkms</code>, <code>libedgetpu1-std</code> and <code>libedgetpu1-max</code> apt packages, then runs <code>apt-get autoremove --purge</code>.",
"Deletes the udev rule <code>/etc/udev/rules.d/99-coral-apex.rules</code> ProxMenux wrote; restores the upstream <code>60-gasket-dkms.rules</code> group to its default if it's still present.",
"Removes the <code>apex</code> system group <strong>only if no users still belong to it</strong> — if you mapped a custom user into <code>apex</code> for an LXC passthrough, the group is left in place and a warning prints the current members.",
"Cleans the Google Coral apt repository entry and keyring (<code>/etc/apt/sources.list.d/coral-edgetpu.list</code> + <code>coral-edgetpu-archive-keyring.gpg</code>).",
"Prompts for a reboot at the end <strong>only if the PCIe path was installed</strong> — the cleanest way to flush the kernel modules. USB-only uninstalls don't need one."
],
"lxcWarnTitle": "LXC containers with apex passthrough",
"lxcWarnBody": "Uninstalling on the host invalidates the device path mapped into any LXC container configured for apex passthrough. Plan the operation during a maintenance window if Frigate / DeepStack / similar workloads depend on it."
},
"updates": {
"heading": "Update notifications",
"intro": "ProxMenux now tracks the installed Coral components in its managed-installs registry. Both variants are followed independently — a host with both M.2 and USB Coral devices gets two update streams, each with its own upstream source:",
"headerVariant": "Variant",
"headerTracked": "Tracked version",
"headerUpstream": "Upstream source",
"pcieVariant": "PCIe / M.2",
"pcieTracked": "<code>gasket-dkms</code> Debian version (or the DKMS-registered version if the package was force-removed)",
"pcieUpstream": "Latest tag of <code>feranick/gasket-driver</code> on GitHub (7-day cache, build-number comparison)",
"usbVariant": "USB",
"usbTracked": "<code>libedgetpu1-std</code> or <code>libedgetpu1-max</code> apt version",
"usbUpstream": "Local <code>apt-cache policy</code> candidate (Google Coral apt repo)",
"outro": "When a newer version is detected the Monitor fires a <code>coral_driver_update_available</code> notification on every enabled channel (Telegram, Discord, Gotify, ntfy, email, webhook). The notification points back at the same installer entry — pick <strong>Reinstall / update</strong> from the action menu above to apply it.",
"antiTitle": "Anti-cascade by design",
"antiBody": "One notification per variant, only when the upstream version actually changes — never on every 24h scan. If you ignore an update it doesn't re-ping you until a newer release lands.",
"rebootTitle": "Reboot is only needed for the PCIe path",
"rebootBody": "The gasket DKMS rebuild loads new kernel modules — that needs a reboot to be active. The USB runtime upgrade is a user-space library swap, no reboot required."
},
"manual": {
"heading": "Manual equivalent",
"intro": "If you want to know what happens under the hood, or redo an individual step by hand, the raw commands per path look like this.",
"pcieHeading": "PCIe / M.2 (gasket + apex via DKMS)",
"usbHeading": "USB (libedgetpu runtime)"
},
"verification": {
"heading": "Verification",
"pcieHeading": "PCIe / M.2",
"usbHeading": "USB"
},
"troubleshoot": {
"heading": "Troubleshooting",
"dkmsFailTitle": "DKMS build fails after a kernel upgrade",
"dkmsFailBody": "Most common cause on PVE 9: the running kernel bumped but <code>proxmox-headers-$(uname -r)</code> isn't installed for it yet. Check with <code>dpkg -l proxmox-headers-$(uname -r)</code>. Install the missing headers and re-run the script — ProxMenux's <code>cleanup_broken_gasket_dkms</code> step handles any leftover half-configured package state.",
"apexMissTitle": "/dev/apex_0 missing after reboot",
"apexMissBody": "The module isn't loaded. Try <code>modprobe apex</code> by hand. If that errors, check <code>dmesg | grep -iE \"apex|gasket\"</code> for the real failure — common culprits are kernel version mismatch (DKMS was built for a different kernel than the one you booted) or a firmware upgrade that disabled the PCIe slot the Coral is in.",
"lxcMissTitle": "Can see /dev/apex_0 but LXC can't",
"lxcMissBody": "Host is fine. Problem is passthrough config — see <lxcLink>Add Coral TPU to an LXC</lxcLink>.",
"usbUnreachTitle": "USB Accelerator detected but Frigate / TFLite can't reach it",
"usbUnreachBody": "Check the udev rules shipped with <code>libedgetpu1-std</code> took effect: <code>ls -l /dev/bus/usb/*/*</code>. The device should NOT be owned by root:root with mode 0600 — if it is, run <code>udevadm control --reload-rules &amp;&amp; udevadm trigger</code> on the host, unplug the USB Coral, wait 3 seconds and plug it back in.",
"logTitle": "Install log",
"logBody": "Every run writes to <code>/tmp/coral_install.log</code> on the host. If the DKMS build dies, the script also appends the last 50 lines of <code>/var/lib/dkms/gasket/1.0/build/make.log</code> to that log — attach it when asking for help on GitHub."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Add Coral TPU to LXC",
"href": "/docs/hardware/coral-tpu-lxc",
"tail": " — pass the host Coral device into a container (Frigate, CodeProject.AI…)."
},
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — same idea for NVIDIA GPUs."
},
{
"label": "ProxMenux Monitor — Hardware tab",
"href": "/docs/monitor/dashboard/hardware",
"tail": " — the Coral modal that surfaces driver, modules, device nodes, runtime status and live temperature once the host install is done."
}
]
}
}
@@ -0,0 +1,204 @@
{
"meta": {
"title": "Install NVIDIA Drivers on the Host | ProxMenux Documentation",
"description": "Install and configure NVIDIA proprietary drivers on a Proxmox VE host using ProxMenux. Covers kernel compatibility, VFIO setup, persistence service, optional NVENC patch and automatic LXC propagation."
},
"header": {
"title": "Install NVIDIA Drivers on the Host",
"description": "Install the NVIDIA proprietary driver on a Proxmox VE host using ProxMenux. The installer handles kernel compatibility, nouveau blacklisting, VFIO configuration, persistence service and can propagate the driver to any LXC container that already has NVIDIA passthrough configured.",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "ProxMenux automates the whole NVIDIA driver lifecycle on the host: detects your GPU, picks a driver version that is compatible with your running kernel, blacklists <code>nouveau</code>, downloads and runs the official NVIDIA <code>.run</code> installer with DKMS, installs the <code>nvidia-persistenced</code> service and udev rules, and offers to apply the optional NVENC patch. If you already have LXC containers with NVIDIA passthrough, it can update the userspace libraries inside them so their version matches the host."
},
"who": {
"heading": "Who is this for?",
"body": "If you have an NVIDIA GPU and you want to use it for hardware-accelerated transcoding in Plex, Jellyfin, Frigate, Immich, Stable Diffusion or any other app running <strong>inside an LXC container</strong>, you need to install the driver on the Proxmox <em>host</em> first. This page covers that host-side install. Passing the GPU to a <strong>virtual machine (VM)</strong> uses a different flow (VFIO passthrough) and is documented separately."
},
"prereqs": {
"title": "Before you start",
"gpu": "<strong>An NVIDIA GPU</strong> physically installed in the host. The script auto-detects it; AMD and Intel GPUs are not handled here.",
"gpuCheck": "lspci | grep -i nvidia",
"notVm": "The GPU <strong>is not currently assigned to a VM via VFIO passthrough</strong>. If it is, the script will refuse to install the host driver to avoid breaking the passthrough config.",
"internet": "Internet access on the host. The installer downloads the driver from <code>download.nvidia.com</code> and, optionally, clones <code>nvidia-persistenced</code> and <code>nvidia-patch</code> from GitHub.",
"space": "About <strong>2 GB of free space</strong> in <code>/opt/nvidia</code> (workdir) plus the RAM used during the install. A reboot is required at the end."
},
"vmWarn": {
"title": "GPU assigned to a VM? Stop here",
"body": "If the GPU is currently bound to <code>vfio-pci</code> (i.e. it is being passed through to a VM), installing the host driver can break the passthrough and destabilise the system. ProxMenux detects this and aborts. Remove the GPU from the VM passthrough configuration and reboot before running this script."
},
"running": {
"heading": "Running the installer",
"body": "Open ProxMenux on the host, go to <strong>Hardware Graphics → NVIDIA GPU Driver Installer</strong>. What you see depends on whether a driver is already present.",
"imageAlt": "Hardware Graphics menu with the NVIDIA GPU Driver Installer entry highlighted"
},
"howRuns": {
"heading": "How the script runs",
"body": "The installer goes through three phases with clear separation between \"collecting information and validating\" and \"actually touching the host\". Until the final confirmation, nothing has been changed."
},
"walkthrough": {
"detect": {
"title": "GPU detection and overview",
"body1": "The script scans the PCI bus and shows every NVIDIA video controller it finds, the current driver status (or <em>\"No NVIDIA driver installed\"</em>), and any LXC container that already has NVIDIA passthrough configured (driver version inside each one).",
"body2": "Review the overview carefully. If the detected GPU is not what you expect, or if a container's version already matches the host, you can cancel here without side effects.",
"imageAlt": "Pre-install overview showing detected GPUs, current driver status and LXC containers with NVIDIA passthrough"
},
"version": {
"title": "Choose the driver version",
"body1": "ProxMenux fetches the list of available drivers from NVIDIA and <strong>filters out versions that are not compatible with your running kernel</strong>. The <em>Latest available</em> option is almost always the right pick.",
"body2": "The compatibility matrix the script uses:",
"headerKernel": "Kernel",
"headerPve": "Typical PVE version",
"headerMin": "Minimum NVIDIA driver",
"rows": [
{
"kernel": "6.17+",
"pve": "Proxmox VE 9.x",
"minCode": "580.82.07",
"minTail": " or newer"
},
{
"kernel": "6.8 6.16",
"pve": "Proxmox VE 8.2+",
"minCode": "550.x",
"minTail": " or newer"
},
{
"kernel": "6.2 6.7",
"pve": "Proxmox VE 8.0 8.1",
"minCode": "535.x",
"minTail": " or newer"
},
{
"kernel": "5.15+",
"pve": "Proxmox VE 7.x (legacy)",
"minCode": "470.x",
"minTail": " or newer"
}
],
"whyTitle": "Why kernel matters",
"whyBody": "Kernel 6.17 introduced internal API changes that break older NVIDIA drivers. If you install a driver below the minimum for your kernel, DKMS will fail to build the module and the GPU will not be available after reboot. ProxMenux filters the list so you can't pick an incompatible version by accident.",
"imageAlt": "Driver version selector with kernel-compatible versions, Latest available on top"
},
"uninstall": {
"title": "Clean uninstall (only if reinstalling)",
"body": "If a driver is already present and you picked a different version, ProxMenux stops the NVIDIA services, unloads the kernel modules, removes DKMS entries and purges <code>nvidia-*</code> / <code>libnvidia-*</code> / <code>cuda-*</code> packages before touching the new installer. This avoids the classic mixed-version mess."
},
"prepare": {
"title": "Prepare the system",
"body": "Behind a single confirmation, the script:",
"items": [
"Installs <code>pve-headers-$(uname -r)</code> (or <code>proxmox-headers-$(uname -r)</code>), <code>build-essential</code> and <code>dkms</code>.",
"Creates <code>/etc/modprobe.d/nouveau-blacklist.conf</code> blacklisting <code>nouveau</code>, and tries to unload it immediately.",
"Writes <code>/etc/modules-load.d/nvidia-vfio.conf</code> with <code>vfio</code>, <code>vfio_pci</code>, <code>nvidia</code>, <code>nvidia_uvm</code> and related modules."
]
},
"download": {
"title": "Download and run the NVIDIA installer",
"body": "The installer downloads the <code>NVIDIA-Linux-x86_64-&lt;version&gt;.run</code> file into <code>/opt/nvidia</code>, validates it (size + executable signature, not just HTTP 200), then runs it with DKMS so the kernel module rebuilds automatically across kernel upgrades.",
"imageAlt": "Download progress followed by the NVIDIA installer running its DKMS build"
},
"persist": {
"title": "Persistence service and udev rules",
"body": "ProxMenux then installs <persistLink>nvidia-persistenced</persistLink> and writes udev rules at <code>/etc/udev/rules.d/70-nvidia.rules</code> so <code>/dev/nvidia*</code> device nodes appear reliably on boot. Without these, LXC passthrough can race on container startup and end up with a container that can't see the GPU."
},
"nvenc": {
"title": "Optional: apply the NVENC patch",
"body": "Consumer NVIDIA GPUs (GeForce line) limit the number of simultaneous NVENC encoding sessions. The community <patchLink>keylase/nvidia-patch</patchLink> removes that restriction. If you plan to use the GPU for Plex / Jellyfin / Frigate with many concurrent streams, answer <strong>Yes</strong> when prompted.",
"supportTitle": "Check patch support for your driver",
"supportBody": "The patch does not cover every driver version. Before relying on it in production, verify your version is listed in the <patchTableLink>patch table</patchTableLink>. If it isn't supported yet, pick a nearby older driver that is."
},
"propagate": {
"title": "Optional: propagate the driver to LXC containers",
"body1": "If the overview screen listed containers with NVIDIA passthrough, ProxMenux now offers to update the userspace libraries inside each one to match the host. Host kernel module and container userspace <strong>must be the exact same version</strong> — otherwise <code>nvidia-smi</code> inside the container will fail with a \"version mismatch\" error.",
"body2": "The update is distro-aware: <code>apk</code> for Alpine, <code>pacman</code> for Arch, and the same <code>.run</code> installer (with <code>--no-kernel-modules --no-dkms --no-install-compat32-libs</code>) for Debian/Ubuntu and other distros. It temporarily raises container RAM to 2 GB if lower, runs the install, then restores the original RAM setting.",
"imageAlt": "Prompt listing LXCs with NVIDIA passthrough and current driver version, with Yes/No to update them all"
},
"reboot": {
"title": "Reboot",
"body": "Finally, the script rebuilds <code>initramfs</code> for all kernels and offers to reboot. A reboot <strong>is required</strong>: the nouveau blacklist and the new kernel module only take effect after restart."
}
},
"reinstallUninstall": {
"heading": "Reinstall or uninstall",
"intro": "When the installer detects that a NVIDIA driver is already loaded (<code>nvidia-smi</code> returns a version), it doesn't silently re-install on top. Instead it shows an action menu so you can choose what to do.",
"imageAlt": "NVIDIA action menu offered when a driver is already installed — two choices: Reinstall / update driver, or Uninstall the NVIDIA driver completely",
"imageCaption": "The action menu only appears when an NVIDIA driver is currently active on the host.",
"reinstallHeading": "Reinstall / update",
"reinstallBody": "Continues with the normal install flow but, before downloading anything, runs a clean removal of the current driver (apt purge + DKMS entries dropped + leftover modules unloaded). This is the safe path to apply a newer driver version, switch branches when the kernel demands it, or recover from a half-broken state. The LXC propagation and NVENC patch prompts re-run at the end.",
"uninstallHeading": "Uninstall — what gets removed",
"uninstallIntro": "Confirms with a yes/no dialog first. Then performs a full, idempotent rollback:",
"uninstallItems": [
"Stops and disables <code>nvidia-persistenced</code>, unloads the kernel modules (<code>nvidia_uvm</code>, <code>nvidia_drm</code>, <code>nvidia_modeset</code>, <code>nvidia</code>) — any LXC container with NVIDIA passthrough will be cleanly cut off.",
"Runs <code>apt purge</code> on every NVIDIA package, removes the DKMS source tree and the <code>/opt/nvidia</code> .run installer cache.",
"Reverts the nouveau blacklist (<code>/etc/modprobe.d/nouveau-blacklist.conf</code>) and the modules-load config (<code>/etc/modules-load.d/nvidia-vfio.conf</code>) so nouveau can come back if you want generic graphics again.",
"Removes the udev rules (<code>/etc/udev/rules.d/70-nvidia.rules</code>) and the NVENC patch state file (if the keylase patch was applied earlier).",
"Rebuilds <code>initramfs</code> for all kernels and prompts for a reboot to finalise (the nouveau unblacklist only takes effect after restart)."
],
"lxcWarnTitle": "LXC containers with NVIDIA passthrough",
"lxcWarnBody": "Removing the host driver invalidates the device paths and CUDA libraries mapped into any LXC with NVIDIA passthrough. Plan the operation during a maintenance window if Frigate / Plex / Jellyfin / Ollama (or anything else) depends on it."
},
"updates": {
"heading": "Update notifications",
"body": "The installed NVIDIA driver is tracked in ProxMenux's managed-installs registry. On startup and every 24h the Monitor checks the upstream listing at <code>download.nvidia.com/XFree86/Linux-x86_64/</code> against the version <code>nvidia-smi</code> reports, and fires a notification when a newer compatible version is available.",
"kindsHeading": "Two kinds of update message",
"kindsItems": [
"<strong>Same-branch patch.</strong> A newer maintenance release in your current driver branch (e.g. installed 580.65.06 → available 580.105.08). Bug fixes and security patches without changing branch.",
"<strong>Branch upgrade required by kernel.</strong> If the host is on a kernel that no longer supports your current branch (e.g. you upgraded the host kernel to 6.17 while still on driver 570.x), the message says so explicitly and recommends the kernel's minimum compatible branch — same matrix the installer uses to filter the version menu."
],
"antiTitle": "Anti-cascade by design",
"antiBody": "One notification per distinct upstream version, never on every 24h scan. The branch-upgrade message in particular only fires once you actually need to switch — until then the same-branch tracker stays muted.",
"applyTitle": "Applying the update",
"applyBody": "The Monitor doesn't auto-apply driver updates — reinstalling the NVIDIA driver always needs a reboot. Open the same installer entry described above, pick <strong>Reinstall / update</strong>, and the new version is downloaded, the DKMS module rebuilt against the running kernel, and the reboot prompted at the end."
},
"verify": {
"heading": "Verifying the install",
"intro": "Once the host is back up, log in over SSH or the Proxmox shell and run:",
"after": "You should see your GPU listed, the driver version on the top border, and no processes yet (nothing is using the GPU at this point). Then check the persistence service:",
"imageAlt": "Output of nvidia-smi on the host showing the detected GPU and installed driver version"
},
"troubleshoot": {
"heading": "Troubleshooting",
"smiFailTitle": "`nvidia-smi` says 'NVIDIA-SMI has failed'",
"smiFailBody": "Almost always a <strong>nouveau</strong> still loaded or a <strong>kernel header mismatch</strong>. After reboot, run <code>lsmod | grep nouveau</code> — if it returns anything, the blacklist didn't take effect (check <code>/etc/modprobe.d/nouveau-blacklist.conf</code> exists and rebuild initramfs with <code>update-initramfs -u -k all</code>, then reboot). If nouveau is gone, check <code>dmesg | grep -i nvidia</code> — DKMS build errors usually mean your kernel headers don't match the running kernel; reinstall them with <code>apt install --reinstall pve-headers-$(uname -r)</code>.",
"lxcMissTitle": "LXC container can't see the GPU after host update",
"lxcMissBody": "The container's userspace libraries are stuck at the previous driver version. Either re-run the NVIDIA installer and accept the LXC propagation prompt, or install the same driver version manually inside the container with <code>--no-kernel-modules</code>.",
"logTitle": "Check the install log",
"logBody": "Every install writes to <code>/tmp/nvidia_install.log</code>. If something fails silently, that file has the full output (downloads, DKMS build, service installs). Attach it when reporting issues on GitHub."
},
"manualSteps": {
"heading": "Looking for the manual steps?",
"body": "The original community guide — installing everything by hand with <code>wget</code> and <code>./NVIDIA-Linux-...run</code> — is still available as a reference under <guideLink>Guides → NVIDIA</guideLink>. It's useful if you want to understand every command the ProxMenux installer runs, or if you're troubleshooting an unusual setup. For day-to-day installs, use ProxMenux — it's the path that keeps receiving fixes (kernel compatibility, LXC propagation, VFIO safety checks)."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough",
"tail": " — pass the NVIDIA GPU to a VM (different binding model from LXC)."
},
{
"label": "Add GPU to LXC",
"href": "/docs/hardware/igpu-acceleration-lxc",
"tail": " — share the NVIDIA GPU with one or more containers."
},
{
"label": "Switch GPU Mode (VM ↔ LXC)",
"href": "/docs/hardware/switch-gpu-mode",
"tail": " — toggle the same GPU between passthrough (VM) and shared (LXC) modes."
},
{
"label": "ProxMenux Monitor — Hardware tab",
"href": "/docs/monitor/dashboard/hardware",
"tail": " — the GPU modal that triggers this installer in one click, plus live monitoring once it's done."
},
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands",
"tail": " — lspci / dmesg / IOMMU / nvidia-smi reference."
}
]
}
}
@@ -0,0 +1,172 @@
{
"meta": {
"title": "Switch GPU Mode (VM ↔ LXC) | ProxMenux Documentation",
"description": "Move an already-assigned GPU between VM mode (vfio-pci) and LXC mode (native driver) on a Proxmox host. ProxMenux detects the current binding, prompts per-workload conflict policies, handles orphan audio cleanup, and rebuilds initramfs only when needed."
},
"header": {
"title": "Switch GPU Mode (VM ↔ LXC)",
"description": "Reassign a GPU that's already in use — flip it from VM passthrough to LXC sharing or the other way round. ProxMenux handles all the host-side binding changes (vfio.conf, driver blacklist, modules, initramfs) and offers a clean policy for every VM or LXC currently using the GPU, so the switch doesn't leave broken config behind.",
"section": "Hardware: GPUs and Coral-TPU"
},
"intro": {
"title": "What this does",
"body": "A GPU on a Proxmox host lives in one of two modes: bound to <code>vfio-pci</code> (reserved for a VM) or bound to its native driver <em>(i915 / amdgpu / nvidia)</em> so the host + LXCs can share it. <strong>Switch GPU Mode</strong> flips between those two without you having to hand-edit <code>vfio.conf</code>, manage blacklists, or remember which VM / LXC lines point to the card. It also warns you cleanly if a workload still references the GPU so you don't end up with a broken VM at boot."
},
"graphics": {
"lxcTitle": "Ready for LXC containers",
"lxcDesc": "Native driver active",
"vmTitle": "Ready for VM passthrough",
"vmDesc": "VFIO-PCI driver active"
},
"when": {
"heading": "When should I use this?",
"intro": "Use this script when a GPU is <strong>already assigned</strong> and you want to move it:",
"headerSituation": "Situation",
"headerUse": "Use this page?",
"rows": [
{
"situation": "GPU is free — never assigned. Want to give it to a VM.",
"useRich": "No — use <vmLink>Add GPU to VM</vmLink>"
},
{
"situation": "GPU is free — never assigned. Want to give it to an LXC.",
"useRich": "No — use <lxcLink>Add GPU to LXC</lxcLink>"
},
{
"situationRich": "GPU is in a VM via <code>vfio-pci</code>, I want to use it from an LXC instead.",
"useRich": "<strong>Yes — this page.</strong>"
},
{
"situation": "GPU is shared with an LXC, I want to dedicate it to a VM.",
"useRich": "<strong>Yes — this page.</strong>"
},
{
"situation": "I just want to completely unbind a GPU from everything.",
"use": "Yes — pick the LXC-mode target and then detach manually."
}
]
},
"prereqs": {
"title": "Before you start",
"assigned": "<strong>A GPU already assigned</strong> — either in a VM via VFIO or attached to at least one LXC. If you haven't assigned it yet, start from Add GPU to VM / LXC instead.",
"iommu": "<strong>IOMMU enabled on the host</strong> — only strictly required when switching <em>to</em> VM mode, but worth having on either way. The script warns if the kernel param is missing.",
"iommuCheck": "dmesg | grep -i 'IOMMU enabled' | head -1",
"reboot": "<strong>Be OK with a reboot.</strong> Switching GPU bindings at the kernel level means the host regenerates initramfs and you reboot to apply. The script prompts at the end.",
"knowList": "<strong>Know which VMs / LXCs are using the GPU.</strong> The script will find them and ask what to do with each, but it's faster if you already know the list."
},
"blocklist": {
"title": "Not all GPUs are safe to pass to a VM",
"body": "A small blocklist of GPU IDs is refused for VM mode due to known passthrough instability (e.g. Intel Arc A770 <code>8086:5a84</code> / <code>8086:5a85</code>). If the selected GPU matches, the script explains why and exits. Switching <em>to</em> LXC mode is always allowed."
},
"running": {
"heading": "Running the script",
"body": "Open ProxMenux on the host, go to <strong>Hardware: GPUs and Coral-TPU → Switch GPU Mode (VM ↔ LXC)</strong>.",
"imageAlt": "Menu entry for 'Switch GPU Mode (VM ↔ LXC)' inside Hardware: GPUs and Coral-TPU"
},
"howRuns": {
"heading": "How the script runs",
"body": "Two phases as usual: everything is collected and validated first, nothing is applied until you confirm at the end."
},
"walkthrough": {
"heading": "Walking through the flow",
"detect": {
"title": "Detect GPUs and their current binding",
"body": "The script scans every VGA / 3D / Display controller on the host and inspects <code>/sys/bus/pci/devices/*/driver</code> to find the current kernel driver. You'll see each GPU labelled with its name, PCI slot and current driver binding — so you can tell at a glance which mode it's in.",
"imageAlt": "GPU checklist showing each detected GPU with its current driver (vfio-pci / nvidia / amdgpu / i915) and PCI slot"
},
"pickGpu": {
"title": "Pick the GPU(s) to switch",
"body": "Single GPU → auto-selected. Multiple GPUs → checklist. You can tick several, but they must all be in the <em>same</em> current mode — otherwise the script can't pick a target mode for the batch and you get a \"mixed mode\" warning asking you to narrow the selection.",
"tipTitle": "Batching switches",
"tipBody": "Useful when you're rebuilding a host: \"All three NVIDIAs go to VM mode, then the iGPU goes back to LXC.\" Two runs, each with uniform target, much less friction than one-at-a-time."
},
"direction": {
"title": "Review the proposed direction",
"intro": "Based on the current mode, the script proposes the opposite as target:",
"items": [
"<strong>VM → LXC:</strong> unbind from <code>vfio-pci</code>, let the native driver (<code>nvidia</code>, <code>amdgpu</code>, <code>i915</code>) reclaim the card so LXCs can share it. On NVIDIA, the per-BDF entry is removed from <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> so the nvidia module reclaims the GPU after reboot.",
"<strong>LXC → VM:</strong> bind to <code>vfio-pci</code> so the card is free for VFIO passthrough to a single VM. On AMD / Intel this means blacklisting the native driver and setting <code>options vfio-pci ids=…</code>. On NVIDIA the <code>nvidia</code> module is <strong>not</strong> blacklisted — instead a per-BDF udev rule applies <code>driver_override=vfio-pci</code> only to the GPUs you select, so other NVIDIA GPUs on the host keep their <code>nvidia</code> driver."
],
"outro": "Confirm the direction or cancel."
},
"conflict": {
"title": "Conflict policy per affected workload",
"body": "The script scans every <code>/etc/pve/lxc/*.conf</code> and <code>/etc/pve/qemu-server/*.conf</code> looking for references to the GPU's PCI slot. For each affected workload you pick a policy:",
"headerPolicy": "Policy",
"headerEffect": "Effect",
"headerWhen": "When to pick",
"keepPolicy": "Keep config, disable onboot",
"keepEffect": "<code>pct set -onboot 0</code> (or <code>qm set</code>). GPU lines stay in the config.",
"keepWhen": "You plan to come back to this VM/LXC once the GPU is back in its original mode. Safe default.",
"removePolicy": "Remove GPU from config",
"removeEffect": "<code>hostpci</code> / <code>dev</code> lines for this GPU's slot are sed'd out.",
"removeWhen": "The VM/LXC will keep running without the GPU (CPU-only transcoding, etc.). Clean workflow.",
"imageAlt": "Dialog asking per-VM / per-LXC conflict policy when switching a GPU that's currently assigned"
},
"audio": {
"title": "Orphan audio cleanup (only when leaving VM mode)",
"body1": "dGPUs (NVIDIA / AMD) ship with an HDMI audio function at <code>.1</code> of the same slot, and sometimes extra audio controllers are attached alongside the GPU. When the GPU leaves the VM, those audio lines become orphans — the VM has <code>hostpci</code> entries pointing to audio devices that aren't going with the GPU.",
"body2": "The script discovers them (precise BDF match, no substring false-positives) and shows a checklist so you can remove them cleanly. It also cleans their vendor:device IDs from <code>/etc/modprobe.d/vfio.conf</code> — but only if no other VM still uses those audio IDs."
},
"apply": {
"title": "Apply host + workload changes",
"body": "Once you confirm, the script writes the host-side changes — <code>vfio.conf</code>, blacklist, modules, and (for NVIDIA) the per-BDF udev rule at <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> plus the BDF state at <code>/etc/proxmenux/vfio-bind.bdfs</code>. It also applies the chosen conflict policy to each affected VM/LXC. If the host config actually changed, it runs <code>update-initramfs -u -k all</code> — otherwise it skips that step."
},
"reboot": {
"title": "Reboot",
"body": "The new GPU binding only takes effect after a reboot. The script prompts you; you can reboot now or later, but don't start the target VM/LXC until the host has rebooted — otherwise the GPU is still held by the previous driver.",
"imageAlt": "Summary dialog listing what changed, followed by the reboot prompt"
}
},
"manual": {
"heading": "Manual equivalent",
"intro": "If you want to understand exactly what the script does (or troubleshoot one of the steps by hand), these are the raw operations for <strong>VM → LXC</strong> on an NVIDIA card with vendor:device <code>10de:2204</code>:",
"lxcToVm": "And for <strong>LXC → VM</strong>:",
"oneVmTitle": "Only one VM can use a given vfio-pci GPU at a time",
"oneVmBody": "Putting multiple <code>hostpci</code> entries with the same PCI slot in two VMs is valid config but only one of the VMs can start with the GPU — the second one will fail. The ProxMenux conflict policy step is exactly about avoiding this trap."
},
"verification": {
"heading": "Verification after reboot"
},
"troubleshoot": {
"heading": "Troubleshooting",
"stillVfioTitle": "GPU still shows vfio-pci after switching to LXC mode",
"stillVfioBody": "<code>update-initramfs</code> didn't run (or the reboot didn't actually happen). Check <code>lsmod | grep vfio</code> — if vfio-pci is loaded, rerun <code>update-initramfs -u -k all</code> and reboot. For AMD/Intel: verify <code>vfio.conf</code> no longer contains the GPU's vendor:device ID. For NVIDIA: verify the BDF is no longer in <code>/etc/proxmenux/vfio-bind.bdfs</code> and that <code>/etc/udev/rules.d/10-proxmenux-vfio-bind.rules</code> doesn't list it.",
"vmFailTitle": "A VM won't start after switching a GPU to LXC mode",
"vmFailBody": "The VM still has <code>hostpci</code> entries pointing to a GPU it can't claim. Run the script again and pick the <em>Remove GPU from config</em> policy, or clean the config by hand:",
"smiFailTitle": "nvidia-smi fails with 'Driver/library version mismatch' after going back to LXC",
"smiFailBody": "Host NVIDIA modules didn't reload cleanly. <code>modprobe -r nvidia</code> then <code>modprobe nvidia</code>. If that fails, reboot — a full reboot always clears residual state from the vfio binding.",
"logTitle": "Install log",
"logBody": "Every run writes to <code>/tmp/proxmenux_gpu_switch_mode.log</code> on the host. Attach it when asking for help on GitHub."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough",
"tail": " — first-time VM mode setup."
},
{
"label": "Add GPU to LXC",
"href": "/docs/hardware/igpu-acceleration-lxc",
"tail": " — first-time LXC mode setup."
},
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — required for LXC mode on NVIDIA GPUs."
},
{
"label": "ProxMenux Monitor — Hardware tab",
"href": "/docs/monitor/dashboard/hardware",
"tail": " — the Graphics Cards section where each GPU shows its current mode and exposes the inline switch control."
},
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands",
"tail": " — quick command reference."
}
]
}
}
@@ -0,0 +1,235 @@
{
"meta": {
"title": "Proxmox Backup Commands — vzdump, qmrestore, pct restore | ProxMenux",
"description": "Reference of Proxmox VE backup and restore commands: vzdump for VMs and LXC containers, qmrestore for VMs, pct restore for containers, scheduled backups in /etc/pve/jobs.cfg, hook scripts and exclude paths.",
"ogTitle": "Proxmox Backup Commands — vzdump, qmrestore, pct restore",
"ogDescription": "Reference of vzdump, qmrestore and pct restore commands for backing up and restoring Proxmox VMs and LXC containers.",
"twitterTitle": "Proxmox Backup Commands | ProxMenux",
"twitterDescription": "vzdump, qmrestore and pct restore commands for backing up and restoring Proxmox VMs and containers."
},
"header": {
"title": "Backup and Restore",
"description": "Curated reference of vzdump, qmrestore and pct restore commands for Proxmox backup workflows. Includes scheduling, advanced options like hook scripts / exclude paths / I/O priority, and backup file management.",
"section": "Help and Info"
},
"intro": {
"title": "Three backup modes",
"body": "<strong>snapshot</strong> uses a live snapshot — guest stays running, briefly pauses I/O. <strong>suspend</strong> freezes the VM during backup (safer than snapshot for non-snapshot-aware FS). <strong>stop</strong> shuts down the VM, backs up cold, restarts. Pick by guest tolerance and storage capability."
},
"commandGroups": [
{
"title": "VM Backup",
"commands": [
{
"command": "vzdump <vmid>",
"description": "Create a backup of a specific VM/CT"
},
{
"command": "vzdump <vmid> --storage <storage>",
"description": "Backup VM to specific storage"
},
{
"command": "vzdump <vmid> --mode snapshot",
"description": "Create snapshot backup (for VMs)"
},
{
"command": "vzdump <vmid> --mode suspend",
"description": "Suspend VM during backup"
},
{
"command": "vzdump <vmid> --mode stop",
"description": "Stop VM during backup"
},
{
"command": "vzdump --all",
"description": "Backup all VMs and containers"
},
{
"command": "vzdump --exclude <vmid1>,<vmid2>",
"description": "Backup all except specified VMs"
}
]
},
{
"title": "Backup Options",
"commands": [
{
"command": "vzdump <vmid> --compress zstd",
"description": "Use zstd compression for backup"
},
{
"command": "vzdump <vmid> --pigz <threads>",
"description": "Use pigz with multiple threads"
},
{
"command": "vzdump <vmid> --notes <text>",
"description": "Add notes to backup"
},
{
"command": "vzdump <vmid> --mailto <email>",
"description": "Send notification email"
},
{
"command": "vzdump <vmid> --maxfiles <n>",
"description": "Keep only n backups per VM"
},
{
"command": "vzdump <vmid> --stdexcludes 0",
"description": "Don't exclude temporary files"
},
{
"command": "vzdump <vmid> --quiet 1",
"description": "Suppress output messages"
}
]
},
{
"title": "Restore Backups",
"commands": [
{
"command": "qmrestore <backup-file> <vmid>",
"description": "Restore VM from backup"
},
{
"command": "qmrestore <backup-file> <vmid> --storage <storage>",
"description": "Restore to specific storage"
},
{
"command": "qmrestore <backup-file> <vmid> --unique",
"description": "Create a VM with unique ID"
},
{
"command": "pct restore <vmid> <backup-file>",
"description": "Restore container from backup"
},
{
"command": "pct restore <vmid> <backup-file> --storage <storage>",
"description": "Restore container to specific storage"
},
{
"command": "pct restore <vmid> <backup-file> --rootfs <storage>",
"description": "Restore to specific rootfs"
},
{
"command": "pct restore <vmid> <backup-file> --unprivileged 1",
"description": "Restore as unprivileged CT"
}
]
},
{
"title": "Backup Management",
"commands": [
{
"command": "ls -la /var/lib/vz/dump/",
"description": "List backups in default location"
},
{
"command": "find /var/lib/vz/dump/ -name \"*.vma*\"",
"description": "Find VM backups"
},
{
"command": "find /var/lib/vz/dump/ -name \"*.tar*\"",
"description": "Find container backups"
},
{
"command": "pvesm list <storage>",
"description": "List backups in specific storage"
},
{
"command": "rm /var/lib/vz/dump/<backup-file>",
"description": "Delete a backup file"
},
{
"command": "cat /etc/vzdump.conf",
"description": "Show backup configuration"
}
]
},
{
"title": "Scheduled Backups",
"commands": [
{
"command": "cat /etc/cron.d/vzdump",
"description": "Show backup schedule"
},
{
"command": "nano /etc/vzdump.conf",
"description": "Edit backup configuration"
},
{
"command": "systemctl list-timers",
"description": "List all scheduled tasks"
},
{
"command": "systemctl status cron",
"description": "Check cron service status"
},
{
"command": "grep vzdump /var/log/syslog",
"description": "Check backup logs in syslog"
},
{
"command": "tail -f /var/log/vzdump.log",
"description": "Monitor backup log in real-time"
}
]
},
{
"title": "Advanced Operations",
"commands": [
{
"command": "qmrestore <backup> <vmid> --force",
"description": "Force restore, overwriting existing VM"
},
{
"command": "vzdump <vmid> --dumpdir <directory>",
"description": "Specify custom backup directory"
},
{
"command": "vzdump <vmid> --script <script>",
"description": "Run hook script during backup"
},
{
"command": "vzdump <vmid> --exclude-path <path>",
"description": "Exclude specific paths from backup"
},
{
"command": "vzdump <vmid> --ionice <priority>",
"description": "Set I/O priority for backup process"
},
{
"command": "vzdump <vmid> --lockwait <minutes>",
"description": "Wait for lock"
},
{
"command": "qm importdisk <vmid> <backup> <storage>",
"description": "Import disk from backup"
}
]
}
],
"testRestores": {
"title": "Test your restores",
"bodyRich": "A backup you've never restored isn't a backup. Periodically pick a backup, restore it to a test VMID with <code>qmrestore --unique</code>, boot the resulting VM and confirm the contents are intact. Same idea for containers via <code>pct restore</code>."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/help-info/vm-ct-commands",
"label": "VM and CT Management",
"tail": " — qm and pct lifecycle commands."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks",
"tail": " — pvesm storage management."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,162 @@
{
"meta": {
"title": "Proxmox GPU Passthrough Commands — lspci, VFIO, IOMMU, qm set hostpci | ProxMenux",
"description": "Reference for GPU passthrough on Proxmox VE: lspci device identification, VFIO modules, IOMMU groups (intel_iommu / amd_iommu), GRUB and initramfs updates, qm set hostpci0, NVIDIA / AMD / Intel passthrough setup.",
"ogTitle": "Proxmox GPU Passthrough Commands — lspci, VFIO, IOMMU, qm set hostpci",
"ogDescription": "Reference for inspecting and configuring GPU passthrough on Proxmox VE — PCI devices, VFIO modules, IOMMU groups, kernel boot params, qm set hostpci.",
"twitterTitle": "Proxmox GPU Passthrough Commands | ProxMenux",
"twitterDescription": "Inspect PCI devices, configure VFIO and IOMMU, and attach GPUs to VMs on Proxmox VE."
},
"header": {
"title": "GPU Passthrough",
"description": "Reference for inspecting and configuring GPU / TPU passthrough on Proxmox: device identification (lspci), VFIO module setup, IOMMU validation, initramfs / GRUB updates and per-VM passthrough config (qm set hostpci, machine q35, bios ovmf).",
"section": "Help and Info"
},
"intro": {
"title": "IOMMU must be enabled in BIOS / UEFI",
"body": "Before any of these commands matter, IOMMU has to be enabled at the firmware level (look for <em>VT-d</em>, <em>AMD-Vi</em> or <em>IOMMU</em> in BIOS / UEFI). Common GRUB parameters to enable it on the Linux side: <code>intel_iommu=on</code> (Intel) or <code>amd_iommu=on</code> (AMD), often combined with <code>iommu=pt video=efifb:off video=vesa:off</code>."
},
"commandGroups": [
{
"title": "Device Identification",
"commands": [
{
"command": "lspci -nn | grep -i nvidia",
"description": "List NVIDIA PCI devices"
},
{
"command": "lspci -nn | grep -i vga",
"description": "List all VGA compatible devices"
},
{
"command": "lspci -nn | grep -i amd",
"description": "List AMD PCI devices"
},
{
"command": "lspci -nnk | grep -A3 VGA",
"description": "List VGA devices with kernel drivers"
},
{
"command": "lspci -v -s <PCI_ID>",
"description": "Show detailed info for specific PCI device"
}
]
},
{
"title": "VFIO Configuration",
"commands": [
{
"command": "dmesg | grep -i vfio",
"description": "Check VFIO module messages"
},
{
"command": "cat /etc/modprobe.d/vfio.conf",
"description": "Review VFIO passthrough configuration"
},
{
"command": "ls -la /etc/modprobe.d/",
"description": "List all modprobe configuration files"
},
{
"command": "cat /etc/modules",
"description": "Show modules loaded at boot time"
},
{
"command": "lsmod | grep vfio",
"description": "Check if VFIO modules are loaded"
}
]
},
{
"title": "IOMMU Configuration",
"commands": [
{
"command": "cat /etc/default/grub",
"description": "Review GRUB options for IOMMU"
},
{
"command": "update-grub",
"description": "Apply GRUB changes"
},
{
"command": "dmesg | grep -i iommu",
"description": "Check IOMMU messages in kernel log"
},
{
"command": "dmesg | grep -e DMAR -e IOMMU",
"description": "Check DMAR and IOMMU messages"
},
{
"command": "find /sys/kernel/iommu_groups/ -type l | sort -V",
"description": "List IOMMU groups"
}
]
},
{
"title": "System Updates",
"commands": [
{
"command": "update-initramfs -u",
"description": "Apply initramfs changes (VFIO)"
},
{
"command": "update-initramfs -u -k all",
"description": "Update initramfs for all kernels"
},
{
"command": "cat /proc/cmdline",
"description": "Show current kernel boot parameters"
}
]
},
{
"title": "VM Configuration",
"commands": [
{
"command": "qm config <vmid> | grep hostpci",
"description": "Show PCI passthrough config for a VM"
},
{
"command": "qm set <vmid> -hostpci0 <PCI_ID>,pcie=1,x-vga=1",
"description": "Add GPU passthrough to a VM"
},
{
"command": "cat /etc/pve/qemu-server/<vmid>.conf",
"description": "View VM configuration file"
},
{
"command": "qm set <vmid> -machine q35",
"description": "Set VM to use Q35 chipset (recommended for passthrough)"
},
{
"command": "qm set <vmid> -bios ovmf",
"description": "Set VM to use UEFI/OVMF (required for GPU passthrough)"
}
]
}
],
"afterChangesTip": {
"title": "After changing GRUB or modprobe configs",
"bodyRich": "Run <code>update-grub</code> + <code>update-initramfs -u</code>, then reboot. Verify with <code>cat /proc/cmdline</code> (kernel parameters), <code>dmesg | grep -i iommu</code> (IOMMU initialised) and <code>find /sys/kernel/iommu_groups/ -type l | sort -V</code> (groups present)."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/hardware/gpu-vm-passthrough",
"label": "Add GPU to VM (Passthrough)",
"tail": " — interactive ProxMenux flow."
},
{
"href": "/docs/hardware/igpu-acceleration-lxc",
"label": "Add GPU to LXC",
"tail": " — passthrough to a container instead of a VM."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
+87
View File
@@ -0,0 +1,87 @@
{
"meta": {
"title": "Proxmox Commands Reference — qm, pct, vzdump, zpool, pveversion | ProxMenux",
"description": "Curated reference of essential Proxmox VE and Linux commands organised by topic: system inspection, VM and LXC management (qm / pct), storage and disks, networking, updates, GPU passthrough, ZFS, backup and restore, and day-to-day CLI tools.",
"ogTitle": "Proxmox Commands Reference — qm, pct, vzdump, zpool",
"ogDescription": "Curated reference of the most useful Proxmox VE and Linux commands, grouped by topic — system, VM/CT, storage, network, updates, GPU passthrough, ZFS, backup and CLI tools.",
"twitterTitle": "Proxmox Commands Reference | ProxMenux",
"twitterDescription": "Curated reference of the most useful Proxmox VE and Linux commands, grouped by topic."
},
"header": {
"title": "Help and Info",
"description": "Curated compendium of useful Linux and Proxmox VE commands organised by topic. Nine categories — covers everything from a quick pveversion check to a multi-line zfs send/receive — meant to live alongside the GPU, disk and share sections of ProxMenux as a one-stop reference.",
"section": "Help and Info"
},
"intro": {
"title": "What this is",
"body": "A reference catalog of the commands you actually use on a Proxmox host, grouped by topic. Inside ProxMenux you can pick a number to run a command directly or paste your own at the prompt; on this site each category is a copy-paste table."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, press <kbd>h</kbd>. You will see this:",
"imageAlt": "Help and Info menu with 9 categories of commands"
},
"categories": {
"heading": "The nine categories",
"options": [
{
"icon": "Terminal",
"href": "/docs/help-info/system-commands",
"title": "Useful System Commands",
"description": "pveversion, uptime, free, journalctl, hostnamectl, current-user info, lynis audit, fastfetch."
},
{
"icon": "Cpu",
"href": "/docs/help-info/vm-ct-commands",
"title": "VM and CT Management",
"description": "qm list / config / start / stop / migrate, pct list / config / enter, snapshots, cloning."
},
{
"icon": "HardDrive",
"href": "/docs/help-info/storage-commands",
"title": "Storage and Disks",
"description": "lsblk, blkid, smartctl, mount info, pvesm status, LVM commands."
},
{
"icon": "Network",
"href": "/docs/help-info/network-commands",
"title": "Network Commands",
"description": "ip / ss / nmcli, bridge inspection, ping / traceroute, DNS lookups, fail2ban-client."
},
{
"icon": "Package",
"href": "/docs/help-info/update-commands",
"title": "Updates and Packages",
"description": "apt update / dist-upgrade, apt-cache policy, dpkg queries, repo file checks."
},
{
"icon": "Cpu",
"href": "/docs/help-info/gpu-commands",
"title": "GPU Passthrough",
"description": "lspci / dmesg checks, IOMMU enablement verification, vfio-pci binding, GPU usage from the host."
},
{
"icon": "Database",
"href": "/docs/help-info/zfs-commands",
"title": "ZFS Management",
"description": "zpool / zfs commands for status, datasets, snapshots, send/receive, ARC tuning, trimming."
},
{
"icon": "Archive",
"href": "/docs/help-info/backup-commands",
"title": "Backup and Restore",
"description": "vzdump, qmrestore / pct restore, Proxmox Backup Server helpers, snapshot operations."
},
{
"icon": "Wrench",
"href": "/docs/help-info/tools-commands",
"title": "System CLI Tools",
"description": "tmux, screen, htop / btop, ncdu, jq, dig, lsof, watch — daily-driver admin tools."
}
]
},
"tip": {
"title": "Searchable from the global search",
"body": "Every command in these pages is indexed by the documentation search. If you remember a flag or fragment but not which page it's on, hit the search bar at the top — you'll land directly on the right entry."
}
}
@@ -0,0 +1,174 @@
{
"meta": {
"title": "Proxmox Network Commands — ip, ping, ss, pve-firewall, iptables | ProxMenux",
"description": "Reference of Proxmox VE host networking commands: ip / ip link / ip addr, ping, traceroute, mtr, ss, ethtool, dig, nslookup, plus pve-firewall, iptables and nftables for filtering. Bridge, bond and VLAN inspection.",
"ogTitle": "Proxmox Network Commands — ip, ping, ss, pve-firewall, iptables",
"ogDescription": "Reference of network commands for Proxmox VE — interface inspection, connectivity tests, monitoring, firewall (pve-firewall, iptables, nftables) and DNS lookups.",
"twitterTitle": "Proxmox Network Commands | ProxMenux",
"twitterDescription": "Network inspection, testing, configuration and firewall commands for Proxmox VE."
},
"header": {
"title": "Network Commands",
"description": "Curated reference for Proxmox host networking: interface info, connectivity tests, configuration, traffic monitoring and firewall management. Combines ip / ss / nmcli / ethtool / tcpdump / pve-firewall.",
"section": "Help and Info"
},
"intro": {
"title": "Quick interface inventory",
"body": "<code>ip a</code> shows every interface with its IPs and MAC. <code>ip r</code> shows the routing table. Together they answer most \"is this interface configured correctly?\" questions in seconds."
},
"commandGroups": [
{
"title": "Network Information",
"commands": [
{
"command": "ip a",
"description": "Show network interfaces and IPs"
},
{
"command": "ip r",
"description": "Show routing table"
},
{
"command": "ip -s link",
"description": "Show traffic statistics per interface"
},
{
"command": "brctl show",
"description": "Show configured network bridges"
},
{
"command": "cat /etc/network/interfaces",
"description": "Show raw network configuration"
}
]
},
{
"title": "Network Testing",
"commands": [
{
"command": "ping <host>",
"description": "Check connectivity with another host"
},
{
"command": "traceroute <host>",
"description": "Trace route to a host"
},
{
"command": "mtr <host>",
"description": "Combine ping and traceroute in real-time"
},
{
"command": "dig <domain>",
"description": "DNS lookup for a domain"
},
{
"command": "nslookup <domain>",
"description": "Alternative DNS lookup"
}
]
},
{
"title": "Network Configuration",
"commands": [
{
"command": "ifreload -a",
"description": "Reload network configuration (ifupdown2)"
},
{
"command": "ethtool <iface>",
"description": "Show Ethernet device info"
},
{
"command": "resolvectl status",
"description": "Show DNS resolution status"
},
{
"command": "nmcli device show",
"description": "Show network device details (if NetworkManager is used)"
},
{
"command": "ip link set <iface> up",
"description": "Bring network interface up"
},
{
"command": "ip link set <iface> down",
"description": "Bring network interface down"
}
]
},
{
"title": "Network Monitoring",
"commands": [
{
"command": "ss -tuln",
"description": "Show listening ports (TCP/UDP)"
},
{
"command": "netstat -tuln",
"description": "Alternative to show listening ports"
},
{
"command": "lsof -i",
"description": "List open network files and connections"
},
{
"command": "tcpdump -i <iface>",
"description": "Capture packets on interface"
},
{
"command": "iftop -i <iface>",
"description": "Monitor bandwidth usage on interface"
}
]
},
{
"title": "Firewall Management",
"commands": [
{
"command": "iptables -L -n -v",
"description": "Show active firewall rules (iptables)"
},
{
"command": "nft list ruleset",
"description": "Show nftables rules"
},
{
"command": "pve-firewall status",
"description": "Check Proxmox firewall status"
},
{
"command": "pve-firewall compile",
"description": "Compile firewall rules for all nodes"
},
{
"command": "pve-firewall reload",
"description": "Reload Proxmox firewall rules"
}
]
}
],
"iptablesTip": {
"title": "iptables vs nftables",
"bodyRich": "Modern Debian / Proxmox uses <strong>nftables</strong> as the underlying firewall engine. The classic <code>iptables -L -n -v</code> command still works as a translation layer, but the source of truth is <code>nft list ruleset</code>. <code>pve-firewall</code> commands are Proxmox's wrapper that emits nftables rules from the cluster firewall config."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/network",
"label": "Network Management",
"tail": " — ProxMenux interactive network tools (bridge analysis, persistent names, monitoring)."
},
{
"href": "/docs/help-info/tools-commands",
"label": "System CLI Tools",
"tail": " — more network monitoring tools."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,232 @@
{
"meta": {
"title": "Proxmox Storage and Disk Commands — lsblk, LVM, pvesm, qm importdisk | ProxMenux",
"description": "Reference of storage and disk commands on Proxmox VE: lsblk, blkid, parted, lvdisplay, vgdisplay, pvs, mount, df, du, ncdu, pvesm status, qm importdisk and qemu-img convert for VM disk operations.",
"ogTitle": "Proxmox Storage and Disk Commands — lsblk, LVM, pvesm, qm importdisk",
"ogDescription": "Reference of storage and disk commands on Proxmox VE — disk inspection, LVM, mounts, Proxmox storage management, VM disk import and image conversion.",
"twitterTitle": "Proxmox Storage Commands | ProxMenux",
"twitterDescription": "Disk inspection, mount info, LVM management, Proxmox storage and VM disk import / conversion commands."
},
"header": {
"title": "Storage and Disks",
"description": "Curated reference for storage inspection on Proxmox hosts: block devices, partitions, mounts, LVM volumes, Proxmox storage configuration, and a few VM disk operations (importdisk, qemu-img convert).",
"section": "Help and Info"
},
"intro": {
"title": "Quick disk inventory",
"body": "<code>lsblk</code> is the fastest way to see all block devices and their partitions in a tree view. For persistent identifiers (which survive between boots and hardware changes) use <code>ls -lh /dev/disk/by-id/</code>."
},
"commandGroups": [
{
"title": "Disk Information",
"commands": [
{
"command": "lsblk",
"description": "List block devices and partitions"
},
{
"command": "fdisk -l",
"description": "List disks with detailed info"
},
{
"command": "blkid",
"description": "Show UUID and filesystem type of block devices"
},
{
"command": "ls -lh /dev/disk/by-id/",
"description": "List disk persistent identifiers"
},
{
"command": "parted -l",
"description": "Detailed partition layout with GPT info"
}
]
},
{
"title": "Storage Usage",
"commands": [
{
"command": "df -h",
"description": "Show disk usage by mount point"
},
{
"command": "du -sh /path",
"description": "Show size of a directory"
},
{
"command": "mount | grep ^/dev",
"description": "Show mounted storage devices"
},
{
"command": "cat /proc/mounts",
"description": "Show all active mounts from the kernel"
}
]
},
{
"title": "LVM Management",
"commands": [
{
"command": "pvdisplay",
"description": "Display physical volumes (LVM)"
},
{
"command": "vgdisplay",
"description": "Display volume groups (LVM)"
},
{
"command": "lvdisplay",
"description": "Display logical volumes (LVM)"
},
{
"command": "pvs",
"description": "Concise output of physical volumes"
},
{
"command": "vgs",
"description": "Concise output of volume groups"
},
{
"command": "lvs",
"description": "Concise output of logical volumes"
}
]
},
{
"title": "Proxmox Storage",
"commands": [
{
"command": "cat /etc/pve/storage.cfg",
"description": "Show Proxmox storage configuration"
},
{
"command": "pvesm status",
"description": "Show status of all storage pools"
},
{
"command": "pvesm list",
"description": "List all available storage"
},
{
"command": "pvesm list <storage>",
"description": "List content of specific storage"
},
{
"command": "pvesm scan <storage>",
"description": "Scan storage for new content"
}
]
},
{
"title": "Disk Actions",
"commands": [
{
"command": "qm importdisk <vmid> <image_path> <storage>",
"description": "Attach disk image to VM"
},
{
"command": "qm set <vmid> -<bus><index> <disk_path>",
"description": "Assign physical disk to VM (passthrough mode)"
},
{
"command": "qemu-img convert -O <format> <input> <output>",
"description": "Convert disk image format"
}
]
},
{
"title": "SMART Disk Health",
"commands": [
{
"command": "smartctl --scan",
"description": "List SMART-capable devices on the host"
},
{
"command": "smartctl -i /dev/<disk>",
"description": "Basic device info (model, firmware, serial)"
},
{
"command": "smartctl -H /dev/<disk>",
"description": "Quick health check — overall PASSED / FAILED"
},
{
"command": "smartctl -A /dev/<disk>",
"description": "SMART attributes only (raw values, thresholds)"
},
{
"command": "smartctl -a /dev/<disk>",
"description": "Full SMART info — info + attributes + self-test log"
},
{
"command": "smartctl -t short /dev/<disk>",
"description": "Start short self-test (~2 minutes, runs in background)"
},
{
"command": "smartctl -t long /dev/<disk>",
"description": "Start long self-test (hours, runs in background)"
},
{
"command": "smartctl -l selftest /dev/<disk>",
"description": "View self-test log (results of past tests)"
},
{
"command": "smartctl -X /dev/<disk>",
"description": "Abort the running self-test"
}
]
},
{
"title": "NVMe Disk Health",
"commands": [
{
"command": "nvme list",
"description": "List NVMe devices visible to the kernel"
},
{
"command": "nvme smart-log /dev/<nvme>",
"description": "NVMe-specific SMART log (temperature, wear, errors)"
},
{
"command": "nvme id-ctrl /dev/<nvme>",
"description": "Controller info (model, firmware, capabilities)"
},
{
"command": "nvme error-log /dev/<nvme>",
"description": "Recent NVMe error log entries"
}
]
}
],
"lvmTip": {
"title": "LVM short vs long commands",
"bodyRich": "Both forms exist for compatibility. <code>pvs</code> / <code>vgs</code> / <code>lvs</code> give a clean single-line-per-volume table; <code>pvdisplay</code> / <code>vgdisplay</code> / <code>lvdisplay</code> give a verbose multi-line dump per volume. For day-to-day use prefer the short versions."
},
"smartInfo": {
"title": "SMART for spinning disks vs NVMe",
"bodyRich": "<strong>Spinning / SATA / SAS disks</strong> use the <code>smartctl</code> family from <code>smartmontools</code> (installed by default on Proxmox). Pass the device as <code>/dev/sda</code>, <code>/dev/sdb</code>, etc. <strong>NVMe disks</strong> have their own native protocol — <code>smartctl</code> works against them (passes most data through), but the <code>nvme</code> tool from <code>nvme-cli</code> reports more NVMe-specific fields (wear levelling, media errors, namespace info). Install with <code>apt install nvme-cli</code> if not present."
},
"selfTestWarn": {
"title": "Self-tests run in the background",
"bodyRich": "<code>smartctl -t short</code> and <code>-t long</code> return immediately — the disk runs the test on its own. Check progress with <code>smartctl -a /dev/&lt;disk&gt;</code> (look for the \"Self-test routine in progress\" line) or wait for completion and read <code>smartctl -l selftest /dev/&lt;disk&gt;</code>. Short tests take ~2 min; long tests can take hours on large spinners. The disk stays usable during the test, but I/O performance drops."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/help-info/zfs-commands",
"label": "ZFS Management",
"tail": " — zpool / zfs commands for ZFS-backed storage."
},
{
"href": "/docs/disk-manager",
"label": "Disk Manager",
"tail": " — interactive ProxMenux flows for disk passthrough, import, formatting, SMART."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,158 @@
{
"meta": {
"title": "Proxmox VE System Commands — pveversion, uptime, journalctl, systemctl | ProxMenux",
"description": "Reference of essential Proxmox VE and Linux system commands: pveversion, pveperf, uptime, journalctl, systemctl, lscpu, lsblk, df, free, last, who. All read-only and safe to run on any host.",
"ogTitle": "Proxmox VE System Commands — pveversion, uptime, journalctl, systemctl",
"ogDescription": "Reference of essential Proxmox VE and Linux system commands — version, uptime, services, logs, user info, hardware probes. All read-only.",
"twitterTitle": "Proxmox VE System Commands | ProxMenux",
"twitterDescription": "Essential system inspection commands for Proxmox VE — version, status, services, logs, user info."
},
"header": {
"title": "Useful System Commands",
"description": "Read-only commands to look at the Proxmox host: version, kernel, uptime, memory, web UI status, recent log lines, who's logged in, and a couple of audit / summary tools. None of them modifies the system.",
"section": "Help and Info"
},
"intro": {
"title": "What this is",
"body": "The same numbered list ProxMenux shows when you choose <em>Useful System Commands</em>. Use the Copy button to grab any command, or look it up to remember the exact flag."
},
"commandGroups": [
{
"title": "System Information",
"commands": [
{
"command": "pveversion",
"description": "Show Proxmox version"
},
{
"command": "pveversion -v",
"description": "Detailed Proxmox version info"
},
{
"command": "hostnamectl",
"description": "System hostname and kernel info"
},
{
"command": "uname -a",
"description": "Kernel and architecture info"
},
{
"command": "cat /etc/os-release",
"description": "OS release details"
}
]
},
{
"title": "System Status",
"commands": [
{
"command": "uptime",
"description": "System uptime"
},
{
"command": "uptime -p",
"description": "Pretty uptime format"
},
{
"command": "free -h",
"description": "RAM and swap usage"
},
{
"command": "who -b",
"description": "Last system boot time"
},
{
"command": "last -x | grep shutdown",
"description": "Previous shutdowns"
}
]
},
{
"title": "Service Management",
"commands": [
{
"command": "systemctl status pveproxy",
"description": "Check Proxmox Web UI status"
},
{
"command": "systemctl restart pveproxy",
"description": "Restart Web UI proxy"
},
{
"command": "journalctl -xe",
"description": "System errors and logs"
},
{
"command": "dmesg -T | tail -n 50",
"description": "Last 50 kernel log lines"
}
]
},
{
"title": "User Information",
"commands": [
{
"command": "whoami",
"description": "Current user"
},
{
"command": "id",
"description": "Current user UID, GID and groups"
},
{
"command": "who",
"description": "Logged-in users"
},
{
"command": "w",
"description": "User activity and uptime"
},
{
"command": "uptime && w",
"description": "Uptime and who is logged in"
},
{
"command": "cut -d: -f1,3,4 /etc/passwd",
"description": "All users with UID and GID"
},
{
"command": "getent passwd | column -t -s :",
"description": "Readable user table (UID, shell, etc.)"
}
]
},
{
"title": "Auditing & Summary Tools",
"commands": [
{
"command": "lynis audit system",
"description": "Run a full system security audit"
},
{
"command": "fastfetch",
"description": "Display system summary in ASCII format"
}
]
}
],
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/help-info/update-commands",
"label": "Updates and Packages",
"tail": " — apt and pve upgrade commands."
},
{
"href": "/docs/help-info/tools-commands",
"label": "System CLI Tools",
"tail": " — htop, btop, ncdu and friends."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,276 @@
{
"meta": {
"title": "Linux CLI Tools for Proxmox — htop, iftop, journalctl, rsync, tmux | ProxMenux",
"description": "Day-to-day Linux CLI tools for Proxmox VE administration: monitoring (htop, atop, glances, iotop), network (iftop, nmap, mtr, ss), file & text (find, grep, journalctl), performance (iostat, perf, strace), security (fail2ban, lynis, lsof) and remote admin (ssh, rsync, tmux).",
"ogTitle": "Linux CLI Tools for Proxmox — htop, iftop, journalctl, rsync, tmux",
"ogDescription": "Day-to-day CLI tools for Proxmox VE administration grouped by purpose: monitoring, network, file/text, performance, security and remote admin.",
"twitterTitle": "Linux CLI Tools for Proxmox | ProxMenux",
"twitterDescription": "Daily-driver CLI tools for Proxmox VE administration grouped by purpose."
},
"header": {
"title": "System CLI Tools",
"description": "Daily-driver CLI tools for Proxmox host administration, grouped by purpose: monitoring, network, file & text, performance analysis, security, remote admin and system configuration.",
"section": "Help and Info"
},
"intro": {
"title": "Most are installed by Post-Install",
"body": "If you ran the ProxMenux Post-Install script with the default selections, the majority of these tools are already installed. For anything missing, ProxMenux's <utilsLink>System Utilities Installer</utilsLink> offers them as predefined groups (basic, dev, network, analysis, …)."
},
"commandGroups": [
{
"title": "System Monitoring",
"commands": [
{
"command": "htop",
"description": "Interactive process viewer with CPU/memory usage"
},
{
"command": "top",
"description": "Display Linux processes in real-time"
},
{
"command": "atop",
"description": "Advanced system & process monitor"
},
{
"command": "glances",
"description": "System monitoring tool with web interface"
},
{
"command": "nmon",
"description": "Performance monitoring tool"
},
{
"command": "iotop",
"description": "Monitor disk I/O usage by processes"
},
{
"command": "vmstat 1",
"description": "Report virtual memory statistics every second"
}
]
},
{
"title": "Network Tools",
"commands": [
{
"command": "iftop",
"description": "Display bandwidth usage on an interface"
},
{
"command": "nmap <host>",
"description": "Network exploration and security scanning"
},
{
"command": "tcpdump -i <interface>",
"description": "Dump network traffic"
},
{
"command": "netstat -tuln",
"description": "Display network connections"
},
{
"command": "ss -tuln",
"description": "Another utility to investigate sockets"
},
{
"command": "mtr <host>",
"description": "Network diagnostic tool combining ping and traceroute"
},
{
"command": "iperf3 -s",
"description": "Run iperf server for bandwidth testing"
}
]
},
{
"title": "File and Text Tools",
"commands": [
{
"command": "find / -name <filename>",
"description": "Find files by name"
},
{
"command": "grep -r 'pattern' /path",
"description": "Search for pattern in files"
},
{
"command": "sed -i 's/old/new/g' file",
"description": "Replace text in files"
},
{
"command": "awk '{print $1}' file",
"description": "Text processing tool"
},
{
"command": "tail -f /var/log/syslog",
"description": "Follow log file in real-time"
},
{
"command": "less /var/log/messages",
"description": "View file with pagination"
},
{
"command": "journalctl -f",
"description": "Follow systemd journal logs"
}
]
},
{
"title": "Performance Analysis",
"commands": [
{
"command": "iostat -x 1",
"description": "Report CPU and I/O statistics"
},
{
"command": "mpstat -P ALL 1",
"description": "Report CPU utilization"
},
{
"command": "perf top",
"description": "System profiling tool"
},
{
"command": "strace <command>",
"description": "Trace system calls and signals"
},
{
"command": "lsof",
"description": "List open files"
},
{
"command": "pstree",
"description": "Display process tree"
},
{
"command": "slabtop",
"description": "Display kernel slab cache information"
}
]
},
{
"title": "Security Tools",
"commands": [
{
"command": "fail2ban-client status",
"description": "Show fail2ban status"
},
{
"command": "chage -l <username>",
"description": "Show password expiry information"
},
{
"command": "lastlog",
"description": "Show last login of all users"
},
{
"command": "last",
"description": "Show listing of last logged in users"
},
{
"command": "w",
"description": "Show who is logged on and what they are doing"
},
{
"command": "lynis audit system",
"description": "Security auditing tool"
},
{
"command": "openssl s_client -connect host:port",
"description": "Test SSL/TLS connections"
}
]
},
{
"title": "Remote Administration",
"commands": [
{
"command": "ssh <user>@<host>",
"description": "Secure shell connection"
},
{
"command": "scp <file> <user>@<host>:<path>",
"description": "Secure copy files"
},
{
"command": "rsync -avz <src> <dest>",
"description": "Synchronize files/folders"
},
{
"command": "screen",
"description": "Terminal multiplexer"
},
{
"command": "tmux",
"description": "Terminal multiplexer alternative"
},
{
"command": "ssh-keygen -t rsa -b 4096",
"description": "Generate SSH key pair"
},
{
"command": "ssh-copy-id <user>@<host>",
"description": "Copy SSH key to server"
}
]
},
{
"title": "System Configuration",
"commands": [
{
"command": "systemctl status <service>",
"description": "Check service status"
},
{
"command": "journalctl -u <service>",
"description": "View service logs"
},
{
"command": "timedatectl",
"description": "Control system time and date"
},
{
"command": "hostnamectl",
"description": "Control system hostname"
},
{
"command": "localectl",
"description": "Control system locale and keyboard"
},
{
"command": "update-alternatives --config <name>",
"description": "Configure system alternatives"
},
{
"command": "dpkg-reconfigure <package>",
"description": "Reconfigure an installed package"
}
]
}
],
"tmuxTip": {
"title": "Use tmux / screen for long-running commands",
"bodyRich": "Anything that takes longer than a coffee break — a backup, a long upgrade, a big rsync — should run inside <code>tmux</code> or <code>screen</code>. SSH disconnects don't kill the session, and you can re-attach from anywhere with <code>tmux attach</code>."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/utils/system-utils",
"label": "System Utilities Installer",
"tail": " — install any of these tools that are missing."
},
{
"href": "/docs/help-info/system-commands",
"label": "Useful System Commands",
"tail": " — Proxmox-specific inspection commands."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,170 @@
{
"meta": {
"title": "Proxmox Update and Package Commands — apt, pveupgrade, dpkg | ProxMenux",
"description": "Reference of update and package commands for Proxmox VE: apt update, apt upgrade, apt dist-upgrade, pveupgrade, dpkg -l, package information lookups, repository configuration in /etc/apt/sources.list.d/.",
"ogTitle": "Proxmox Update and Package Commands — apt, pveupgrade, dpkg",
"ogDescription": "apt, pveupgrade and dpkg commands for keeping Proxmox VE up to date — system upgrades, package management, repository configuration.",
"twitterTitle": "Proxmox Update Commands | ProxMenux",
"twitterDescription": "apt and pveupgrade commands for managing updates and packages on Proxmox VE hosts."
},
"header": {
"title": "Updates and Packages",
"description": "Curated reference of apt and Proxmox-specific upgrade commands: system updates, package install / remove / purge, package lookups (apt-cache policy, dpkg -l), and repository configuration inspection.",
"section": "Help and Info"
},
"intro": {
"title": "Always update the index first",
"body": "<code>apt update</code> refreshes the local package index from the configured repositories. Without it, <code>apt install</code> may pull stale versions or fail with \"Unable to locate package\"."
},
"commandGroups": [
{
"title": "System Updates",
"commands": [
{
"command": "apt update && apt upgrade -y",
"description": "Update and upgrade all system packages"
},
{
"command": "apt dist-upgrade -y",
"description": "Full system upgrade, including dependencies"
},
{
"command": "apt update",
"description": "Update package lists only"
},
{
"command": "apt upgrade",
"description": "Upgrade packages only (interactive)"
},
{
"command": "apt full-upgrade",
"description": "Upgrade packages with dependency handling (interactive)"
}
]
},
{
"title": "Proxmox Updates",
"commands": [
{
"command": "pveupdate",
"description": "Update Proxmox package lists"
},
{
"command": "pveupgrade",
"description": "Show available Proxmox upgrades"
},
{
"command": "pve-upgrade",
"description": "Perform Proxmox VE upgrade"
},
{
"command": "pveceph upgrade",
"description": "Upgrade Ceph packages (if Ceph is installed)"
}
]
},
{
"title": "Package Management",
"commands": [
{
"command": "apt autoremove --purge",
"description": "Remove unused packages and their config"
},
{
"command": "apt clean",
"description": "Clear out the local repository of retrieved package files"
},
{
"command": "apt autoclean",
"description": "Clear out only outdated package files"
},
{
"command": "apt install <package>",
"description": "Install a specific package"
},
{
"command": "apt remove <package>",
"description": "Remove a package"
},
{
"command": "apt purge <package>",
"description": "Remove a package and its configuration files"
}
]
},
{
"title": "Package Information",
"commands": [
{
"command": "apt list --installed",
"description": "List all installed packages"
},
{
"command": "apt search <keyword>",
"description": "Search for packages by keyword"
},
{
"command": "apt show <package>",
"description": "Show detailed information about a package"
},
{
"command": "dpkg -l",
"description": "List all installed packages (alternative)"
},
{
"command": "dpkg -l | grep <keyword>",
"description": "Search installed packages by keyword"
},
{
"command": "apt-cache policy <package>",
"description": "Show package versions and priorities"
}
]
},
{
"title": "Repository Management",
"commands": [
{
"command": "cat /etc/apt/sources.list",
"description": "Show main APT repository sources"
},
{
"command": "ls -la /etc/apt/sources.list.d/",
"description": "List additional repository source files"
},
{
"command": "cat /etc/apt/sources.list.d/pve-enterprise.list",
"description": "Show Proxmox Enterprise repo config"
},
{
"command": "apt-key list",
"description": "List repository signing keys"
}
]
}
],
"backupWarn": {
"title": "Take a backup before major upgrades",
"bodyRich": "For point releases (8.4.1 → 8.4.5) the standard <code>apt update &amp;&amp; apt upgrade</code> is safe. For <strong>major version upgrades</strong> (PVE 8 → 9) use the dedicated ProxMenux flow: <upgradeLink>Upgrade PVE 8 to PVE 9</upgradeLink> — it adds pre-flight checks, repository migration and post-upgrade validation."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/utils/system-update",
"label": "Proxmox System Update (interactive)",
"tail": " — wrapper that does all of this with a confirmation dialog and reboot prompt."
},
{
"href": "/docs/utils/upgrade-pve8-pve9",
"label": "Upgrade PVE 8 to PVE 9",
"tail": " — for major-version upgrades."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,182 @@
{
"meta": {
"title": "Proxmox qm and pct Commands — VM and LXC Container Management | ProxMenux",
"description": "Reference of Proxmox VE qm and pct commands for VMs and LXC containers: list, config, start, stop, shutdown, reboot, destroy, clone, migrate, snapshot, resize, plus pct exec / enter / push / pull for containers.",
"ogTitle": "Proxmox qm and pct Commands — VM and LXC Container Management",
"ogDescription": "Reference of Proxmox VE qm and pct commands — manage virtual machines and LXC containers from the CLI: start, stop, configure, snapshot, migrate, clone, destroy.",
"twitterTitle": "Proxmox qm / pct Commands | ProxMenux",
"twitterDescription": "Curated qm / pct commands for managing virtual machines and LXC containers in Proxmox VE."
},
"header": {
"title": "VM and CT Management",
"description": "Curated reference for the qm (VMs) and pct (LXC containers) commands. Listing, lifecycle (start / stop / shutdown / destroy), config inspection, and container-specific operations like exec, enter, push and pull.",
"section": "Help and Info"
},
"intro": {
"title": "Find a VMID or CTID first",
"body": "Almost every command needs a numeric ID. Use <code>qm list</code> for VMs and <code>pct list</code> for containers. Replace <code>&lt;vmid&gt;</code> / <code>&lt;ctid&gt;</code> in the snippets with the actual ID before running."
},
"commandGroups": [
{
"title": "Listing and Information",
"commands": [
{
"command": "qm list",
"description": "List all virtual machines"
},
{
"command": "pct list",
"description": "List all LXC containers"
},
{
"command": "qm config <vmid>",
"description": "Show VM configuration (parsed by qm)"
},
{
"command": "pct config <ctid>",
"description": "Show container configuration (parsed by pct)"
}
]
},
{
"title": "Configuration Files (raw)",
"commands": [
{
"command": "cat /etc/pve/qemu-server/<vmid>.conf",
"description": "View raw VM configuration file"
},
{
"command": "cat /etc/pve/lxc/<ctid>.conf",
"description": "View raw CT configuration file"
},
{
"command": "nano /etc/pve/qemu-server/<vmid>.conf",
"description": "Edit raw VM configuration file (nano)"
},
{
"command": "nano /etc/pve/lxc/<ctid>.conf",
"description": "Edit raw CT configuration file (nano)"
},
{
"command": "vi /etc/pve/qemu-server/<vmid>.conf",
"description": "Edit raw VM configuration file (vi)"
},
{
"command": "vi /etc/pve/lxc/<ctid>.conf",
"description": "Edit raw CT configuration file (vi)"
}
]
},
{
"title": "VM Management",
"commands": [
{
"command": "qm start <vmid>",
"description": "Start a virtual machine. Use the correct <vmid>"
},
{
"command": "qm stop <vmid>",
"description": "Force stop a virtual machine. Use the correct <vmid>"
},
{
"command": "qm shutdown <vmid>",
"description": "Gracefully shutdown a virtual machine"
},
{
"command": "qm reset <vmid>",
"description": "Reset a virtual machine (hard reboot)"
},
{
"command": "qm suspend <vmid>",
"description": "Suspend a virtual machine"
},
{
"command": "qm resume <vmid>",
"description": "Resume a suspended virtual machine"
},
{
"command": "qm destroy <vmid>",
"description": "Delete a VM (irreversible). Use the correct <vmid>"
}
]
},
{
"title": "Container Management",
"commands": [
{
"command": "pct start <ctid>",
"description": "Start a container. Use the correct <ctid>"
},
{
"command": "pct stop <ctid>",
"description": "Force stop a container. Use the correct <ctid>"
},
{
"command": "pct shutdown <ctid>",
"description": "Gracefully shutdown a container"
},
{
"command": "pct restart <ctid>",
"description": "Restart a container"
},
{
"command": "pct destroy <ctid>",
"description": "Delete a CT (irreversible). Use the correct <ctid>"
}
]
},
{
"title": "Container Operations",
"commands": [
{
"command": "pct exec <ctid> -- getent passwd | column -t -s :",
"description": "Show CT users in table format"
},
{
"command": "pct exec <ctid> -- ps aux --sort=-%mem | head",
"description": "Top memory processes in CT"
},
{
"command": "pct enter <ctid>",
"description": "Enter container shell"
},
{
"command": "pct push <ctid> <source> <dest>",
"description": "Copy file from host to container"
},
{
"command": "pct pull <ctid> <source> <dest>",
"description": "Copy file from container to host"
}
]
}
],
"destroyWarn": {
"title": "Destroy is irreversible",
"bodyRich": "<code>qm destroy</code> and <code>pct destroy</code> delete the VM / CT and all its disks. There is no confirmation prompt by default. Take a backup first if there's any chance you might want the data back — see <backupLink>Backup and Restore</backupLink>."
},
"qmConfigTip": {
"title": "qm config vs editing the .conf file directly",
"bodyRich": "<code>qm config &lt;vmid&gt;</code> and <code>pct config &lt;ctid&gt;</code> read the file through Proxmox's own parser — output is normalised, comments stripped, pending changes shown separately. Editing <code>/etc/pve/qemu-server/&lt;vmid&gt;.conf</code> or <code>/etc/pve/lxc/&lt;ctid&gt;.conf</code> directly bypasses the parser. Useful for fixing a corrupted config or applying a setting <code>qm set</code> won't accept, but stop the guest first to avoid races. The cluster filesystem (<code>pmxcfs</code>) takes care of propagating the change to other nodes."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/help-info/backup-commands",
"label": "Backup and Restore",
"tail": " — vzdump and qmrestore / pct restore."
},
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks",
"tail": " — qm importdisk and disk management."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,227 @@
{
"meta": {
"title": "ZFS Commands on Proxmox — zpool, zfs snapshot, send/receive, scrub | ProxMenux",
"description": "Reference of ZFS management commands on Proxmox VE: zpool create / status / history, zfs list / get / set, snapshots, clone, zfs send and receive, scrub, clear, replace, zpool iostat, ARC summary.",
"ogTitle": "ZFS Commands on Proxmox — zpool, zfs snapshot, send/receive, scrub",
"ogDescription": "Reference of zpool and zfs commands on Proxmox VE — pools, datasets, snapshots, replication, maintenance.",
"twitterTitle": "ZFS Commands on Proxmox | ProxMenux",
"twitterDescription": "zpool and zfs commands for Proxmox VE: pools, datasets, snapshots, replication, maintenance."
},
"header": {
"title": "ZFS Management",
"description": "Curated reference for zpool and zfs commands: pool inspection, dataset CRUD, snapshots, clone and send/receive (incremental and recursive), scrub / clear / replace for maintenance, plus I/O statistics and ARC summary.",
"section": "Help and Info"
},
"intro": {
"title": "Two command families",
"body": "<code>zpool *</code> manages the storage pools (physical layer — disks, vdevs, redundancy). <code>zfs *</code> manages the datasets and snapshots that live inside those pools (logical layer — filesystems, volumes, snapshots, properties)."
},
"commandGroups": [
{
"title": "Pool Information",
"commands": [
{
"command": "zpool list",
"description": "List all ZFS pools"
},
{
"command": "zpool status",
"description": "Show detailed pool status and health"
},
{
"command": "zpool status -v",
"description": "Show verbose pool status with errors"
},
{
"command": "zpool history",
"description": "Show command history for all pools"
},
{
"command": "zpool history <pool>",
"description": "Show command history for specific pool"
},
{
"command": "zpool get all <pool>",
"description": "Show all properties of a pool"
}
]
},
{
"title": "Dataset Management",
"commands": [
{
"command": "zfs list",
"description": "List all ZFS datasets"
},
{
"command": "zfs list -r <pool>",
"description": "List all datasets in a pool recursively"
},
{
"command": "zfs create <pool>/<dataset>",
"description": "Create a new dataset"
},
{
"command": "zfs destroy <pool>/<dataset>",
"description": "Destroy a dataset"
},
{
"command": "zfs rename <pool>/<dataset> <pool>/<new-name>",
"description": "Rename a dataset"
},
{
"command": "zfs get all <pool>/<dataset>",
"description": "Show all properties of a dataset"
},
{
"command": "zfs set compression=on <pool>/<dataset>",
"description": "Enable compression on a dataset"
}
]
},
{
"title": "Snapshot Management",
"commands": [
{
"command": "zfs list -t snapshot",
"description": "List all snapshots"
},
{
"command": "zfs list -t snapshot -r <pool>",
"description": "List all snapshots in a pool"
},
{
"command": "zfs snapshot <pool>/<dataset>@<snapshot-name>",
"description": "Create a snapshot"
},
{
"command": "zfs destroy <pool>/<dataset>@<snapshot-name>",
"description": "Delete a snapshot"
},
{
"command": "zfs rollback <pool>/<dataset>@<snapshot-name>",
"description": "Rollback to a snapshot"
},
{
"command": "zfs hold <tag> <pool>/<dataset>@<snapshot-name>",
"description": "Place a hold on a snapshot"
},
{
"command": "zfs release <tag> <pool>/<dataset>@<snapshot-name>",
"description": "Release a hold on a snapshot"
}
]
},
{
"title": "Clone and Send/Receive",
"commands": [
{
"command": "zfs clone <pool>/<dataset>@<snapshot> <pool>/<clone-name>",
"description": "Create a clone from a snapshot"
},
{
"command": "zfs send <pool>/<dataset>@<snapshot> > backup.zfs",
"description": "Send a snapshot to a file"
},
{
"command": "zfs receive <pool>/<dataset> < backup.zfs",
"description": "Receive a snapshot from a file"
},
{
"command": "zfs send -i <pool>/<dataset>@<snap1> <pool>/<dataset>@<snap2> > incr.zfs",
"description": "Send incremental snapshot"
},
{
"command": "zfs send -R <pool>/<dataset>@<snapshot> > full-recursive.zfs",
"description": "Send recursive snapshot"
}
]
},
{
"title": "Maintenance and Repair",
"commands": [
{
"command": "zpool scrub <pool>",
"description": "Start a scrub operation on a pool"
},
{
"command": "zpool scrub -s <pool>",
"description": "Stop a running scrub"
},
{
"command": "zpool clear <pool>",
"description": "Clear error counts in a pool"
},
{
"command": "zpool clear <pool> <device>",
"description": "Clear errors on a specific device"
},
{
"command": "zpool replace <pool> <old-device> <new-device>",
"description": "Replace a failed device"
},
{
"command": "zpool offline <pool> <device>",
"description": "Take a device offline"
},
{
"command": "zpool online <pool> <device>",
"description": "Bring a device online"
}
]
},
{
"title": "Performance and Monitoring",
"commands": [
{
"command": "zpool iostat",
"description": "Show I/O statistics for pools"
},
{
"command": "zpool iostat -v",
"description": "Show detailed I/O statistics"
},
{
"command": "zpool iostat 5",
"description": "Show I/O statistics every 5 seconds"
},
{
"command": "arc_summary",
"description": "Show ARC statistics (if installed)"
},
{
"command": "zfs get compressratio <pool>/<dataset>",
"description": "Show compression ratio"
},
{
"command": "zfs get used,available,referenced <pool>/<dataset>",
"description": "Show space usage"
}
]
}
],
"bestPractices": {
"title": "Operational best practices",
"bodyRich": "Run <code>zpool scrub</code> weekly or monthly to detect silent corruption. Keep at least 10-15% of pool space free — ZFS performance degrades sharply over 80% full. Always replace failed devices with <code>zpool replace</code> (in-place) rather than detach + add (which loses redundancy temporarily)."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/help-info/storage-commands",
"label": "Storage and Disks",
"tail": " — generic block-device and LVM commands."
},
{
"href": "/docs/help-info/backup-commands",
"label": "Backup and Restore",
"tail": " — vzdump, qmrestore."
},
{
"href": "/docs/help-info",
"label": "Help and Info overview",
"tail": "."
}
]
}
}
+93
View File
@@ -0,0 +1,93 @@
{
"meta": {
"title": "Installing ProxMenux | ProxMenux Documentation",
"description": "One-line installer for ProxMenux on Proxmox VE 8+ hosts. Choose between the Translation flavour (multi-language) or Normal (lightweight English-only). Beta channel also available for early access to new features.",
"ogTitle": "Installing ProxMenux | ProxMenux Documentation",
"ogDescription": "Install ProxMenux on Proxmox VE 8+ in one command. Stable and beta channels available."
},
"header": {
"title": "Installing ProxMenux",
"description": "One-line installer that runs on any Proxmox VE 8+ host. Auto-installs the dependencies it needs, downloads the scripts, sets up the menu launcher and (on first run) prompts you to pick a language. Two install channels: stable (default) and beta.",
"section": "Installation"
},
"stable": {
"heading": "Install",
"intro": "Run this in your Proxmox host's terminal:",
"code": "bash -c \"$(wget -qLO - https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh)\""
},
"during": {
"heading": "During installation",
"intro": "ProxMenux automatically installs and configures the dependencies it needs:",
"tablePackage": "Package",
"tablePurpose": "Purpose",
"rows": [
{
"package": "dialog",
"purpose": "Interactive terminal menus"
},
{
"package": "curl",
"purpose": "Downloads and connectivity checks"
},
{
"package": "jq",
"purpose": "JSON processing"
},
{
"package": "git",
"purpose": "Repository cloning and updates"
}
],
"outro": "The installer also pulls down the script tree into <code>/usr/local/share/proxmenux/</code> and creates the launcher at <code>/usr/local/bin/menu</code>. The <strong>ProxMenux Monitor</strong> web dashboard is registered as <code>proxmenux-monitor.service</code>.",
"imageAlt": "ProxMenux installation in progress"
},
"first": {
"heading": "First launch",
"intro": "Once installed, run:",
"code": "menu",
"outro": "ProxMenux launches and you land on the main menu. From here you can run any of the workflows documented in this site — <postlink>Post-Install</postlink> is a good first stop on a fresh Proxmox host."
},
"beta": {
"heading": "Beta channel",
"calloutTitle": "What is the Beta Program?",
"calloutBody": "Want to try the latest features before the official release and help shape the final version? The ProxMenux Beta Program gives early access to new functionality — including the newest builds of ProxMenux Monitor — directly from the <code>develop</code> branch. Beta builds may contain bugs or incomplete features. Your feedback helps fix them before the stable release.",
"intro": "Install the beta version instead of the stable one with:",
"code": "bash -c \"$(wget -qLO - https://raw.githubusercontent.com/MacRimi/ProxMenux/develop/install_proxmenux_beta.sh)\"",
"outro": "Beta is opt-in — you have to explicitly run the beta installer. When a stable release is published, ProxMenux notifies you on the next <code>menu</code> launch and offers to switch automatically. To opt out earlier, use the <betalink>Deactivate Beta Program</betalink> option in Settings."
},
"updating": {
"heading": "Updating",
"body": "ProxMenux self-updates. When a new version is available, you're prompted on the next <code>menu</code> launch and accepting replaces utility files and configurations in place. No manual download needed. Stable users get stable releases; beta users get beta releases (and the auto-switch prompt above when a stable cuts over)."
},
"uninstall": {
"heading": "Uninstalling",
"body": "From inside ProxMenux: <strong>Settings → Uninstall ProxMenux</strong>. Removes the script tree, launcher and Monitor service, optionally removes selected dependencies, restores <code>/root/.bashrc</code> and <code>/etc/motd</code> backups taken at install time. Full step-by-step: <uninstalllink>Uninstall ProxMenux</uninstalllink>."
},
"troubleshoot": {
"heading": "Troubleshooting",
"virustotalTitle": "VirusTotal flags the install URL",
"virustotalBody": "A 1/95 detection by heuristic engines (e.g. <em>Chong Lua Dao</em>) is a known false positive. The installer uses the standard <code>curl | bash</code> pattern and downloads legitimate binaries (like <code>jq</code> from its official GitHub release), which aggressive scanners flag based on <em>behaviour</em> rather than actual malicious code. The installer is 100% open source and reviewable. More context in <issuelink>Issue #162</issuelink>.",
"aptTitle": "Install fails with apt errors",
"aptBody": "Usually a missing or misconfigured Proxmox repo. The installer pulls dependencies via apt; if the repo config is broken (often the case on bare-bones Proxmox 8 installs that haven't been updated yet), apt fails. Run <code>apt-get update</code> manually first and resolve any errors, then re-run the installer.",
"menuTitle": "`menu: command not found` after install",
"menuBody": "The launcher lives at <code>/usr/local/bin/menu</code>. Check it's there: <code>ls -lh /usr/local/bin/menu</code>. If missing, the install ended early — re-run the installer. If present but not found, your PATH doesn't include <code>/usr/local/bin</code>; either fix PATH or invoke the launcher directly: <code>/usr/local/bin/menu</code>.",
"stuckTitle": "The install hangs or doesn't progress",
"stuckBody": "If an install, reinstall or update gets stuck because of a connection issue, cancel with <strong>Ctrl + C</strong> and re-run the installer manually.",
"otherTitle": "Other issues",
"otherBody": "Check the <issueslink>GitHub Issues</issueslink> for known problems or open a new one with the relevant log output. Beta users: include <code>journalctl -u proxmenux-monitor -n 50</code> if Monitor-related."
},
"next": {
"heading": "What's next",
"postInstall": "<postlink>Post-Install Script</postlink> — tweaks and hardening for a fresh Proxmox host.",
"introduction": "<introlink>Introduction</introlink> — the full feature tour.",
"monitor": "<monitorlink>ProxMenux Monitor</monitorlink> — web dashboard for the host (auto-installed alongside the menu)."
},
"requirements": {
"heading": "Requirements & good practices",
"reqTitle": "Requirements",
"reqBody": "Proxmox VE <strong>8.x or later</strong>. PVE 7 and earlier are not supported. Internet access from the host (the installer downloads scripts, dependencies and — on the Translation install — Python packages from PyPI). Run as <strong>root</strong> on the Proxmox host.",
"inspectTitle": "Always inspect scripts you run from the internet",
"inspectReview": "<sourcelink>Review the installer source</sourcelink> before running.",
"inspectCoc": "All executable links follow the <coclink>ProxMenux Code of Conduct</coclink>."
}
}
+206
View File
@@ -0,0 +1,206 @@
{
"meta": {
"title": "ProxMenux — Menu-Driven Tool for Proxmox VE Management | Open Source",
"description": "Open-source, menu-driven tool for Proxmox VE management. ProxMenux is two pieces sharing one project: a CLI/TUI for post-install tweaks, VM and LXC creation, GPU and Coral TPU passthrough, disk, storage and network workflows; and a self-hosted web dashboard with proactive health monitoring, notifications to Telegram / Discord / Email, AI rewrite and a REST API.",
"ogTitle": "ProxMenux — Menu-Driven Tool for Proxmox VE Management",
"ogDescription": "Open-source CLI/TUI plus a web dashboard for Proxmox VE. Post-install, VMs, GPUs, disks, network, storage, security — and a separate Monitor with health checks, notifications, AI rewrite and REST API.",
"twitterTitle": "ProxMenux — Menu-Driven Tool for Proxmox VE Management",
"twitterDescription": "Open-source CLI/TUI + web dashboard for Proxmox VE. Health Monitor, notifications, AI rewrite, REST API."
},
"header": {
"title": "Introduction",
"description": "ProxMenux is an open-source, menu-driven tool for Proxmox VE. Two pieces share the same project: a CLI/TUI that wraps the most common host, VM, container, storage, network and security workflows; and a self-hosted web dashboard with proactive health monitoring, notifications, an AI rewrite hook and a REST API.",
"section": "Introduction"
},
"hero": {
"tagline": "<strong>One menu, every workflow.</strong> Everything that normally takes a tab open to the wiki, two forum threads and a copy-pasted command sequence — exposed as a numbered option you can run in seconds.",
"audience": "Built for <em>first-time</em> Proxmox users (safe, opinionated defaults) and <em>experienced</em> admins (fewer keystrokes for tasks they've done a hundred times). Free and open source under an active community on <github>GitHub</github>."
},
"twoProducts": {
"heading": "Two products, one project",
"intro": "ProxMenux ships as two independent pieces sharing the same source tree. The installer deploys both — they live side by side on the host and don't depend on each other:",
"scripts": {
"title": "ProxMenux Scripts",
"body": "The original CLI/TUI you launch with <code>menu</code>. Nine functional areas covering post-install optimizations, VM and LXC creation, GPU and Coral TPU passthrough, disks, storage, network, security, utilities, plus a curated commands reference. Runs in any terminal — local, SSH or web."
},
"monitor": {
"title": "ProxMenux Monitor",
"body": "Self-hosted web dashboard (AppImage). Real-time host metrics, a proactive Health Monitor, notifications, an optional AI rewrite hook (six providers), an integrated web terminal and a REST API. Enable from the Scripts menu (Settings → ProxMenux Monitor)."
},
"calloutTitle": "What ProxMenux acts on",
"calloutIntro": "Three layers, all reachable from the same project:",
"layers": [
"<strong>The Proxmox host</strong> — repos, packages, network, ZFS, Ceph, kernel, observability.",
"<strong>Virtual machines (VMs)</strong> — creation, GPU passthrough, OVA / OVF import / export, disk passthrough.",
"<strong>LXC containers</strong> — creation, mount points, GPU / TPU passthrough, NFS / Samba clients and servers."
]
},
"scriptsSection": {
"heading": "ProxMenux Scripts — what you get",
"intro": "Nine functional areas, each with its own menu inside <code>menu</code> and a detail page in the documentation. Click any card to jump straight to that section's overview.",
"items": [
{
"title": "Post-Install",
"description": "Optimizations for a freshly installed Proxmox setup: repos, kernel, time sync, basic security, performance, with reversible options.",
"icon": "Server",
"href": "/docs/post-install"
},
{
"title": "GPUs & Coral TPU",
"description": "NVIDIA, Intel iGPU, AMD and Coral TPU passthrough to VMs and LXC containers, with mode switching between VM and LXC.",
"icon": "Cpu",
"href": "/docs/hardware/nvidia-host"
},
{
"title": "Create VM",
"description": "Wizards for NAS systems, Windows and Linux — with sensible defaults for hardware, storage and network.",
"icon": "Server",
"href": "/docs/create-vm"
},
{
"title": "Disk Manager",
"description": "Import physical disks to VMs and LXC, format and wipe, SMART tests, qcow2 / vmdk / vdi image import — from a menu.",
"icon": "HardDrive",
"href": "/docs/disk-manager"
},
{
"title": "Storage & Share",
"description": "Register NFS, Samba (CIFS), iSCSI and local storage in Proxmox; share folders between host and LXC containers via bind mounts or network protocols.",
"icon": "Boxes",
"href": "/docs/storage-share"
},
{
"title": "Network",
"description": "Read-only diagnostics, analyze-then-suggest workflows and guided repairs for /etc/network/interfaces. Mandatory backups before any change.",
"icon": "Network",
"href": "/docs/network"
},
{
"title": "Security",
"description": "Fail2Ban (intrusion prevention for SSH and the web UIs) and Lynis (hardening audit) — install and manage with sensible defaults.",
"icon": "Shield",
"href": "/docs/security"
},
{
"title": "Utilities",
"description": "Build Windows ISOs from UUP Dump, install CLI tools, run a safe system update, perform PVE 8 → 9 upgrade, export and import OVA / OVF VMs.",
"icon": "Wrench",
"href": "/docs/utils"
},
{
"title": "Commands Reference",
"description": "Curated catalogue of Linux and Proxmox commands organised by topic — system, VM/CT (qm, pct), storage, network, ZFS, GPU passthrough, backup, day-to-day CLI tools.",
"icon": "BookOpen",
"href": "/docs/help-info"
}
]
},
"monitorSection": {
"heading": "ProxMenux Monitor — what you get",
"intro": "The web dashboard product. Self-hosted on the Proxmox host on TCP 8008. Click any card to jump straight to that section's page, or read the <link>Monitor overview</link> first.",
"items": [
{
"title": "Health Monitor",
"description": "Ten categories scanned every 5 minutes (CPU, memory, storage, disks/SMART, network, VMs, services, logs, updates, security) with severity levels and per-category suppression.",
"icon": "Activity",
"href": "/docs/monitor/health-monitor"
},
{
"title": "Notifications",
"description": "Telegram, Discord, Email, Gotify and Apprise (multi-channel) — with deduplication, cooldown, burst aggregation, quiet hours and a complete history.",
"icon": "Bell",
"href": "/docs/monitor/notifications"
},
{
"title": "AI Assistant",
"description": "Optional rewrite of notifications in plain language. Six providers: OpenAI, Anthropic Claude, Google Gemini, Groq, OpenRouter, local Ollama. Twelve languages.",
"icon": "Sparkles",
"href": "/docs/monitor/ai-assistant"
},
{
"title": "Web Terminal",
"description": "Browser-based interactive shell on the Proxmox host plus a separate ProxMenux Scripts terminal that runs the menu through the web UI.",
"icon": "Terminal",
"href": "/docs/monitor/dashboard/terminal"
},
{
"title": "REST API",
"description": "HTTP endpoints for system, health, storage / SMART, network, VMs, notifications and security — useful for Homepage, Home Assistant, Prometheus or custom scripts.",
"icon": "Code2",
"href": "/docs/monitor/api"
},
{
"title": "Integrations",
"description": "Native Proxmox VE webhook, Prometheus scrape, Uptime Kuma probe, Homepage / Home Assistant / Glance widgets, n8n / Zapier flows, Tailscale Secure Gateway.",
"icon": "Plug",
"href": "/docs/monitor/integrations"
}
]
},
"installPaths": {
"heading": "Install paths",
"intro": "The installer deploys Scripts and Monitor in one go. Scripts has two flavours — translation or lightweight — and the Monitor is installed as a standalone AppImage you enable from the menu later:",
"headerPath": "Install path",
"headerBundles": "What it bundles",
"headerWhen": "When you'd pick it",
"rows": [
{
"pathRich": "<strong>Scripts: Translation</strong>",
"bundles": "CLI/TUI + Python venv + googletrans (English, Spanish, French, German, Italian, Portuguese)",
"when": "Multi-language menus, non-English speakers"
},
{
"pathRich": "<strong>Scripts: Normal (lightweight)</strong>",
"bundles": "CLI/TUI English-only, smaller footprint, no Python venv",
"when": "Most users — Proxmox docs are English anyway"
},
{
"pathRich": "<strong>Monitor</strong>",
"bundles": "Self-contained AppImage on TCP 8008. Independent install — can be enabled from the Scripts menu, or run the AppImage directly.",
"when": "When a web dashboard for the host is useful — phone, tablet, browser tab"
}
],
"outro": "Detailed install commands and prerequisites are on the <link>Installation page</link>."
},
"warnSource": {
"title": "Always check what scripts you run from the internet",
"body": "ProxMenux is open source and every script is reviewable on GitHub. Before running the install command, look at the source. Do the same with any other automation tool.",
"sourceLabel": "View ProxMenux source",
"cocLabel": "Code of Conduct"
},
"next": {
"heading": "Where to go next",
"items": [
{
"lead": "<strong>New to ProxMenux?</strong> ",
"linkHref": "/docs/installation",
"linkLabel": "Install it in one command",
"tailRich": " and run <code>menu</code>."
},
{
"lead": "<strong>Just installed Proxmox?</strong> Start with the ",
"linkHref": "/docs/post-install",
"linkLabel": "Post-Install Script",
"tail": "."
},
{
"lead": "<strong>Want a web dashboard?</strong> ",
"linkHref": "/docs/monitor",
"linkLabel": "ProxMenux Monitor",
"tail": " covers what it shows, how it's built and how to secure it."
},
{
"lead": "<strong>Looking for a specific command?</strong> ",
"linkHref": "/docs/help-info",
"linkLabel": "Commands Reference",
"tail": " is a curated catalog organised by topic, with copy buttons."
},
{
"lead": "<strong>Want longer how-to guides?</strong> The ",
"linkHref": "/guides",
"linkLabel": "Guides section",
"tail": " covers Coral TPU, NVIDIA passthrough, Kodi LXC and more."
}
]
}
}
@@ -0,0 +1,396 @@
{
"meta": {
"title": "Proxmox Dashboard Authentication — 2FA, API Tokens, User Profile, Reverse Proxy | ProxMenux Monitor",
"description": "Reach and secure ProxMenux Monitor: first-launch protect-your-dashboard flow, password authentication with display name + avatar, profile page, TOTP 2FA enrolment, long-lived API tokens for scripts, HTTPS configuration, reverse-proxy snippets for Nginx, Caddy and Traefik, the audit log and the optional Fail2Ban jail.",
"ogTitle": "Proxmox Dashboard Authentication — 2FA, API Tokens, Reverse Proxy",
"ogDescription": "Secure ProxMenux Monitor with password + TOTP 2FA, long-lived API tokens, HTTPS, reverse-proxy snippets and an optional Fail2Ban jail.",
"twitterTitle": "Proxmox Dashboard Authentication | ProxMenux Monitor",
"twitterDescription": "Password + TOTP 2FA, API tokens, HTTPS, Nginx/Caddy/Traefik snippets and audit log."
},
"header": {
"title": "Access & Authentication",
"description": "Reaching the dashboard, the first-launch security flow, and every layer that can sit between an attacker and the host: password + TOTP, JWT sessions, long-lived API tokens, HTTPS, reverse proxies, Secure Gateway, and the optional Fail2Ban jail.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Authentication is opt-in",
"body": "On first launch the dashboard shows a single dialog — <em>\"Protect Your Dashboard?\"</em> — with two buttons: <strong>Yes, Setup Password</strong> and <strong>No, Continue Without Protection</strong>. Saying no leaves every API endpoint open on TCP 8008 — fine for an isolated lab LAN, dangerous on anything else. Two-Factor Authentication (2FA) is <strong>not</strong> part of this initial choice; it's configured later from <strong>the Security tab</strong> once a password is set."
},
"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 what the systemd unit ships out of the box. The reverse-proxy and Secure Gateway sections below cover the other two. The Monitor honours <code>X-Forwarded-For</code>, <code>X-Forwarded-Proto</code> and <code>X-Forwarded-Host</code> so URLs and CORS work behind any of them without manual configuration."
},
"firstLaunch": {
"heading": "First-launch flow",
"intro": "The first time you open the dashboard, the frontend calls <code>GET /api/auth/status</code>. If the auth config has never been written (<code>configured: false</code>), a single dialog appears titled <em>\"Protect Your Dashboard?\"</em> with two choices:",
"imageAlt": "First-launch dialog 'Protect Your Dashboard?' with two buttons: Yes Setup Password, No Continue Without Protection",
"imageCaption": "The first-launch authentication chooser. Two buttons — password protection or skip. Re-runs after a fresh install or after \"Disable authentication\" from Settings.",
"headerButton": "Button",
"headerWhat": "What happens",
"headerApi": "API call",
"rows": [
{
"button": "Yes, Setup Password",
"what": "Opens a form with the mandatory username + password and an optional <em>display name</em> + <em>avatar image</em>. Stores them in <code>auth.json</code> with <code>enabled: true</code>. Returns a JWT so you're logged in immediately. The form is documented in detail below.",
"api": "POST /api/auth/setup"
},
{
"button": "No, Continue Without Protection",
"what": "Marks <code>declined: true</code> in <code>auth.json</code>. Every API endpoint is publicly accessible until you change your mind from Settings.",
"api": "POST /api/auth/skip"
}
],
"twofaCalloutTitle": "2FA is configured later, not here",
"twofaCalloutBody": "The first-launch dialog covers only the password decision. <strong>Two-Factor Authentication (TOTP)</strong> is set up afterwards from <strong>the Security tab</strong> once you're logged in with a password. The full TOTP walkthrough is further down this page.",
"createTitle": "Creating the first user",
"createIntro": "Clicking <em>Yes, Setup Password</em> opens a single form that creates the account and, optionally, seeds the user's profile in one go so the avatar appears in the header right after saving. The fields are:",
"headerField": "Field",
"headerRequired": "Required",
"headerNotes": "Notes",
"fieldRows": [
{
"field": "Username",
"required": "Yes",
"notes": "The login identifier. Cannot be changed later from the UI; editing it requires touching <code>auth.json</code> directly."
},
{
"field": "Password",
"required": "Yes",
"notes": "Minimum 10 characters, with at least 3 of the 4 categories (lowercase, uppercase, digit, symbol). A short list of obvious passwords (<code>password</code>, <code>12345678</code>, <code>proxmenux</code>…) is rejected outright. The same rules are enforced server-side, so a curl call cannot bypass the front-end check."
},
{
"field": "Display name",
"required": "No",
"notes": "Friendly label shown in the header dropdown and on the profile page. Falls back to the username when empty. Can be changed later from <strong>Avatar → View profile</strong>."
},
{
"field": "Avatar image",
"required": "No",
"notes": "PNG, JPEG, WebP or GIF up to 2 MB. Rendered as a circle in the header and on the profile page. When empty, the header shows the first letter of the display name (or username) on a coloured circle. Can be uploaded, replaced or removed later from the profile page."
}
],
"createImageAlt": "Create-user form with mandatory Username + Password fields and the optional Display name + Avatar upload section",
"createImageCaption": "The first-launch create-user form. Display name and avatar are optional — leaving them empty creates the account and falls back to a single-letter circle in the header.",
"saveCalloutTitle": "One save, three API calls under the hood",
"saveCalloutBody": "The form submits <code>POST /api/auth/setup</code> first (username + password). On success it uses the freshly-issued JWT to follow up with <code>PUT /api/auth/profile</code> (display name) and <code>POST /api/auth/profile/avatar</code> (avatar bytes) if those fields were filled. Failures on the profile calls are non-fatal — the account is already created and you can finish the profile later from the dedicated page.",
"avatarTitle": "Avatar menu and profile page",
"avatarBody1": "Once authentication is configured, an avatar circle appears at the top-right of every dashboard page next to the theme toggle. Clicking it opens a small dropdown with shortcuts to the profile page and the Security tab, plus a <strong>Sign out</strong> action — closing the session can be done from here or from the Security tab, whichever is closer to where you are.",
"avatarBody2": "The profile page itself is a small card with an avatar preview, the username (read-only), and the display name with an inline edit button. Avatar uploads, replacements and removals are atomic — the header avatar refreshes automatically when any of them succeed, so there is no need to reload the page. The same set of endpoints documented in the next section are used by both the create-user form and the profile page.",
"profileImageAlt": "Profile page with avatar preview circle, Upload / Replace / Remove buttons, read-only username and editable display name field",
"profileImageCaption": "The dedicated profile page. Username is read-only; display name and avatar can be edited from here without touching the Security tab.",
"headerEndpoint": "Endpoint",
"headerEpWhat": "What it does",
"endpointRows": [
{
"endpoint": "GET /api/auth/profile",
"what": "Returns the current username, display name and whether an avatar is set (<code>has_avatar</code>, <code>avatar_mtime</code>)."
},
{
"endpoint": "PUT /api/auth/profile",
"what": "Updates the display name. Body: <code>'{' \"display_name\": \"...\" '}'</code>."
},
{
"endpoint": "GET /api/auth/profile/avatar",
"what": "Returns the avatar bytes (PNG / JPEG / WebP / GIF) with the matching content type. Requires the Bearer header — the front-end fetches it as a blob and converts to a local object URL for rendering."
},
{
"endpoint": "POST /api/auth/profile/avatar",
"what": "Uploads a new avatar (max 2 MB). Content type must match the file. Old avatar is replaced atomically."
},
{
"endpoint": "DELETE /api/auth/profile/avatar",
"what": "Removes the avatar. The header falls back to the initial-on-coloured-circle placeholder."
}
],
"reversibleTitle": "Continuing without protection is reversible — but only from the host",
"reversibleBody": "Once you click <em>No, Continue Without Protection</em>, the welcome dialog never appears again. You can re-enable authentication from <strong>the Security tab</strong> inside the dashboard, or by editing <code>/root/.config/proxmenux-monitor/auth.json</code> and removing the <code>declined</code> flag, then restarting the service."
},
"password": {
"heading": "Password authentication",
"intro": "After Set up, every API call (except the few public endpoints listed below) requires a JWT in <code>Authorization: Bearer &lt;token&gt;</code>:",
"items": [
"<strong>Session token (login):</strong> 24-hour expiration. Issued by <code>POST /api/auth/login</code>.",
"<strong>API token (integrations):</strong> 365-day expiration. Issued by <code>POST /api/auth/generate-api-token</code>. Documented separately in the next section."
],
"loginImageAlt": "Login screen shown after authentication is configured — username and password fields",
"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 endpoints (no token)",
"publicIntro": "These are the only endpoints that work without authentication, even when auth is enabled:",
"publicItems": [
"<code>/api/auth/login</code>, <code>/api/auth/status</code>, <code>/api/auth/setup</code> — the auth flow itself, by necessity.",
"<code>/api/system-info</code> — lightweight system snapshot (hostname, uptime, <code>health.status</code>). The right endpoint for external probes (Uptime Kuma, load-balancer health checks, status pages)."
],
"cryptoTitle": "Cryptography and storage",
"cryptoIntro": "ProxMenux Monitor is open source — none of this is secret. Documenting the stack here explicitly is a deliberate choice: operators who store credentials on their host deserve to know how those credentials are protected before they decide to trust them. The algorithms below are the same ones the code in <code>scripts/auth_manager.py</code> uses; this section is a contract, not a marketing promise.",
"headerAsset": "Asset",
"headerAlgo": "Algorithm",
"headerWhere": "Where it lives",
"cryptoRows": [
{
"asset": "Password",
"algorithm": "PBKDF2-HMAC-SHA256 with a per-password random salt and a high iteration count (OWASP 2023+ baseline). Stored as <code>pbkdf2_sha256$&lt;iters&gt;$&lt;salt&gt;$&lt;hash&gt;</code>.",
"where": "<code>auth.json</code> → <code>password_hash</code>"
},
{
"asset": "Session / API JWT",
"algorithm": "HS256 signed with a per-install secret minted at first launch (<code>secrets.token_urlsafe</code>, ≥48 bytes). Tokens carry <code>iss=proxmenux-monitor</code> + <code>aud=api</code> claims; the signature is validated against the current secret on every request.",
"where": "Secret: <code>auth.json</code> → <code>jwt_secret</code>. JWT itself: only on the client."
},
{
"asset": "API token metadata",
"algorithm": "SHA-256 of the JWT stored alongside a <code>signed_with</code> fingerprint of the <code>jwt_secret</code> used to mint it — used to display the token in the UI and to detect tokens whose signing secret has been rotated.",
"where": "<code>auth.json</code> → <code>api_tokens[]</code>"
},
{
"asset": "2FA TOTP secret",
"algorithm": "Standard TOTP (RFC 6238) base32-encoded. Backup codes are pre-generated, single-use, hashed with the same PBKDF2 scheme as the password.",
"where": "<code>auth.json</code> → <code>totp_secret</code> + <code>backup_codes[]</code>"
},
{
"asset": "Revocations",
"algorithm": "When a token or session is revoked, its SHA-256 is added to a deny-list checked on every verification (mem-cached for ~30 s to avoid disk reads on the hot path).",
"where": "<code>auth.json</code> → <code>revoked_tokens[]</code>"
}
],
"authJsonTitle": "auth.json — what it contains and how it's protected",
"authJsonBody": "Everything ProxMenux Monitor needs to authenticate you lives in a single file: <code>/root/.config/proxmenux-monitor/auth.json</code>, mode <code>0600</code>, owner <code>root</code>. The file holds <em>hashes</em> (PBKDF2) and <em>signing material</em> (<code>jwt_secret</code>, <code>totp_secret</code>) — never a plaintext password. Treat it like any other root-only secret: if you back up or replicate the host, encrypt the destination, and never commit it to version control.",
"rotateTitle": "Rotating jwt_secret invalidates all existing JWTs",
"rotateBody": "If <code>auth.json</code> is regenerated (manual delete, reinstall, restore from a backup with a different secret) the <code>jwt_secret</code> changes and every previously-issued JWT — both interactive sessions and long-lived API tokens — fails verification with \"Invalid or expired token\". The UI flags affected API tokens with an <strong>Invalid — regenerate</strong> badge so the operator knows to revoke and re-mint them; Home Assistant / scripts / any external client needs a fresh token after that.",
"recoverTitle": "Recovering a lost password",
"recoverIntro": "There is no online \"forgot password\" flow — by design, since the dashboard runs on the operator's own host and the recovery path is shell access to that host. ProxMenux ships a guided reset inside the configuration menu so you don't have to hand-edit <code>auth.json</code>:",
"survivesTitle": "What survives the reset",
"survivesBody": "Only the interactive login is wiped. The <code>jwt_secret</code> and the registered <code>api_tokens</code> are preserved — so Home Assistant and any other script using a long-lived API token continue to work without reconfiguration. If you want a fully clean slate (also rotate the JWT secret), delete <code>auth.json</code> manually and restart the service. The next launch generates a fresh secret and all old tokens become invalid.",
"physicalTitle": "Physical-access prerequisite",
"physicalBody": "This reset path needs <strong>root shell on the host</strong>. That is the trust anchor of the whole authentication scheme: anyone who can run <code>menu</code> as root can already do anything on the box, so giving them password reset is not a privilege increase. The corollary: if you let an untrusted user reach the Proxmox shell, the Monitor login won't protect anything that user couldn't already destroy by other means."
},
"twofa": {
"heading": "Two-Factor Authentication (TOTP)",
"intro": "2FA adds a second factor on top of your password: a 6-digit code that rotates every 30 seconds, generated on a phone or password manager you control. Even if someone obtains the password, they still can't log in without the code from your device. ProxMenux Monitor implements the standard <strong>TOTP</strong> protocol (RFC 6238), so any authenticator app works.",
"pickTitle": "Pick an authenticator app",
"pickIntro": "If you already use one for Google / GitHub / your bank, that one will work — skip to the setup walkthrough. If not, here's a survey of common options. All of them are free; the differences are mainly about which platforms they run on and how (or whether) they back up your secrets.",
"headerApp": "App",
"headerPlatforms": "Platforms",
"headerAppNotes": "Notes",
"apps": [
{
"name": "Google Authenticator",
"href": "https://safety.google/authentication/",
"platforms": "iOS, Android",
"notes": "The default for many users. Optional Google-account cloud backup."
},
{
"name": "Microsoft Authenticator",
"href": "https://www.microsoft.com/en-us/security/mobile-authenticator-app",
"platforms": "iOS, Android",
"notes": "Microsoft-account backup. Also handles MS push notifications if you use them at work."
},
{
"name": "Authy",
"href": "https://authy.com/",
"platforms": "iOS, Android, desktop",
"notes": "Multi-device encrypted sync (the desktop app is being phased out — check the latest status)."
},
{
"name": "Apple Passwords",
"href": "https://support.apple.com/guide/passwords/welcome/mac",
"platforms": "iOS, iPadOS, macOS, visionOS, Windows (via iCloud)",
"notes": "Built into Apple OSes; standalone Passwords app since iOS 18 / macOS Sequoia. Stores TOTP next to the password and syncs across devices via iCloud Keychain."
},
{
"name": "Bitwarden",
"href": "https://bitwarden.com/",
"platforms": "iOS, Android, desktop, browser",
"notes": "Open source. TOTP lives next to the password it protects (handy if you also use BW for passwords; defeats \"separate device\" if you don't)."
},
{
"name": "1Password",
"href": "https://1password.com/",
"platforms": "iOS, Android, desktop, browser",
"notes": "Same idea as Bitwarden — TOTP integrated with the password vault. Subscription."
},
{
"name": "Aegis Authenticator",
"href": "https://getaegis.app/",
"platforms": "Android",
"notes": "Open source. Encrypted on-device backup file you control. No cloud, no account required."
},
{
"name": "Raivo OTP",
"href": "https://raivo-otp.com/",
"platforms": "iOS, macOS",
"notes": "Open source. Optional iCloud sync. The Apple-ecosystem counterpart to Aegis."
},
{
"name": "Ente Auth",
"href": "https://ente.io/auth/",
"platforms": "iOS, Android, desktop, web",
"notes": "Open source. End-to-end encrypted cloud sync across devices."
},
{
"name": "2FAS",
"href": "https://2fas.com/",
"platforms": "iOS, Android, browser extension",
"notes": "Open source. Optional encrypted cloud backup; browser extension can autofill codes."
},
{
"name": "FreeOTP+",
"href": "https://github.com/helloworld1/FreeOTPPlus",
"platforms": "Android, iOS",
"notes": "Open source (Red Hat-led). Minimal — no cloud, no account."
}
],
"backupTitle": "What \"backup\" really matters for",
"backupBody": "If you lose the device that has the authenticator on it, the only ways back in are (1) a backup code saved when you enabled 2FA, or (2) a backup of the authenticator's vault. Apps with cloud sync (Google Auth, Microsoft Auth, Authy, Apple Passwords, Ente, 2FAS, Bitwarden, 1Password) can restore on a new device. Apps without cloud (Aegis, Raivo, FreeOTP+) need an encrypted export file you've copied somewhere safe. Either approach works — the bad case is \"no backup at all\".",
"setupTitle": "Step-by-step setup from the dashboard",
"setupImageAlt": "2FA setup screen with QR code and backup codes",
"setupImageCaption": "The 2FA setup dialog — QR code, Base32 secret (for manual entry), and the ten one-time backup codes. The codes are only displayed here; if you close the dialog without copying them, they're gone.",
"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 opens with a QR code, a long string in Base32 format and ten short codes labelled \"backup codes\".",
"<strong>Add the entry to the authenticator app:</strong>",
"<strong>Save the backup codes.</strong> Copy the ten codes somewhere safe — a password manager, an encrypted note, a printed copy in a drawer. Treat them like spare keys: each works exactly once and gets you in if your phone is gone or broken.",
"<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>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": [
"<em>Easy path:</em> in the app, tap <em>Add account</em> → <em>Scan QR code</em>, point the camera at the QR on the screen. The app names the entry automatically (something like <code>ProxMenux Monitor (your-username)</code>) and starts showing a 6-digit code that refreshes every 30 seconds.",
"<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": "Once you click Save, log out and log back in <em>immediately</em>, while the setup dialog is still fresh in your mind. If the code is rejected (clock-skew between server and phone is the most common cause), you can still fix it from the open session. Logging out without testing first means a one-trip-no-return — at that point only a backup code or editing <code>auth.json</code> on the host gets you back in.",
"lostTitle": "Lost authenticator",
"lostIntro": "Three escape hatches, in order of how disruptive they are:",
"lostItems": [
"<strong>Use a backup code.</strong> At the login screen, in the TOTP field, type one of the ten codes you saved at setup time. Each works once and is then consumed; the remaining codes still work. Once you're in, regenerate 2FA from Settings to get a fresh ten.",
"<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": "From the dashboard, open the <strong>Security</strong> tab and click <strong>Disable 2FA</strong>. The endpoint <code>POST /api/auth/totp/disable</code> requires the current password as confirmation, then deletes the TOTP secret and clears the backup codes. Remember to also remove the entry in the authenticator app — the app doesn't know the server side is gone, so the dead entry will sit there forever otherwise.",
"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": [
"<strong>Phone:</strong> Settings → Date & Time → automatic / network sync ON.",
"<strong>Proxmox host:</strong> <code>timedatectl status</code> — \"System clock synchronized: yes\" should be visible. If not, <code>timedatectl set-ntp true</code> and wait a minute."
],
"rejectedOutro": "Once both clocks agree, the code is accepted within the next 30-second window."
},
"apiTokens": {
"heading": "API tokens (long-lived)",
"intro": "Browser sessions expire after 24 hours. For unattended integrations (Homepage widgets, Home Assistant sensors, Grafana scrapers, Uptime Kuma probes…) you generate a separate <strong>API token</strong> that lives 365 days. The token is a JWT signed with the same secret as the session token, but its <code>token_name</code> claim makes it easy to track and revoke individually.",
"imageAlt": "API tokens panel showing the token list with name, prefix, created date and expiry",
"imageCaption": "The API tokens list under Settings — name, prefix (last 4 chars are shown for identification), created and expiry dates, revoke action.",
"generateTitle": "Generate a token",
"generateIntro": "From the dashboard:",
"generateSteps": [
"Navigate to <strong>the Security tab → API Access Tokens</strong> section.",
"Type a descriptive name (<em>e.g. \"Home Assistant\"</em>).",
"Re-enter your password. If 2FA is on, also the current 6-digit code.",
"Click <strong>Generate Token</strong>. The token appears <strong>once</strong> — copy it immediately."
],
"generateCli": "From the command line:",
"useTitle": "Use a token",
"revokeTitle": "Revoke a token",
"revokeBody": "From the panel above: each row has a <strong>Revoke</strong> action that adds the token hash to <code>revoked_tokens</code> in <code>auth.json</code>. Revoked tokens fail validation immediately on the next request.",
"cheatTitle": "Token security cheat-sheet",
"cheatItems": [
"Store tokens in your integration's native secrets store — Homepage <code>secrets.yaml</code>, Home Assistant <code>!secret</code>, environment variables, etc. Never commit them to git.",
"One token per integration, named after the consumer. Revoke individually when retiring an integration.",
"Rotate every 612 months. The expiry is a hard limit, not a recommendation."
],
"outro": "Full storage best-practices and integration recipes live in <apiLink>API Reference → Token Management</apiLink> and <intLink>Integrations</intLink>."
},
"https": {
"heading": "HTTPS",
"intro": "Two paths to TLS:",
"items": [
"<strong>Reverse proxy (recommended).</strong> Terminate TLS on Nginx / Caddy / Traefik and forward HTTP on port 8008 to the Flask process. Snippets below.",
"<strong>Direct HTTPS in the AppImage.</strong> Configure a certificate via <code>POST /api/ssl/configure</code> (UI: <strong>Settings → SSL</strong>). When SSL is configured the process switches from Flask's dev server to <code>gevent.pywsgi</code> with the gevent-websocket handler so WebSocket terminal also works over WSS. The cert files live wherever you point them; the paths are stored in the SSL config."
],
"calloutTitle": "Direct HTTPS limitations",
"calloutBody": "The bundled gevent path is suitable for self-signed or LAN-only certificates. For Let's Encrypt / ACME and automatic renewal, run a real reverse proxy in front — Caddy auto-renews and Traefik / Nginx have well-known patterns. The Monitor doesn't implement ACME on its own."
},
"gateway": {
"heading": "Secure Gateway (Tailscale)",
"intro": "Reverse proxies are the classic answer to \"reach the dashboard from outside\" but they require a public domain, certificate, and an open port on the edge. <strong>Secure Gateway</strong> is the zero-port alternative shipped inside the Monitor itself — a pre-built deployable app that spins up an Alpine LXC running <a>Tailscale</a> as a subnet router. Once joined to your tailnet, every device on it can hit the Monitor at the host's own LAN IP — from a laptop on holiday, a phone on 5G, or another node — without exposing TCP 8008 to the internet.",
"calloutTitle": "Why this is convenient",
"calloutBody": "The URL stays the same as on the LAN — <code>http://&lt;proxmox-lan-ip&gt;:8008</code> works everywhere Tailscale works. No certificates, no DNS, no port forwarding. The Monitor itself sees the request as coming from a tailnet IP (typically <code>100.x.y.z</code>), so the auth log and the Fail2Ban hook still function as on the LAN.",
"deployBody": "The deploy flow is one screen — pick the host LXC storage, paste a Tailscale auth-key (generated at <a>login.tailscale.com/admin/settings/keys</a>), choose which subnets to advertise, click Deploy. The LXC takes ~30 seconds to bootstrap and registers in the tailnet automatically.",
"outro": "Step-by-step deployment, subnet-routes configuration, Tailscale ACLs and Exit Node mode are documented separately in <link>Dashboard → Security → Secure Gateway</link> — that's where the deploy wizard lives in the dashboard UI. This page only covers the access pattern."
},
"proxy": {
"heading": "Reverse proxy snippets",
"intro": "The simplest layout is a <strong>dedicated host name</strong> for the Monitor (e.g. <code>monitor.example.com</code>) pointing at port 8008 on the Proxmox host. Snippets below use that pattern. Sub-path mounts (<code>example.com/proxmenux-monitor/</code>) are possible but require extra rewriting and are not the default — see the callout at the end.",
"nginxTitle": "Nginx",
"caddyTitle": "Caddy",
"traefikTitle": "Traefik (labels — Docker / Kubernetes)",
"subPathTitle": "Advanced: sub-path mounts under an existing domain",
"subPathBody": "If you don't want a dedicated host name, you can mount the Monitor under a path on an existing domain — for example <code>example.com/proxmenux-monitor/</code>. The Next.js build uses relative asset paths so static files resolve, but the proxy must <strong>strip the prefix</strong> before forwarding so the Monitor still receives plain <code>/api/*</code> URLs. On Nginx that's a <code>location /proxmenux-monitor/ &rbrace; proxy_pass http://127.0.0.1:8008/; &lbrace;</code> (the trailing slash on <code>proxy_pass</code> does the strip). On Caddy, use <code>handle_path /proxmenux-monitor/*</code>. A dedicated host name is simpler."
},
"audit": {
"heading": "Audit log",
"intro": "Every authentication event (success and failure) is appended to <code>/var/log/proxmenux-auth.log</code> in a single line, syslog-style format:",
"outro": "Tail it the usual way: <code>tail -F /var/log/proxmenux-auth.log</code>. The file is rotated by <code>logrotate</code> if a config drop-in is added; the Monitor itself does not rotate it."
},
"fail2ban": {
"heading": "Optional: Fail2Ban jail",
"calloutTitle": "Fail2Ban is not bundled with the Monitor",
"calloutBody": "Fail2Ban is <strong>not</strong> installed by ProxMenux Monitor itself. Install it via <link>Security → Fail2Ban</link> in the ProxMenux menu (or with the standard Debian package). Without it, the Monitor still writes the audit log above — it just doesn't auto-ban repeat offenders.",
"intro": "When Fail2Ban is installed, the ProxMenux integration ships a <code>[proxmenux]</code> jail that:",
"items": [
"Reads <code>/var/log/proxmenux-auth.log</code>.",
"Matches the <code>authentication failure; rhost=&lt;ip&gt;</code> pattern with a dedicated filter.",
"Bans the offending IP at the kernel firewall level by default.",
"Is queried by the Flask <code>before_request</code> hook every 30 s — so even when the firewall can't block (because the connection comes from the reverse proxy), the application returns HTTP 403 to banned IPs based on what Fail2Ban knows."
],
"outro": "Configuration, ban time tuning and unban procedures are in <link>Security → Fail2Ban</link>."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noScreenTitle": "The first-launch screen never appears",
"noScreenBody": "Either auth is already configured (<code>configured: true</code>) or somebody already chose Skip. To start fresh:",
"noScreenOutro": "This wipes the auth state — also any TOTP secrets and API tokens. Back up <code>auth.json</code> first if you have tokens you want to keep.",
"tokenTitle": "HTTP 401 on every request from a working API token",
"tokenBody": "Token expired (365 d limit) or got into the <code>revoked_tokens</code> list. Generate a new one in Settings and update the integration. To check:",
"tokenOutro": "Expired or revoked tokens return <code>'{'\"error\":\"Invalid or expired token\"'}'</code>.",
"no2faTitle": "Can't log in after enabling 2FA, no authenticator at hand",
"no2faBody": "Use a backup code in the TOTP field. If those are gone, edit <code>/root/.config/proxmenux-monitor/auth.json</code> from a host shell, set <code>totp_enabled</code> to <code>false</code>, restart the service.",
"wsTitle": "Reverse proxy works but the terminal tab disconnects every minute",
"wsBody": "WebSocket idle timeout in the proxy. Bump the read timeout (Nginx: <code>proxy_read_timeout 86400s</code>; Traefik: <code>idleTimeout</code> in the entry-point or middleware) and confirm <code>proxy_set_header Upgrade $http_upgrade</code> and <code>Connection \"upgrade\"</code> are present."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "API Reference → Token Management",
"href": "/docs/monitor/api",
"tail": " — full lifecycle of API tokens (generate / list / revoke), security best-practices, secrets storage patterns."
},
{
"label": "Integrations",
"href": "/docs/monitor/integrations",
"tail": " — Homepage, Home Assistant, Grafana / Prometheus, Uptime Kuma, generic cURL."
},
{
"label": "Dashboard → Security → Secure Gateway",
"href": "/docs/monitor/dashboard/security",
"tail": " — deploy the Tailscale gateway LXC step by step (subnet routes, ACLs, Exit Node mode)."
},
{
"label": "Security → Fail2Ban",
"href": "/docs/security/fail2ban",
"tail": " — how to install and configure the optional jail."
},
{
"label": "Settings → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — start / stop the systemd service from the ProxMenux TUI."
}
]
}
}
@@ -0,0 +1,342 @@
{
"meta": {
"title": "Proxmox AI Assistant — OpenAI, Claude, Gemini, Groq, Ollama | ProxMenux Monitor",
"description": "ProxMenux Monitor's optional AI Assistant rewrites Proxmox VE notification bodies in plain language. Six providers supported: OpenAI, Anthropic Claude, Google Gemini, Groq, OpenRouter and local Ollama. Twelve languages, three detail levels per channel, custom prompt mode with a community library, and a context-enrichment layer that adds uptime, recurrence and SMART data to disk events.",
"ogTitle": "Proxmox AI Assistant — OpenAI, Claude, Gemini, Groq, Ollama",
"ogDescription": "Rewrite Proxmox VE notifications in plain language with OpenAI, Anthropic Claude, Google Gemini, Groq, OpenRouter or local Ollama.",
"twitterTitle": "Proxmox AI Assistant | ProxMenux Monitor",
"twitterDescription": "Rewrite Proxmox VE notifications in plain language with OpenAI, Anthropic, Gemini, Groq, OpenRouter or local Ollama."
},
"header": {
"title": "AI Assistant",
"description": "The opt-in rewriter that runs every outbound notification through an LLM before fan-out — turning structured templates into plain-language messages, with per-channel detail levels, twelve languages, a custom prompt mode with a public community library, and a context-enrichment layer that adds uptime, recurrence, SMART data and known-error matches to the prompt.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Off by default, single switch to enable",
"body": "AI rewrite is opt-in. Until you flip the master toggle inside <em>Settings → Notifications → Advanced: AI Enhancement</em>, every event is dispatched with the original templated body. When the toggle is on and a provider call fails or times out, the dispatcher falls back to the templated body silently — your notifications never block on the LLM."
},
"howItWorks": {
"heading": "How it works",
"intro": "Every event the Monitor dispatches goes through the same pipeline. The AI rewriter is one optional stage that sits between the templated body and the channel send. End to end, a single event walks through four steps:",
"steps": [
"<strong>Event + template.</strong> An event arrives from one of the six collectors and is rendered into a structured plain-text body by <code>notification_templates.py</code>. This is the body the channel would send if AI rewrite were off.",
"<strong>Context enrichment.</strong> The dispatcher inspects the event and conditionally appends the relevant extra signals — system uptime (only for critical system failures), event frequency, SMART data (only for disk events), Known Errors database matches and journal log lines.",
"<strong>Prompt builder.</strong> The system prompt is assembled from the template plus the per-channel settings: target language, detail level, emoji rules from <em>Rich messages</em>, and the AI Suggestions addon if enabled. In Custom prompt mode, your prompt replaces the system prompt entirely. The user message is built from the templated body plus the enriched context blocks.",
"<strong>Provider call.</strong> The configured provider (Groq, OpenAI, Anthropic, Gemini, Ollama or OpenRouter) returns a rewritten title and body. The dispatcher parses the response, replaces the original title and body for that channel, and hands it off to the channel adapter for delivery."
],
"notesIntro": "Three details worth holding on to before reading the rest of this page:",
"notes": [
"<strong>The AI does not produce events.</strong> Every event is born from a real signal (Health Monitor scan, journal line, PVE webhook, etc.) and is rendered into a templated body before the AI ever sees it. The AI is a translator and re-formatter, not a watcher.",
"<strong>The AI runs per-channel.</strong> Telegram and Discord can use a brief rewrite while Email gets a detailed report — same event, different shape, all from one provider call per channel.",
"<strong>Failure is silent.</strong> If the provider 5xx's, times out, returns malformed output or rejects the request, the dispatcher logs the error and falls back to the original templated body for that channel. You never lose a notification because the LLM had a bad day."
]
},
"enabling": {
"heading": "Enabling the panel",
"intro": "The AI configuration lives at the bottom of the Notifications panel inside the Settings tab, as a collapsible <em>Advanced: AI Enhancement</em> block. Click the header to expand:",
"collapsedAlt": "Collapsed Advanced AI Enhancement header with chevron indicator",
"collapsedCaption": "Collapsed by default — one click expands the panel.",
"panelAlt": "Expanded AI Enhancement panel showing AI-Enhanced Messages master toggle, Provider Google Gemini, API Key masked, Model gemini-2.5-flash, Prompt Mode Default, Language English, Detail Level per Channel for Telegram Discord Gotify Email, AI Suggestions toggle and Test Connection button",
"panelCaption": "The full AI Enhancement panel — every control documented in this page maps to one of the fields above.",
"outro": "Top to bottom, the panel exposes: the <em>AI-Enhanced Messages</em> master toggle, the provider selector with an information modal next to it, the API key input (or Ollama URL for local mode), the model dropdown (loaded from the provider after entering the key), the prompt mode (<em>Default</em> / <em>Custom</em>), the output language, the per-channel detail level, the <em>AI Suggestions</em> opt-in, and a <em>Test Connection</em> button that sends a probe message to the provider to validate the credentials."
},
"context": {
"heading": "What context the AI receives",
"intro": "Before the prompt is built, the dispatcher walks a context-enrichment routine that decides which extra signals are relevant to the event at hand. The aim is to give the LLM enough information to produce a useful message, without flooding it (and your wallet) with noise that doesn't apply. Five context blocks can be added to the user message:",
"headerBlock": "Block",
"headerWhen": "When it's injected",
"headerWhat": "What it carries",
"rows": [
{
"block": "System uptime",
"when": "Only for critical system-level failures: <code>crash</code>, <code>panic</code>, <code>oom</code>, <code>kernel</code>, <code>split_brain</code>, <code>quorum_lost</code>, <code>node_offline</code>, <code>node_fail</code>, <code>system_fail</code>, <code>boot_fail</code>. Skipped for disk errors, warnings and routine operations to keep the prompt tight.",
"what": "A line such as <code>System uptime: 14 days (stable system)</code>. Lets the LLM distinguish startup issues from long-running failures."
},
{
"block": "Event frequency",
"when": "Always, when the Monitor has seen the same fingerprint before.",
"what": "Occurrence count, first-seen timestamp, optional pattern label (recurring / one-off / spike). The LLM uses this to phrase \"recurring issue\" vs \"first time seen\"."
},
{
"block": "SMART data",
"when": "Only for disk-related events (event type contains <code>disk</code>, <code>smart</code>, <code>storage</code>, <code>io_error</code>, or the body mentions <code>/dev/sd</code>, <code>ata</code>, <code>i/o error</code>).",
"what": "Output of <code>smartctl</code> for the affected device — overall health (PASSED / FAILED) plus the relevant attributes for the failure mode."
},
{
"block": "Known errors DB",
"when": "When the body or journal context matches a Proxmox-specific error pattern shipped with the Monitor.",
"what": "A <code>KNOWN PROXMOX ERROR DETECTED</code> block with the matched cause and a concrete solution. The prompt instructs the LLM to translate this verbatim — no paraphrasing of the recommended fix."
},
{
"block": "Journal logs",
"when": "Whenever the originating collector captured journal lines for the event (mostly the journal watcher and the task watcher).",
"what": "Raw <code>journalctl</code> excerpts. The prompt tells the LLM to extract IDs, timestamps and root-cause hints, and to ignore unrelated entries."
}
],
"afterBlocks": "Once these blocks are joined, the user message sent to the LLM has this shape:",
"calloutTitle": "No telemetry beyond the event itself",
"calloutBody": "The Monitor only sends what it has on hand for the current event — no system-wide telemetry, no historical metric series, no inventory dumps. The five blocks above are the upper bound of what leaves the host on a single AI rewrite."
},
"tokens": {
"heading": "Tokens — what they are and how they're consumed",
"intro1": "Every commercial provider charges per <em>token</em>, so it's worth understanding what a token is before picking a plan. A token is roughly four characters of English text or about three quarters of a word. The phrase <em>\"Backup completed on storage local-bak\"</em> is around eight tokens. A short journal excerpt of ten lines can be 200-400 tokens depending on the technical density.",
"intro2": "Two things are billed on every call:",
"items": [
"<strong>Input tokens</strong> — the system prompt plus the user message (severity, title, body, enriched context). For ProxMenux the system prompt alone is on the order of 1.5-2 KB (≈ 400-500 tokens) and the user message varies from 50 tokens (a clean backup-complete) to ~1500 tokens (a disk error with 30 lines of journal context).",
"<strong>Output tokens</strong> — what the model writes back. The Monitor caps this with <code>max_tokens</code> (see the table below). The cap is a <em>limit</em>, not a charge: if the model produces 250 tokens with a cap of 1500, you pay for 250."
],
"capsIntro": "These are the actual caps the dispatcher applies, taken straight from <code>AI_DETAIL_TOKENS</code> in <code>notification_templates.py</code>:",
"headerLevel": "Detail level",
"headerCap": "Output cap (tokens)",
"headerConsumption": "Typical real consumption",
"capRows": [
{
"level": "brief",
"cap": "500",
"consumption": "50-200 output tokens for short events."
},
{
"level": "standard",
"cap": "1500",
"consumption": "200-700 output tokens for typical events with light context."
},
{
"level": "detailed",
"cap": "3000",
"consumption": "500-2000 output tokens for full email reports with logs and SMART tables."
}
],
"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": "A homelab with 50-100 events per day on <code>standard</code> typically consumes a few thousand tokens per day. With the free tiers offered by Groq and Gemini, that fits without touching a paid plan. With OpenAI or Anthropic, billed per-token, the cost lands in the cents-per-month range for that volume. If your event count is much higher, the <link>Detail level per channel</link> section explains how to keep chat channels on <code>brief</code> while letting Email take the full report."
},
"providers": {
"heading": "AI providers",
"intro": "Six providers are wired into the Monitor. The provider dropdown in the UI shows them all; an information button next to it opens a modal with a one-line description for each. Below is the full reference, with the URL for getting an API key, the description shown in the UI and the relevant notes from the codebase.",
"imageAlt": "AI Providers Information modal listing the six supported providers — Groq, OpenAI, Anthropic Claude, Google Gemini, Ollama, OpenRouter — each with its icon and one-line description, and a special OpenAI-Compatible APIs note for OpenAI",
"imageCaption": "The in-app modal — six cards, one per provider, with the same descriptions documented below.",
"groq": {
"heading": "Groq",
"tagline": "Very fast, generous free tier (30 req/min). Ideal to start.",
"items": [
"API key: <a>console.groq.com/keys</a>",
"Verified models: <code>llama-3.3-70b-versatile</code>, <code>llama-3.1-70b-versatile</code>, <code>llama-3.1-8b-instant</code>, <code>llama3-70b-8192</code>, <code>llama3-8b-8192</code>, <code>mixtral-8x7b-32768</code>, <code>gemma2-9b-it</code>.",
"Recommended: <strong><code>llama-3.3-70b-versatile</code></strong> — best quality at full Groq inference speed."
]
},
"openai": {
"heading": "OpenAI",
"tagline": "Industry standard. Very accurate and widely used.",
"items": [
"API key: <a>platform.openai.com/api-keys</a>",
"Verified models: <code>gpt-4.1-nano</code>, <code>gpt-4.1-mini</code>, <code>gpt-4o-mini</code>, <code>gpt-4.1</code>, <code>gpt-4o</code>, <code>gpt-5-chat-latest</code>, <code>gpt-5.4-nano</code>, <code>gpt-5.4-mini</code>.",
"Recommended: <strong><code>gpt-4.1-nano</code></strong> — the cheapest member of the chat family, sufficient quality for translation and re-formatting. Reasoning models (o-series, gpt-5 non-chat) are supported by the provider plumbing but kept off the verified list: higher latency without measurable quality gain on this workload."
],
"baseUrlTitle": "OpenAI-compatible base URL",
"baseUrlBody": "The OpenAI provider also accepts a custom <em>Base URL</em>, which lets you point the Monitor at any OpenAI-compatible endpoint. Confirmed to work with <strong>BytePlus / ByteDance (Kimi K2.5)</strong>, <strong>LocalAI</strong>, <strong>LM Studio</strong>, <strong>vLLM</strong>, <strong>Together AI</strong>, <strong>Fireworks AI</strong>, and any other service that speaks the OpenAI <code>/v1/chat/completions</code> dialect. Set the URL in the OpenAI tab next to the API key field."
},
"anthropic": {
"heading": "Anthropic (Claude)",
"tagline": "Excellent for writing and translation. Fast and economical.",
"items": [
"API key: <a>console.anthropic.com/settings/keys</a>",
"Verified models: <code>claude-3-5-haiku-latest</code>, <code>claude-3-5-sonnet-latest</code>, <code>claude-3-opus-latest</code>.",
"Recommended: <strong><code>claude-3-5-haiku-latest</code></strong> — Claude's smallest, fastest model with strong language quality for the translation workload."
]
},
"gemini": {
"heading": "Google Gemini",
"tagline": "Free tier available, great quality/price ratio.",
"items": [
"API key: <a>aistudio.google.com/app/apikey</a>",
"Verified models: <code>gemini-2.5-flash-lite</code>, <code>gemini-2.5-flash</code>, <code>gemini-3-flash-preview</code>.",
"Recommended: <strong><code>gemini-2.5-flash-lite</code></strong> — flash and flash-lite pass the verifier consistently. The pro variants reject the <code>thinkingBudget=0</code> setting the Monitor uses and are overkill for this workload."
]
},
"openrouter": {
"heading": "OpenRouter",
"tagline": "Aggregator with access to 100+ models using a single API key. Maximum flexibility.",
"items": [
"API key: <a>openrouter.ai/keys</a>",
"Verified models: <code>meta-llama/llama-3.3-70b-instruct</code>, <code>meta-llama/llama-3.1-70b-instruct</code>, <code>meta-llama/llama-3.1-8b-instruct</code>, <code>anthropic/claude-3.5-haiku</code>, <code>anthropic/claude-3.5-sonnet</code>, <code>google/gemini-flash-1.5</code>, <code>openai/gpt-4o-mini</code>, <code>mistralai/mistral-7b-instruct</code>, <code>mistralai/mixtral-8x7b-instruct</code>.",
"Recommended: <strong><code>meta-llama/llama-3.3-70b-instruct</code></strong> — same model as the Groq entry but routed through OpenRouter, which means a single key for all the listed models."
]
},
"ollama": {
"heading": "Ollama (Local)",
"tagline": "Uses models available on your Ollama server. 100% local, no costs, total privacy.",
"items": [
"No API key. Set the <em>Ollama URL</em> field to your server (default <code>http://localhost:11434</code> or whatever host runs your Ollama instance).",
"Models: <strong>not filtered.</strong> The Monitor reads whichever models you have pulled on the Ollama side via <code>ollama pull &lt;model&gt;</code>. The dropdown is populated from <code>GET /api/tags</code> on your Ollama server.",
"Install: <a>ollama.com/download</a> — runs on Linux, macOS, Windows. For best results pick a model that fits in RAM with a large enough context window for the journal blocks the dispatcher injects."
]
}
},
"models": {
"heading": "Why these specific models",
"intro": "The model dropdown for each commercial provider is populated from a curated list shipped with the Monitor (<code>verified_ai_models.json</code>). Models on this list have been tested end-to-end with the chat / completions API format the Monitor uses, with the exact <code>system_prompt + user_message + max_tokens</code> shape the AI Enhancer sends. The list is refreshed before each ProxMenux release with a private verifier tool that probes every candidate model and prunes the ones that misbehave.",
"consequencesIntro": "Two consequences worth being aware of:",
"consequences": [
"<strong>The recommended model</strong> for each provider is the one that has the best balance of quality, latency and cost for notification translation specifically — not the most capable model the provider sells. Notification rewrites don't need frontier-model reasoning; they need fast and cheap.",
"<strong>You can still pick another verified model</strong> from the dropdown — sometimes you have a free-tier quota you want to spend on a particular model, or you have a strong preference. Pick any of the listed entries; they've all passed the verifier."
],
"ollamaTitle": "Ollama is the exception",
"ollamaBody": "Ollama models are local and the Monitor doesn't filter them — the dropdown reflects whatever you have pulled. Pick a model in the 7B-13B range with at least an 8K context window for the AI rewrite to behave reasonably with the journal context blocks."
},
"defaultPrompt": {
"heading": "Default prompt",
"intro": "With prompt mode set to <em>Default</em>, the Monitor uses the system prompt below. The prompt is templated at runtime: <code>'{'language'}'</code>, <code>'{'detail_level'}'</code>, <code>'{'emoji_instructions'}'</code> and <code>'{'suggestions_addon'}'</code> are replaced before the call. The variants for rich vs plain channels and the AI Suggestions addon are shown immediately after.",
"showFullSummary": "Show full default system prompt",
"passagesIntro": "Two passages in the prompt above are placeholders that get swapped depending on the per-channel <em>Rich messages</em> toggle:",
"passages": [
"<strong>Rich on</strong> → an emoji block is injected listing the icons the LLM may use, plus a hostname rule (the LLM must keep the hostname prefix from the title verbatim) and a handful of formatted examples (backup start, backup complete, updates, VM start, health degraded). This is what produces the emoji-prefixed messages on Telegram and Discord.",
"<strong>Rich off</strong> → a one-line block tells the LLM to use plain ASCII only — no emojis, no Unicode symbols. Used for email and any channel where formatting noise hurts inbox rules or readability."
],
"suggestionsPlaceholder": "And the <code>'{'suggestions_addon'}'</code> placeholder is empty unless you enable AI Suggestions (next section), in which case this block gets injected:",
"showAddonSummary": "Show AI Suggestions addon"
},
"customPrompt": {
"heading": "Custom prompt mode",
"intro": "Switching the prompt mode to <em>Custom</em> swaps the entire default system prompt for one you write yourself. The custom prompt is stored in the Monitor's SQLite settings and sent verbatim on every AI rewrite call. It's the right escape hatch when you want a completely different voice, structure or focus than the bundled prompt offers.",
"imageAlt": "Custom Prompt mode showing a textarea with translation rules and Export Import buttons plus a Community prompts link",
"imageCaption": "Custom Prompt — large textarea with the user's prompt, plus <em>Export</em>, <em>Import</em> and a link to the community gallery on GitHub.",
"changesTitle": "What changes when Custom is on",
"changes": [
"<strong>The default prompt is replaced entirely.</strong> The Proxmox mappings, the context-handling rules and the emoji instructions are all gone. If you want to keep any of them, paste them into your prompt — the bundled <code>EXAMPLE_CUSTOM_PROMPT</code> shown below is a starting point.",
"<strong>The Language selector is ignored.</strong> The default prompt has a <code>'{'language'}'</code> placeholder; the custom prompt does not. If you want output in a specific language, declare it inside your prompt (\"Translate to Spanish\", \"Output everything in French\").",
"<strong>Detail level still applies</strong> in the sense that it's available as a setting per channel, but the cap on output tokens becomes a fixed 500 in custom mode (vs the 500 / 1500 / 3000 ramp of the default prompt). If your custom prompt asks for a long report, raise the cap by editing the prompt or split the request.",
"<strong>The Output Format markers are still mandatory.</strong> The Monitor parses the response by looking for <code>[TITLE]</code> and <code>[BODY]</code> on their own lines. A custom prompt that doesn't emit those markers will break the parser and fall back to the original templated body.",
"<strong>Rich messages emoji rules are not auto-injected.</strong> If you want emojis, tell the prompt to use them. If you want plain text, tell it not to. The toggle only gates the bundled blocks of the default prompt, not your custom string."
],
"starterTitle": "Starter prompt",
"starterIntro": "The <em>Custom Prompt</em> textarea ships pre-filled with a minimal example you can adapt:",
"showStarterSummary": "Show starter custom prompt",
"shareTitle": "Sharing prompts with the community",
"shareIntro": "The <em>Export</em> button writes your current custom prompt to a file (<code>.txt</code> / <code>.md</code>) you can keep as a backup or hand to someone else. <em>Import</em> pulls one back in. The third button next to them links to a public community gallery on GitHub:",
"shareLinkLabel": "github.com/MacRimi/ProxMenux/discussions — Share custom prompts for AI notifications",
"shareOutro": "Browse the discussion to see what other operators have built — terse pager-style alerts, verbose technical reports, language-specific variants. If you tweak yours and like the result, post it there: even a one-paragraph description of what your prompt optimises for helps people pick a good starting point. Feedback on what works and what doesn't is equally welcome."
},
"suggestions": {
"heading": "AI Suggestions (BETA)",
"intro": "AI Suggestions is an opt-in addon that lets the LLM append <strong>one</strong> short, actionable tip at the end of the body. It only activates when the prompt mode is <em>Default</em>, the master AI toggle is on, and the <em>AI Suggestions</em> switch is flipped — and even then, the prompt instructs the model to skip the tip whenever the cause or solution is unclear.",
"formatIntro": "When a tip is added, it follows this exact format:",
"rulesIntro": "The rules baked into the addon (visible in the collapsible block under the Default prompt section above):",
"rules": [
"The tip is included <em>only</em> if the journal context or the Known Errors database clearly points to a specific fix.",
"The tip is capped at 100 characters.",
"It must be specific (concrete command or path) — generic advice is rejected by the prompt itself.",
"If a Known Error provides a solution, the LLM must use that solution, not invent a new one.",
"If nothing in the input gives the LLM enough certainty to suggest a concrete fix, the tip is skipped — no guessing."
],
"betaTitle": "Why BETA",
"betaBody": "Tip quality depends on two things outside of ProxMenux: the model picked, and how rich the journal context for the event was. With a strong model (Claude 3.5 Haiku, GPT-4.1 Mini, Llama 3.3 70B) and a disk error that comes with smartctl + journal lines, the tip is consistently useful. With a tiny local Ollama model and a one-line event, the tip can fall flat or get skipped entirely. Disable the toggle if you find the tips noisy and re-enable it when you want it back."
},
"detailLevel": {
"heading": "Detail level per channel",
"intro": "Each of the four channels (Telegram, Discord, Gotify, Email) has its own detail-level dropdown. Three values are available, mapped to specific output token caps and to specific instructions in the default prompt:",
"headerLevel": "Level",
"headerLabel": "UI label",
"headerCap": "Output cap",
"headerProduce": "What the prompt asks the LLM to produce",
"rows": [
{
"level": "brief",
"label": "2-3 lines, essential only",
"cap": "500 tokens",
"produce": "\"What happened + where\". Nothing else."
},
{
"level": "standard",
"label": "Concise with basic context",
"cap": "1500 tokens",
"produce": "3-6 lines: what, where, cause, affected devices."
},
{
"level": "detailed",
"label": "Complete technical details",
"cap": "3000 tokens",
"produce": "Full report: what, where, cause, affected, logs, SMART data, history."
}
],
"defaultsIntro": "Defaults the Monitor applies on first install:",
"defaults": [
"<strong>Telegram, Discord, Gotify</strong> — <code>standard</code>.",
"<strong>Email</strong> — <code>detailed</code>. Email is the channel where you typically want the full picture for archival."
],
"emailTitle": "Email detail level appends the original",
"emailBody": "When Email is on <code>detailed</code> and the original templated body has substantial content (more than 50 characters), the dispatcher appends the original message at the bottom of the AI rewrite, separated by a 40-dash divider and an <code>Original message:</code> label. This means a detailed email always carries both the AI-friendly version and the machine-friendly raw template — useful when you want to grep an old alert later."
},
"language": {
"heading": "Language",
"intro": "Twelve languages are wired in. The dropdown sets <code>ai_language</code> in the config and the value is interpolated into the system prompt at the place where the prompt says <em>\"translate alerts into '{'language'}'\"</em>. The full list:",
"list": "English (<code>en</code>), Spanish (<code>es</code>), French (<code>fr</code>), German (<code>de</code>), Portuguese (<code>pt</code>), Italian (<code>it</code>), Russian (<code>ru</code>), Swedish (<code>sv</code>), Norwegian (<code>no</code>), Japanese (<code>ja</code>), Chinese (<code>zh</code>), Dutch (<code>nl</code>).",
"rulesIntro": "Two important rules taken straight from the prompt:",
"rules": [
"<strong>Translate</strong>: labels, descriptions, status words, units (e.g. GB → Go in French).",
"<strong>Do not translate</strong>: hostnames, IPs, paths, VM/CT IDs, device names like <code>/dev/sdX</code>, technical identifiers. These stay verbatim regardless of language."
],
"customNote": "Custom prompt mode <strong>does not use</strong> the Language selector. If you switch to Custom and want a specific output language, declare it inside your prompt."
},
"templates": {
"heading": "A note on templates",
"body1": "The body the AI receives is not raw event data — it's a pre-rendered template. Each event type (<code>backup_complete</code>, <code>vm_start</code>, <code>auth_fail</code>, <code>health_degraded</code>, etc.) has a template in <code>notification_templates.py</code> that knows how to format that specific event into a structured plain-text body. The AI rewrites that body, it doesn't replace the templating step.",
"body2": "Two practical implications: the AI never sees a hostname or VMID it has to invent — those fields are placed by the template before the rewrite. And if AI is disabled, the templated body is what gets dispatched directly. The <link>Notifications</link> page documents the dispatch pipeline in full and is the right cross-reference for everything that happens to an event before it reaches this layer."
},
"privacy": {
"heading": "Privacy & data flow",
"intro": "With AI rewrite enabled, the Monitor sends the rendered notification body plus the enriched context blocks to the configured provider. That can include hostnames, IPs, usernames, device paths, journal log lines and SMART attributes for the affected device. Whether that leaves the host depends on which provider you chose:",
"headerProvider": "Provider",
"headerDestination": "Data destination",
"rows": [
{
"provider": "Ollama",
"destination": "Stays on the Ollama host. If Ollama runs on the same Proxmox node, nothing leaves the network at all."
},
{
"provider": "OpenAI",
"destination": "<code>api.openai.com</code> (or your custom Base URL endpoint). Subject to OpenAI's data-handling policy at the time of the call."
},
{
"provider": "Anthropic",
"destination": "<code>api.anthropic.com</code>."
},
{
"provider": "Google Gemini",
"destination": "<code>generativelanguage.googleapis.com</code>."
},
{
"provider": "Groq",
"destination": "<code>api.groq.com</code>."
},
{
"provider": "OpenRouter",
"destination": "<code>openrouter.ai</code>, which forwards to the underlying model provider chosen in the <code>model</code> field. Two hops instead of one."
}
],
"calloutTitle": "If event content cannot leave the network",
"calloutBody": "Use Ollama, or disable the AI rewriter. There is no middle ground — the dispatcher does not try to redact hostnames or IPs before sending; the prompt is built from the actual event payload as the Monitor sees it."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — the dispatch pipeline, channels, per-event toggles and the PVE webhook integration that surrounds this layer."
},
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the largest single producer of events the AI ends up rewriting, with its own per-category suppression durations."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tail": " — where the AI Enhancer fits into the wider Monitor process (it's a module, not a separate service)."
}
],
"communityLabel": "Community prompts on GitHub",
"communityTail": " — browse, share, ask."
}
}
@@ -0,0 +1,681 @@
{
"meta": {
"title": "Proxmox Monitor API — Integration Reference | ProxMenux",
"description": "HTTP endpoints exposed by ProxMenux Monitor for integrations: Home Assistant, Homepage, Grafana, Prometheus, n8n and custom dashboards. Read-only data export plus the safe write operations needed by automations — VM control, backup trigger, notification dispatch, alert acknowledgement.",
"ogTitle": "Proxmox Monitor API — Integration Reference",
"ogDescription": "Endpoints exposed by ProxMenux Monitor for Home Assistant, Homepage, Grafana, Prometheus, n8n and custom dashboards.",
"twitterTitle": "Proxmox Monitor API | ProxMenux",
"twitterDescription": "Endpoints for Home Assistant, Homepage, Grafana, Prometheus, n8n and custom dashboards."
},
"header": {
"title": "API Reference",
"description": "The HTTP endpoints integrators use to read state and trigger safe actions on ProxMenux Monitor — Home Assistant sensors, Homepage cards, Grafana dashboards, Prometheus scrapes, n8n flows and custom scripts. Every category, plus a complete list of Prometheus metrics, with curl examples.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "What this page is for",
"body": "This page lists the endpoints we expect external integrations to use — read-only data export across every part of the Monitor, plus the small set of write operations that automations legitimately need (trigger a backup, send a custom notification, acknowledge an alert). The whole API runs from the same Flask process that serves the dashboard UI on TCP <strong>8008</strong>; bind address and TLS are configured in <link>Access & Authentication</link>."
},
"headerEndpoint": "Endpoint",
"headerMethod": "Method",
"headerUse": "Use",
"auth": {
"heading": "Authentication",
"intro": "Every endpoint marked \"authenticated\" expects a JWT bearer token in the request header:",
"tokensIntro": "Two ways to obtain the token:",
"items": [
"<strong>API tokens (recommended for integrations).</strong> Long-lived tokens minted from <strong>Settings → Security → API Tokens</strong> in the dashboard. Each token is named, can be revoked individually, and is what you should hand to Home Assistant / Homepage / Grafana / n8n.",
"<strong>Login flow (short-lived JWT).</strong> <code>POST /api/auth/login</code> with a username, password and TOTP token if 2FA is enabled. The returned JWT is short-lived and refreshed by the dashboard automatically; useful for ad-hoc scripts that authenticate as a human user."
],
"flowLink": "The auth flow, password policy, 2FA setup, audit log and TLS configuration all live in <link>Access & Authentication</link>.",
"rows": [
{
"endpoint": "/api/auth/login",
"method": "POST",
"use": "Body: <code>'{'\"username\",\"password\",\"totp_token?\"'}'</code>. Returns a short-lived JWT."
},
{
"endpoint": "/api/auth/api-tokens",
"method": "GET",
"use": "List API tokens (metadata only — names, prefixes, dates; never the actual secret)."
},
{
"endpoint": "/api/auth/api-tokens",
"method": "POST",
"use": "Mint a new long-lived API token. Body: <code>'{'\"name\":\"'<'label'>'\"'}'</code>. The token value is returned once and cannot be retrieved again."
},
{
"endpoint": "/api/auth/api-tokens/<id>",
"method": "DELETE",
"use": "Revoke a specific API token by its ID."
}
]
},
"conventions": {
"heading": "Conventions",
"items": [
"All requests and responses are JSON unless explicitly noted (log download is plain text, <code>/api/prometheus</code> is text/plain in the OpenMetrics format, task log is plain text).",
"Successful mutating endpoints return <code>'{'\"success\": true, ...'}'</code>. Error responses use a non-2xx HTTP status with <code>'{'\"success\": false, \"error\": \"'<'reason'>'\"'}'</code>.",
"List endpoints accept optional <code>limit</code>, <code>offset</code>, <code>since</code> and category-specific filters via query string.",
"Time fields are returned as Unix epoch seconds or ISO-8601 with explicit timezone, never as locale strings."
]
},
"system": {
"heading": "System & hardware",
"rows": [
{
"endpoint": "/api/system",
"method": "GET",
"use": "CPU, memory, swap, uptime, load — current snapshot."
},
{
"endpoint": "/api/info",
"method": "GET",
"use": "Static host info: hostname, kernel, PVE version, CPU model, distro."
},
{
"endpoint": "/api/system-info",
"method": "GET",
"use": "Extended system snapshot used by the dashboard header (overall metrics + boot time)."
},
{
"endpoint": "/api/hardware",
"method": "GET",
"use": "Detailed hardware inventory — PCI devices, GPUs, sensors map."
},
{
"endpoint": "/api/hardware/live",
"method": "GET",
"use": "Live values for sensors that change second to second."
},
{
"endpoint": "/api/temperature/history",
"method": "GET",
"use": "Time series of CPU / package temperatures."
},
{
"endpoint": "/api/gpu/<slot>/realtime",
"method": "GET",
"use": "NVIDIA / Intel / AMD GPU live metrics by PCI slot."
}
]
},
"health": {
"heading": "Health Monitor",
"rows": [
{
"endpoint": "/api/health",
"method": "GET",
"use": "Small health probe — returns JSON with <code>status</code>, <code>timestamp</code>, <code>version</code>. Suitable for Uptime Kuma keyword checks; the receiver must send the bearer header."
},
{
"endpoint": "/api/health/status",
"method": "GET",
"use": "Overall health verdict — single severity + summary string."
},
{
"endpoint": "/api/health/details",
"method": "GET",
"use": "All ten categories with per-category statuses and the structured payload that produced each."
},
{
"endpoint": "/api/health/full",
"method": "GET",
"use": "Full snapshot — categories + active errors + dismissed list + custom suppression settings. Backs the modal in one round-trip; uses a 6-min background cache for instant response."
},
{
"endpoint": "/api/health/active-errors",
"method": "GET",
"use": "Active list, filterable by <code>?category=&lt;name&gt;</code>."
},
{
"endpoint": "/api/health/dismissed",
"method": "GET",
"use": "Dismissed list with remaining suppression hours."
},
{
"endpoint": "/api/health/settings",
"method": "GET",
"use": "Per-category Suppression Duration values currently configured."
},
{
"endpoint": "/api/health/remote-storages",
"method": "GET",
"use": "Inventory of Proxmox-defined remote storages, with online state."
},
{
"endpoint": "/api/health/interfaces",
"method": "GET",
"use": "Inventory of network interfaces with type (bridge / bond / physical), IP and link speed."
},
{
"endpoint": "/api/health/acknowledge",
"method": "POST",
"use": "Body: <code>'{'\"error_key\":\"smart_sdh\"'}'</code>. Dismiss an alert with the category's configured Suppression Duration."
},
{
"endpoint": "/api/health/cleanup-orphans",
"method": "POST",
"use": "Manual cleanup of errors whose underlying device or VM is gone. Idempotent."
}
],
"outro": "Response shapes and the semantics of the categories live in <link>Health Monitor</link>."
},
"storage": {
"heading": "Storage",
"rows": [
{
"endpoint": "/api/storage",
"method": "GET",
"use": "All disks visible to the host (block devices, ZFS pools, LVM)."
},
{
"endpoint": "/api/storage/summary",
"method": "GET",
"use": "Compact summary used by dashboard cards."
},
{
"endpoint": "/api/proxmox-storage",
"method": "GET",
"use": "Proxmox-defined storages from <code>/etc/pve/storage.cfg</code> with online state and free space."
},
{
"endpoint": "/api/storage/observations",
"method": "GET",
"use": "Permanent disk observation history — SMART warnings, I/O errors, ZFS pool events, kept across error auto-resolves."
},
{
"endpoint": "/api/storage/smart/<disk>",
"method": "GET",
"use": "Current SMART attributes for one disk."
},
{
"endpoint": "/api/storage/smart/<disk>/latest",
"method": "GET",
"use": "Most recent SMART self-test for the disk."
},
{
"endpoint": "/api/storage/smart/<disk>/history",
"method": "GET",
"use": "List of stored SMART reports for the disk."
},
{
"endpoint": "/api/storage/smart/<disk>/history/<file>",
"method": "GET",
"use": "Read a specific stored SMART report."
},
{
"endpoint": "/api/storage/smart/<disk>/test",
"method": "POST",
"use": "Trigger a SMART self-test. Body: <code>'{'\"type\":\"short\"|\"long\"'}'</code>."
},
{
"endpoint": "/api/storage/smart/schedules",
"method": "GET",
"use": "List the currently scheduled SMART tests."
},
{
"endpoint": "/api/storage/smart/tools",
"method": "GET",
"use": "Detect whether <code>smartctl</code> and friends are installed."
}
]
},
"network": {
"heading": "Network",
"rows": [
{
"endpoint": "/api/network",
"method": "GET",
"use": "All interfaces with link state and addresses."
},
{
"endpoint": "/api/network/summary",
"method": "GET",
"use": "Compact view used by the dashboard."
},
{
"endpoint": "/api/network/<iface>/metrics",
"method": "GET",
"use": "Per-interface RX / TX, error counters, RRD time series."
},
{
"endpoint": "/api/network/latency/current",
"method": "GET",
"use": "Latest gateway latency probe."
},
{
"endpoint": "/api/network/latency/history",
"method": "GET",
"use": "Time series of gateway latency."
}
]
},
"vms": {
"heading": "VMs & containers",
"rows": [
{
"endpoint": "/api/vms",
"method": "GET",
"use": "List of all VMs and CTs with status, vmid, name."
},
{
"endpoint": "/api/vms/<vmid>",
"method": "GET",
"use": "Full detail for one guest (config, network, disks)."
},
{
"endpoint": "/api/vms/<vmid>/metrics",
"method": "GET",
"use": "CPU / memory / disk I/O time series for one guest (RRD)."
},
{
"endpoint": "/api/vms/<vmid>/logs",
"method": "GET",
"use": "Recent task logs scoped to that guest."
},
{
"endpoint": "/api/vms/<vmid>/backups",
"method": "GET",
"use": "List backups currently held for this guest."
},
{
"endpoint": "/api/vms/<vmid>/control",
"method": "POST",
"use": "Body: <code>'{'\"action\":\"start|stop|reboot|shutdown\"'}'</code>. Power-cycle a guest."
},
{
"endpoint": "/api/vms/<vmid>/backup",
"method": "POST",
"use": "Trigger <code>vzdump</code> for that guest. Body chooses storage and mode (<code>snapshot</code> / <code>suspend</code> / <code>stop</code>)."
},
{
"endpoint": "/api/vms/<vmid>/config",
"method": "PUT",
"use": "Update the description (notes) field of a VM / CT. Other config keys are not modifiable from this endpoint."
},
{
"endpoint": "/api/node/metrics",
"method": "GET",
"use": "Aggregated node-level metrics (RRD)."
}
]
},
"backups": {
"heading": "Backups",
"rows": [
{
"endpoint": "/api/backups",
"method": "GET",
"use": "Cluster-wide list of backups."
},
{
"endpoint": "/api/backup-storages",
"method": "GET",
"use": "Storages flagged as backup targets, with free space."
}
]
},
"logs": {
"heading": "Logs, tasks, events",
"rows": [
{
"endpoint": "/api/logs",
"method": "GET",
"use": "Filtered journal entries. Query: <code>?level=&service=&limit=</code>."
},
{
"endpoint": "/api/logs/download",
"method": "GET",
"use": "Plain-text dump of the filtered range."
},
{
"endpoint": "/api/events",
"method": "GET",
"use": "Internal event stream — the same one that feeds notifications."
},
{
"endpoint": "/api/task-log/<upid>",
"method": "GET",
"use": "Plain-text complete log for one Proxmox task by UPID."
}
]
},
"notifications": {
"heading": "Notifications & AI",
"intro": "The dispatch pipeline, channel walk-throughs and AI rewriter setup live in <notifLink>Notifications</notifLink> and <aiLink>AI Assistant</aiLink>.",
"rows": [
{
"endpoint": "/api/notifications",
"method": "GET",
"use": "Recent notifications surfaced in the dashboard."
},
{
"endpoint": "/api/notifications/download",
"method": "GET",
"use": "Export notifications as text."
},
{
"endpoint": "/api/notifications/status",
"method": "GET",
"use": "Dispatcher status — whether the background thread is running, queue depth, last send."
},
{
"endpoint": "/api/notifications/settings",
"method": "GET",
"use": "Read the full notification config (channels, per-event toggles, AI rewriter, Display Name)."
},
{
"endpoint": "/api/notifications/history",
"method": "GET",
"use": "Dispatch history. Query: <code>?limit=&offset=&severity=&channel=</code>."
},
{
"endpoint": "/api/notifications/history",
"method": "DELETE",
"use": "Wipe the dispatch history table."
},
{
"endpoint": "/api/notifications/test",
"method": "POST",
"use": "Send a test notification to one channel. Body: <code>'{'\"channel\":\"telegram\"'}'</code>."
},
{
"endpoint": "/api/notifications/send",
"method": "POST",
"use": "Emit a custom event. Body: <code>'{'\"event_type\":\"custom\",\"severity\":\"WARNING\",\"title\":\"...\",\"body\":\"...\",\"data\":'{''}''}'</code>."
},
{
"endpoint": "/api/notifications/test-ai",
"method": "POST",
"use": "Test the AI provider connection. Body: <code>'{'\"provider\",\"api_key\",\"model\",\"ollama_url?\"'}'</code>."
},
{
"endpoint": "/api/notifications/provider-models",
"method": "POST",
"use": "List available models for the selected AI provider."
},
{
"endpoint": "/api/notifications/proxmox/setup-webhook",
"method": "POST",
"use": "Register the Monitor as a webhook target in <code>/etc/pve/notifications.cfg</code>."
},
{
"endpoint": "/api/notifications/proxmox/cleanup-webhook",
"method": "POST",
"use": "Remove the Monitor target from PVE's notification config."
},
{
"endpoint": "/api/notifications/proxmox/read-cfg",
"method": "GET",
"use": "Read PVE's current <code>notifications.cfg</code> as PVE sees it."
}
]
},
"security": {
"heading": "Security (read)",
"rows": [
{
"endpoint": "/api/security/firewall/status",
"method": "GET",
"use": "PVE firewall state and active rules."
},
{
"endpoint": "/api/security/fail2ban/details",
"method": "GET",
"use": "Fail2Ban jail status — only useful when the optional jail is installed."
},
{
"endpoint": "/api/security/fail2ban/activity",
"method": "GET",
"use": "Recent Fail2Ban events (bans, unbans, jail starts)."
},
{
"endpoint": "/api/security/lynis/status",
"method": "GET",
"use": "Lynis last-run status (whether installed, last scan timestamp)."
},
{
"endpoint": "/api/security/lynis/report",
"method": "GET",
"use": "Latest Lynis audit report (warnings, suggestions, hardening index)."
},
{
"endpoint": "/api/security/tools",
"method": "GET",
"use": "Detect which optional security tools (Fail2Ban, Lynis) are installed."
}
]
},
"proxmenuxIntegration": {
"heading": "ProxMenux integration",
"rows": [
{
"endpoint": "/api/proxmenux/update-status",
"method": "GET",
"use": "Whether ProxMenux Monitor has an update available, current and latest version."
},
{
"endpoint": "/api/proxmenux/installed-tools",
"method": "GET",
"use": "List of every ProxMenux post-install optimization currently registered on the host (from <code>/usr/local/share/proxmenux/installed_tools.json</code>)."
},
{
"endpoint": "/api/proxmenux/tool-source/<key>",
"method": "GET",
"use": "Source code of a specific post-install function — the exact bash that was applied."
}
]
},
"prometheus": {
"heading": "Prometheus metrics",
"intro": "ProxMenux Monitor exposes a Prometheus-format scrape endpoint at <code>GET /api/prometheus</code> (authenticated) returning OpenMetrics-format text. Every metric is labelled with <code>node=\"&lt;hostname&gt;\"</code> and carries an explicit timestamp so it ingests cleanly into Prometheus, VictoriaMetrics, Mimir or any compatible TSDB.",
"exportedTitle": "Exported metrics",
"headerGroup": "Group",
"headerMetric": "Metric",
"headerDesc": "Description",
"groups": [
{
"group": "System",
"metrics": [
{
"metric": "proxmox_cpu_usage",
"desc": "CPU usage percentage (gauge)."
},
{
"metric": "proxmox_memory_total_bytes",
"desc": "Total physical memory in bytes."
},
{
"metric": "proxmox_memory_used_bytes",
"desc": "Used memory in bytes."
},
{
"metric": "proxmox_memory_usage_percent",
"desc": "Memory usage percentage."
},
{
"metric": "proxmox_load_average",
"desc": "System load average. Label <code>period=\"1m\" | \"5m\" | \"15m\"</code>."
}
]
},
{
"group": "Uptime",
"metrics": [
{
"metric": "proxmox_uptime_seconds",
"desc": "Seconds since last boot."
}
]
},
{
"group": "Hardware",
"metrics": [
{
"metric": "proxmox_cpu_temperature_celsius",
"desc": "CPU package temperature."
},
{
"metric": "proxmox_disk_temperature_celsius",
"desc": "Per-disk temperature. Label <code>device</code>."
},
{
"metric": "proxmox_fan_speed_rpm",
"desc": "Fan speeds. Label <code>fan</code>."
}
]
},
{
"group": "Disk space",
"metrics": [
{
"metric": "proxmox_disk_total_bytes",
"desc": "Total disk space per mount. Label <code>mountpoint</code>."
},
{
"metric": "proxmox_disk_used_bytes",
"desc": "Used disk space per mount."
},
{
"metric": "proxmox_disk_usage_percent",
"desc": "Disk usage percentage per mount."
}
]
},
{
"group": "Network",
"metrics": [
{
"metric": "proxmox_network_bytes_sent_total",
"desc": "Total bytes sent (counter)."
},
{
"metric": "proxmox_network_bytes_received_total",
"desc": "Total bytes received (counter)."
},
{
"metric": "proxmox_interface_bytes_sent_total",
"desc": "Per-interface bytes sent. Label <code>interface</code>."
},
{
"metric": "proxmox_interface_bytes_received_total",
"desc": "Per-interface bytes received."
}
]
},
{
"group": "VMs / CTs",
"metrics": [
{
"metric": "proxmox_vms_total",
"desc": "Total number of VMs and LXCs."
},
{
"metric": "proxmox_vms_running",
"desc": "Number of running guests."
},
{
"metric": "proxmox_vms_stopped",
"desc": "Number of stopped guests."
},
{
"metric": "proxmox_vm_status",
"desc": "Per-VM/CT status (1 = running, 0 = stopped). Labels <code>vmid</code>, <code>name</code>, <code>type</code>."
},
{
"metric": "proxmox_vm_cpu_usage",
"desc": "Per-VM/CT CPU usage. Same labels."
},
{
"metric": "proxmox_vm_memory_used_bytes / _max_bytes",
"desc": "Per-VM/CT memory used and configured maximum."
}
]
},
{
"group": "GPU",
"metrics": [
{
"metric": "proxmox_gpu_temperature_celsius",
"desc": "GPU temperature. Labels <code>slot</code>, <code>vendor</code>."
},
{
"metric": "proxmox_gpu_utilization_percent",
"desc": "GPU utilization percentage."
},
{
"metric": "proxmox_gpu_memory_total_bytes",
"desc": "GPU memory total."
},
{
"metric": "proxmox_gpu_power_draw_watts",
"desc": "GPU power draw in watts."
},
{
"metric": "proxmox_gpu_clock_speed_mhz",
"desc": "GPU core clock speed."
},
{
"metric": "proxmox_gpu_memory_clock_mhz",
"desc": "GPU memory clock speed."
}
]
},
{
"group": "UPS",
"metrics": [
{
"metric": "proxmox_ups_battery_charge_percent",
"desc": "Battery charge percentage."
},
{
"metric": "proxmox_ups_load_percent",
"desc": "Current load on the UPS."
},
{
"metric": "proxmox_ups_runtime_seconds",
"desc": "Estimated runtime on battery."
},
{
"metric": "proxmox_ups_input_voltage_volts",
"desc": "Input voltage."
}
]
}
],
"scrapeTitle": "Prometheus scrape config",
"scrapeIntro": "The endpoint requires authentication. Pass the API token as a bearer header in your Prometheus scrape config:",
"perHostTitle": "Per-host scrape",
"perHostBody": "Each ProxMenux Monitor instance exports metrics for the host it runs on. In a cluster, point Prometheus at every node — the <code>node</code> label on every series lets you distinguish them in Grafana queries (<code>proxmox_vms_running'{'node=\"pve01\"'}'</code>)."
},
"puttingItTogether": {
"heading": "Putting it together",
"body": "For end-to-end recipes wiring these endpoints into Home Assistant sensors, Homepage cards, Grafana dashboards, n8n flows and other tools, see the dedicated <link>Integrations</link> page — it walks through the typical setup for each platform with copy-paste configuration. This page stays focused on the catalogue itself."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — minting tokens, the audit log, the optional Fail2Ban jail, TLS configuration."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tailRich": " — what each event type carries in <code>data</code> when you call <code>/api/notifications/send</code>."
},
{
"label": "AI Assistant",
"href": "/docs/monitor/ai-assistant",
"tailRich": " — how <code>/api/notifications/test-ai</code> and <code>/api/notifications/provider-models</code> are wired."
},
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tailRich": " — the response shape of <code>/api/health/*</code> and the semantics of the ten categories."
}
]
}
}
@@ -0,0 +1,303 @@
{
"meta": {
"title": "ProxMenux Monitor Architecture — AppImage, Flask, SQLite, WebSocket | ProxMenux",
"description": "How ProxMenux Monitor is built: AppImage layout, Flask blueprints, background workers, data sources (psutil, pvesh, smartctl, journalctl), SQLite persistence, WebSocket terminal, AI providers, notification channels, reverse proxy and optional Fail2Ban integration.",
"ogTitle": "ProxMenux Monitor Architecture",
"ogDescription": "Inside ProxMenux Monitor — AppImage layout, Flask blueprints, background workers, SQLite, WebSocket, AI providers, notification channels.",
"twitterTitle": "ProxMenux Monitor Architecture",
"twitterDescription": "AppImage, Flask, SQLite, WebSocket, AI providers and notification channels — inside the Monitor."
},
"header": {
"title": "Architecture",
"description": "How ProxMenux Monitor is packaged, what runs inside the AppImage, and how requests flow from the browser through the Flask backend to the host's tooling and SQLite store.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "One process, many responsibilities",
"body": "A single Python process listens on TCP 8008. It serves the static Next.js build, exposes the REST API, handles the WebSocket terminal, runs the periodic Health Monitor, and dispatches notifications. There is no separate web server, no message broker, no external database."
},
"requestFlow": {
"heading": "Request flow",
"intro": "From the browser to the kernel, every dashboard view follows the same path:",
"diagramCaption": "Each request is authenticated by JWT (when auth is enabled), dispatched to a blueprint, and answered with data collected on demand from host tooling. If Fail2Ban is installed and the proxmenux jail is active, the middleware also checks the request against the jail's banned IP list. The optional reverse proxy is transparent to Flask — it forwards X-Forwarded-* headers and the app recovers the real client IP from them. State that needs to outlive a request lives in SQLite.",
"diagramArrowLabel": "HTTP / WS",
"nodes": {
"clientLabel": "Client",
"clientDetail": "Browser or PWA\n+ optional\nNginx / Caddy /\nTraefik proxy",
"flaskLabel": "Flask :8008",
"flaskDetail": "Blueprints\nJWT middleware\nFail2Ban hook\n(if installed)",
"hostLabel": "Host tools",
"hostDetail": "psutil\npvesh\nsmartctl\njournalctl",
"stateLabel": "Local state",
"stateDetail": "SQLite DB\n+ auth.json"
},
"threadsIntro": "The same process also runs four <strong>background threads</strong> started at boot — they don't serve HTTP, they push state into SQLite or into the notification queue while the host is up:",
"headerThread": "Thread",
"headerCadence": "Cadence",
"headerJob": "Job",
"rows": [
{
"thread": "_temperature_collector_loop",
"cadence": "60 s",
"job": "Records CPU temperature and a network-latency sample into the history DB so the dashboard graphs have data even when no client is connected."
},
{
"thread": "_health_collector_loop",
"cadence": "5 min",
"job": "Runs the full Health Monitor cycle (10 categories), persists active errors, dismissals and disk observations, and feeds new events into the notification engine."
},
{
"thread": "_vital_signs_sampler",
"cadence": "~1 s",
"job": "High-frequency CPU + temperature sampler used for live widgets in the Overview panel."
},
{
"thread": "notification_manager.start()",
"cadence": "event-driven",
"job": "Spawns the journal / task / hook watchers (<code>JournalWatcher</code>, <code>TaskWatcher</code>, <code>ProxmoxHookWatcher</code>) and dispatches to configured channels with optional AI rewriting."
}
]
},
"systemd": {
"heading": "systemd unit",
"intro": "The installer drops a unit at <code>/etc/systemd/system/proxmenux-monitor.service</code>. Default content:",
"items": [
"<strong><code>User=root</code></strong> — required: SMART, <code>pvesh</code>, journal scopes, ZFS commands and the web terminal all need root.",
"<strong><code>Restart=on-failure</code></strong> with a 10-second back-off — non-zero exits relaunch automatically.",
"<strong><code>After=network.target</code></strong> — waits for the host network stack to be online."
],
"inspectTitle": "Inspect the live unit"
},
"appimage": {
"heading": "What the AppImage contains",
"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>No host Python pollution.</strong> The vendored interpreter and packages are isolated inside the AppImage — upgrading the host's system Python doesn't affect the Monitor and vice-versa.",
"<strong>Hardware tools are bundled too.</strong> <code>ipmitool</code>, <code>lm-sensors</code> and <code>upsc</code> ship inside the AppImage so the dashboard can read out-of-band sensors and UPS state without forcing the user to install Debian packages."
]
},
"flask": {
"heading": "Flask app structure",
"intro": "<code>flask_server.py</code> creates a single <code>Flask(__name__)</code> instance, enables CORS, and registers six blueprints plus a WebSocket initializer:",
"headerBlueprint": "Blueprint / module",
"headerPrefix": "Routes prefix",
"headerOwns": "Owns",
"rows": [
{
"blueprint": "flask_server.py",
"prefix": [
"/api/system",
"/api/storage",
"/api/network",
"/api/vms",
"/api/hardware",
"/api/logs",
"/api/prometheus"
],
"owns": "Core data endpoints + static dashboard serving + optional Fail2Ban app-level check (active only when Fail2Ban is installed on the host with the <code>proxmenux</code> jail)."
},
{
"blueprint": "flask_auth_routes.py",
"prefix": [
"/api/auth/*"
],
"owns": "Login, JWT issuing, TOTP setup/verify, password change, API token generation."
},
{
"blueprint": "flask_health_routes.py",
"prefix": [
"/api/health/*"
],
"owns": "Public health probe, detailed status, active / dismissed errors, suppression settings."
},
{
"blueprint": "flask_terminal_routes.py",
"prefix": [
"/api/terminal/* + WS"
],
"owns": "PTY allocation per session and WebSocket pipe to <code>xterm.js</code> in the browser."
},
{
"blueprint": "flask_notification_routes.py",
"prefix": [
"/api/notifications/*"
],
"owns": "Channel CRUD, test-send, AI provider config, history, manual sends."
},
{
"blueprint": "flask_security_routes.py",
"prefix": [
"/api/security/*"
],
"owns": "Authentication failures and, when Fail2Ban is installed, jail status, ban events and manual unban."
},
{
"blueprint": "flask_proxmenux_routes.py",
"prefix": [
"/api/proxmenux/*"
],
"owns": "Reads which ProxMenux post-install optimizations are installed on the host."
},
{
"blueprint": "flask_oci_routes.py",
"prefix": [
"/api/oci/*"
],
"owns": "OCI / container app deployment helpers (Proxmox VE 9.1+)."
}
],
"endpointsLink": "The full endpoint list with request / response shapes is in <link>API Reference</link>."
},
"dataSources": {
"heading": "Data sources",
"intro": "Nothing is collected from a custom agent — the Monitor reads the same files and runs the same commands a human admin would:",
"headerSource": "Source",
"headerUsedFor": "Used for",
"rows": [
{
"source": "psutil",
"usedFor": "CPU load, memory, swap, mountpoint usage, NIC counters, process list."
},
{
"source": "pvesh / qm / pct",
"usedFor": "Proxmox node info, VM and CT inventory and config, storage pools, task history."
},
{
"source": "smartctl",
"usedFor": "SATA / NVMe attributes, SMART health, wear / lifetime, model and serial."
},
{
"source": "zpool / zfs",
"usedFor": "Pool state (ONLINE / DEGRADED / FAULTED / UNAVAIL), scrub progress, dataset usage."
},
{
"source": "journalctl",
"usedFor": "System logs, OOM kills, ATA / NVMe / dm errors, security events, custom service units."
},
{
"source": "ip / iproute2",
"usedFor": "Interfaces, addresses, bridges, bonds, OVS-managed devices."
},
{
"source": "nvidia-smi · intel_gpu_top",
"usedFor": "GPU utilisation, VRAM, temperature, encoder / decoder load."
},
{
"source": "lspci · lscpu · dmidecode",
"usedFor": "PCIe topology, CPU model and topology, board and BIOS info."
},
{
"source": "ipmitool · sensors",
"usedFor": "Out-of-band sensors, fan speeds, board temperatures (when supported)."
},
{
"source": "upsc (NUT)",
"usedFor": "UPS battery state, load, runtime — when a NUT server is configured on the host."
}
],
"cacheTitle": "Output is cached — not every request hits the host",
"cacheBody": "Expensive sources (<code>smartctl -a</code>, <code>pvesh get</code>) are wrapped in time-bound caches inside the Flask process so a busy dashboard tab doesn't hammer the disk or the cluster API. The cache TTLs are tuned per source (a few seconds for live metrics, several minutes for SMART)."
},
"persistence": {
"heading": "Persistence",
"intro": "Two filesystem locations split state by sensitivity:",
"headerPath": "Path",
"headerOwner": "Owner",
"headerContents": "Contents",
"rows": [
{
"path": "/usr/local/share/proxmenux/health_monitor.db",
"owner": "root:root",
"contents": "SQLite DB. Tables: <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>. WAL journal mode."
},
{
"path": "/usr/local/share/proxmenux/.notification_key",
"owner": "root <code>0600</code>",
"contents": "32-byte XOR key used to encrypt sensitive notification settings before storing them in the DB (Telegram tokens, AI API keys, etc.)."
},
{
"path": "/root/.config/proxmenux-monitor/auth.json",
"owner": "root:root",
"contents": "Authentication state: enabled flag, username, SHA-256 password hash, TOTP secret, backup codes, list of issued API tokens, list of revoked token hashes."
},
{
"path": "/var/log/proxmenux-auth.log",
"owner": "root:root",
"contents": "Plain-text auth event log. Always written. If Fail2Ban is installed with the <code>[proxmenux]</code> jail, the jail reads this file to ban brute-force attempts; if not, the file simply accumulates the log entries."
}
],
"backupTitle": "Back up auth.json before reinstalling",
"backupBody": "Reinstalling the AppImage replaces the binary but leaves <code>/root/.config/proxmenux-monitor/auth.json</code> and <code>/usr/local/share/proxmenux/health_monitor.db</code> intact. If you restore from a host backup, keep both files together — the API tokens stored in <code>auth.json</code> are validated against <code>JWT_SECRET</code>; if the DB and auth.json get out of sync, dismissed errors and stored tokens may misbehave."
},
"health": {
"heading": "Health Monitor cycle",
"intro": "Every 5 minutes <code>health_monitor.py</code> runs a deterministic cycle across the ten categories shown on the dashboard:",
"items": [
"Critical PVE services (<code>pveproxy</code>, <code>pvedaemon</code>, <code>pvestatd</code>, <code>pve-cluster</code>).",
"Proxmox storage pools (<code>pvesh get /storage</code> + per-storage availability).",
"Disks and filesystems: SMART, dmesg I/O errors, ZFS pool health, mountpoint capacity.",
"VMs and CTs: failed starts, crashed guests, QMP errors, shutdown failures.",
"Network: bridge / bond status, link state, latency to the gateway.",
"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 / chassis sensors against vendor thresholds.",
"Security: authentication failures, ban events, fail2ban jail status."
],
"afterIntro": "Each finding is normalised into a stable <code>error_key</code> + category + severity. The persistence layer deduplicates against the existing <code>errors</code> table — repeated events update <code>last_seen</code> and the occurrence counter without spamming notifications.",
"cycleEnd": "The cycle also auto-resolves stale errors using the per-category <em>Suppression Duration</em> setting, cleans up errors for resources that no longer exist (deleted VMs / removed disks / unmounted storages), and prunes the <code>events</code> log older than 30 days. The full catalogue of categories and the dashboard view that surfaces them is documented in <link>Dashboard → Health Monitor</link>."
},
"notifications": {
"heading": "Notification engine",
"intro": "<code>notification_manager.py</code> is the orchestrator. It loads the configured channels, owns the delivery queue, and exposes both a Python API (for Flask routes and the Health Monitor cycle) and a CLI entrypoint (for the <code>.sh</code> hook scripts shipped with ProxMenux).",
"items": [
"<strong>Watchers</strong> push events: <code>JournalWatcher</code> tails the system journal, <code>TaskWatcher</code> polls the Proxmox task list, <code>ProxmoxHookWatcher</code> reacts to backup / replication / snapshot hooks, and <code>PollingCollector</code> handles slow data sources.",
"<strong>Templates</strong> turn an event into a (title, body) pair. The same template can run through the configured AI provider (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) to produce a plain-language rewrite; both versions are stored in <code>notification_history</code>.",
"<strong>Channels</strong> deliver messages: Telegram, Discord, Email, Gotify and Apprise (multi-channel). Each is implemented in <code>notification_channels.py</code> behind the same <code>create_channel()</code> / <code>send()</code> interface, so adding a new channel is a single class.",
"<strong>Encryption.</strong> Sensitive settings (<code>telegram.token</code>, <code>discord.webhook_url</code>, <code>ai_api_key_*</code>, <code>email.password</code>) are XOR-encrypted with the key in <code>.notification_key</code> before being written to the DB. Plaintext never touches disk."
],
"linksFooter": "Per-event toggles, channel overrides and AI configuration are surfaced in <notifLink>Settings → Notifications</notifLink> and <aiLink>Settings → AI Assistant</aiLink>."
},
"websocket": {
"heading": "WebSocket terminal",
"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> Flask's development server with <code>flask-sock</code> handles upgrade requests. Good enough for LAN / direct access.",
"<strong>HTTPS / WSS mode:</strong> when an SSL certificate is configured, the process switches to <code>gevent.pywsgi.WSGIServer</code> with <code>geventwebsocket.handler.WebSocketHandler</code>, so WebSockets work over TLS without polyfills."
],
"outro": "The PTY is a child of the Flask process, so it inherits <code>User=root</code> from the unit. Every terminal request goes through JWT auth; the user must already be logged in to the dashboard before a PTY is allocated.",
"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": {
"heading": "Reverse proxy & Fail2Ban",
"intro": "Two safeguards make sure security works the same way whether the dashboard is hit directly or through a reverse proxy:",
"items": [
"<strong>Real client IP recovery.</strong> A <code>before_request</code> hook reads <code>X-Forwarded-For</code> and <code>X-Real-IP</code> in that order, falling back to <code>request.remote_addr</code>. The recovered address is what auth logging and rate limiting see. This is always on.",
"<strong>Application-level Fail2Ban check (optional).</strong> When the dashboard sits behind a proxy, the kernel firewall can't block the real attacker IP — the connection always comes from the proxy. To plug that gap, the same hook above queries the <code>proxmenux</code> Fail2Ban jail every 30 seconds, caches the banned IP set, and short-circuits requests from those IPs with HTTP 403 inside Flask."
],
"calloutTitle": "Fail2Ban is not bundled",
"calloutBody": "Fail2Ban is <strong>not</strong> installed by ProxMenux Monitor itself. The application-level check is a no-op until you install Fail2Ban on the host (e.g. via <link>Security → Fail2Ban</link> in the ProxMenux menu). When the <code>fail2ban-client</code> binary or the <code>proxmenux</code> jail is absent, the call fails silently and requests are not gated — auth still applies, but no IP-level banning.",
"outro": "Reverse-proxy snippets (Nginx / Caddy / Traefik) and the Fail2Ban jail walkthrough are in <accessLink>Access & Authentication</accessLink> and <fail2banLink>Security → Fail2Ban</fail2banLink>."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — first-launch setup, password + TOTP 2FA, reverse-proxy snippets, Fail2Ban jail."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — every endpoint, token management, security best-practices."
},
{
"label": "Settings → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — the in-menu service toggle and status verification flow inside the ProxMenux TUI."
}
]
}
}
@@ -0,0 +1,246 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Hardware tab | ProxMenux Documentation",
"description": "The Hardware tab inventories the physical machine: CPU and motherboard, memory modules, thermal sensors, GPUs (with per-slot real-time monitoring and one-click driver installer), Coral TPU accelerators, storage summary with link-speed checks, full PCI and USB device lists, power consumption, PSUs, fans and UPS state."
},
"header": {
"title": "Dashboard: Hardware tab",
"description": "The physical machine in one screen — CPU and motherboard identity, every memory module, thermal sensors across all subsystems, GPUs with live utilisation and a built-in driver installer, Coral TPUs, every PCI and USB device with its kernel driver, the full disk inventory with negotiated link speeds, plus power, cooling and the UPS.",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "Built from standard tools",
"body": "Most of this tab is parsed from <code>lscpu</code>, <code>dmidecode</code>, <code>lspci</code>, <code>lsusb</code>, <code>lsblk</code>, <code>smartctl</code>, <code>nvme</code>, <code>sensors</code>, <code>nvidia-smi</code>, <code>intel_gpu_top</code>, <code>amdgpu_top</code>, <code>ipmitool</code> and <code>upsc</code>. Sections only render when the relevant tool returns data, so a host without a UPS won't show the UPS card and a host without IPMI won't show out-of-band power figures."
},
"thresholds": {
"title": "Status colours and thresholds applied here",
"intro": "Every temperature chip and reading on this tab follows the same classification — <green/> <strong>green</strong> below Warning, <amber/> <strong>amber</strong> from Warning to Critical, <red/> <strong>red</strong> at Critical and above. Recommended defaults shipped with ProxMenux:",
"items": [
"<strong>CPU temperature</strong> — Warning 80 °C, Critical 90 °C.",
"<strong>Disk temperature</strong> — HDD 60/65 °C · SSD 70/75 °C · NVMe 80/85 °C · SAS 55/65 °C (warning / critical)."
],
"outro": "Every value is configurable per host — <link>Settings → Health Monitor Thresholds</link> is the single source of truth and explains how to tune them."
},
"sections": {
"heading": "Sections",
"intro": "The tab renders top-to-bottom in this order. Some sections only appear when the host has the corresponding hardware or tool installed — they're marked <em>(conditional)</em> below.",
"systemInfoTitle": "System Information",
"systemInfoIntro": "Two side-by-side blocks, always present:",
"systemInfoItems": [
"<strong>CPU</strong> — model name, microarchitecture, sockets / cores / threads, base / boost frequency, virtualisation flags (VT-x / AMD-V), cache topology.",
"<strong>Motherboard</strong> — vendor, model, BIOS version, BIOS date, SMBIOS UUID. Useful for matching to vendor download pages when looking for firmware updates."
],
"memoryTitle": "Memory Modules",
"memoryBody": "One row per populated slot from <code>dmidecode</code>: slot label, module size, type (DDR4 / DDR5 / ECC variants), speed (configured and rated), manufacturer, part number and serial. Empty slots are listed greyed-out so you can see the upgrade headroom at a glance.",
"thermalTitle": "Thermal Monitoring",
"thermalIntro": "Five sub-blocks, each fed by <code>lm-sensors</code> + tool-specific scrapers. A block hides itself when no sensors are reported in that category.",
"thermalItems": [
"<strong>CPU</strong> — package and per-core temperatures.",
"<strong>GPU</strong> — discrete-GPU sensors via <code>nvidia-smi</code> / <code>amdgpu_top</code> / Intel iGPU. Includes hot-spot and memory-junction when the driver exposes them.",
"<strong>NVME</strong> — composite + per-sensor temperatures from <code>nvme</code>.",
"<strong>PCI</strong> — sensors that surface as PCI-attached devices (HBAs, network cards with internal sensors).",
"<strong>OTHER</strong> — chipset, VRM, ambient sensors that don't fit elsewhere."
]
},
"graphics": {
"heading": "Graphics Cards",
"intro": "Each detected video controller renders as its own card with vendor, model, kind (<em>Integrated</em> / <em>PCI</em> / BMC), PCI slot (BDF), kernel driver and module list. The card also exposes an inline <strong>Switch Mode</strong> control that flips the GPU between LXC sharing (native driver) and VM passthrough (<code>vfio-pci</code>) — see <link>Switch GPU Mode (VM ↔ LXC)</link> for what happens on the host when you press it.",
"vfioImageAlt": "Graphics Cards section showing a Matrox G200EH integrated GPU bound to mgag200 (Ready for LXC) and an NVIDIA Quadro P400 bound to vfio-pci (Ready for VM passthrough)",
"vfioImageCaption": "Two GPUs detected: the Matrox BMC chip is on the native driver and ready for LXC; the NVIDIA Quadro P400 is bound to <code>vfio-pci</code>, ready for VM passthrough.",
"lxcImageAlt": "Graphics Cards section showing an Intel UHD Graphics iGPU on i915 and an NVIDIA Quadro P1000 on the nvidia driver, both labelled Ready for LXC containers",
"lxcImageCaption": "Same node after switching the NVIDIA card back to the native driver — both GPUs now Ready for LXC containers.",
"realtimeTitle": "Real-time monitoring modal",
"realtimeBody": "Clicking a GPU card opens a per-slot monitoring modal that polls the appropriate vendor tool every three seconds. The modal exposes vendor, type, PCI slot, driver, kernel module(s), live engine utilisation (Render/3D, Video, Blitter, VideoEnhance), graphics & memory clocks, temperature, power draw (when reported), VRAM usage, and an Active Processes table with per-process engine load. Data is served from <code>/api/gpu/&lt;slot&gt;/realtime</code>.",
"toolsIntro": "The vendor tool used per GPU:",
"headerVendor": "Vendor",
"headerTool": "Tool",
"headerProject": "Project",
"tools": [
{
"vendor": "NVIDIA",
"tool": "nvidia-smi",
"projectLabel": "developer.nvidia.com",
"projectHref": "https://developer.nvidia.com/nvidia-system-management-interface"
},
{
"vendor": "Intel iGPU",
"tool": "intel_gpu_top (igt-gpu-tools)",
"projectLabel": "gitlab.freedesktop.org",
"projectHref": "https://gitlab.freedesktop.org/drm/igt-gpu-tools"
},
{
"vendor": "AMD",
"tool": "amdgpu_top",
"projectLabel": "github.com/Umio-Yasuno/amdgpu_top",
"projectHref": "https://github.com/Umio-Yasuno/amdgpu_top"
},
{
"vendor": "Matrox / ASPEED (BMC)",
"tool": "— (display only)",
"projectLabel": "Detected and labelled as BMC; no realtime block."
}
],
"nvidiaImageAlt": "GPU monitoring modal for an NVIDIA Quadro P1000: vendor NVIDIA, driver nvidia loaded, graphics clock 1.26 GHz, memory clock 2.50 GHz, temperature 50 °C, all engine utilisation bars at 0 %, no active processes, total memory 4096 MiB",
"nvidiaImageCaption": "NVIDIA Quadro P1000 with the proprietary driver loaded — clocks, temperature, engine bars and active processes all visible.",
"intelImageAlt": "GPU monitoring modal for an Intel UHD Graphics iGPU on i915 driver, showing 11.31 W power draw, 1 % video engine load and an ffmpeg process consuming 8 MB",
"intelImageCaption": "Intel iGPU with <code>i915</code> active. The Active Processes table picks up an ffmpeg job using the video engine.",
"amdImageAlt": "GPU monitoring modal for an AMD Lucienne integrated GPU on amdgpu driver, with engine utilisation bars at 0 % and amdgpu_top listed as an active process",
"amdImageCaption": "AMD iGPU monitored through <code>amdgpu_top</code> — the tool itself shows up as an active process because it's the live polling backend.",
"installTitle": "Installing the NVIDIA driver from the modal",
"installBody": "When an NVIDIA GPU is bound to <code>nouveau</code>/<code>nvidiafb</code> (no proprietary driver installed), the realtime block can't read clocks, power or per-process load. The modal then replaces the metrics with an <strong>Install NVIDIA Drivers</strong> button that wires straight into the same script documented at <link>Install NVIDIA Drivers (Host)</link>.",
"noDriverAlt": "GPU monitoring modal for an NVIDIA Quadro P620 with kernel modules nvidiafb and nouveau loaded, an Extended Monitoring Not Available callout and a blue Install NVIDIA Drivers button",
"noDriverCaption": "No proprietary driver installed yet — the modal shows a one-click installer.",
"promptAlt": "NVIDIA GPU Driver Installation confirmation dialog listing detected GPUs, LXC containers with NVIDIA passthrough and a Yes/Cancel pair",
"promptCaption": "Pre-install summary: detected GPUs, LXC containers that already have NVIDIA passthrough, and what the script will do. Nothing is touched until you confirm.",
"successAlt": "Terminal output showing the NVIDIA driver 580.105.08 installed successfully and nvidia-smi reporting a Quadro P620",
"successCaption": "Successful install — the NVIDIA <code>.run</code> built via DKMS, the persistence service is in place, and <code>nvidia-smi</code> reports the GPU.",
"warningTitle": "Pick a driver version your GPU actually supports",
"warningBody": "Newer NVIDIA driver branches drop support for older GPU families (e.g. Maxwell / Kepler). If the install finishes but <code>nvidia-smi</code> reports <em>\"No devices were found\"</em> or DKMS errors out, the chosen branch most likely doesn't cover your GPU — re-run the installer and pick an older branch (legacy 470.x for Kepler-era cards, etc.). NVIDIA publishes the per-GPU compatibility on the <a>official driver lookup page</a>.",
"whereGoIntro": "Where to go from here:",
"whereGoItems": [
"<link1>Install NVIDIA Drivers (Host)</link1> — full walk-through of the installer, kernel-compatibility matrix, optional NVENC patch and LXC propagation.",
"<link2>Switch GPU Mode (VM ↔ LXC)</link2> — what the inline <em>Switch Mode</em> control actually does.",
"<link3>Add GPU to VM (Passthrough)</link3> and <link4>Add GPU to LXC</link4> — first-time assignment of an unbound GPU."
]
},
"coral": {
"heading": "Coral TPU / AI Accelerators",
"subHeading": "(conditional)",
"intro": "Renders when the host has Google Coral or other AI-accelerator devices wired up. Each device opens a modal with its connection type (M.2 / mini-PCIe / USB), PCIe link width, vendor / product ID, kernel driver (<code>apex</code> for PCIe, <code>libedgetpu</code> for USB), kernel modules (<code>gasket</code> + <code>apex</code>), device nodes (<code>/dev/apex_*</code>), Edge TPU runtime status, live temperature and the firmware hardware-warning thresholds.",
"imageAlt": "Coral Edge TPU detail modal: PCIe / M.2 connection, PCIe 5.0 GT/s x1 link, vendor 1ac1:089a, kernel driver apex, gasket and apex modules loaded, /dev/apex_0 present, Edge TPU Runtime not installed, temperature 53.5 °C with hardware warning thresholds",
"imageCaption": "M.2 Coral with the host kernel modules loaded, the device node up and the firmware temperature warnings exposed. The runtime line goes green once the matching Edge TPU runtime is installed.",
"pathsIntro": "Two install paths exist depending on the form factor:",
"pathsItems": [
"<strong>M.2 / Mini-PCIe</strong> — the host needs the <code>gasket</code> + <code>apex</code> kernel modules built via DKMS so the device node <code>/dev/apex_0</code> appears at boot.",
"<strong>USB Accelerator</strong> — the host only needs the Edge TPU user-space runtime (<code>libedgetpu1-std</code>) from Google's APT repository."
],
"outro": "Both are handled by a single ProxMenux entry — <installLink>Install Coral TPU on the Host</installLink> — which auto-detects what you have. Background and the official runtime live at <a>coral.ai/docs</a>. Once the host side is ready, hand the device to a container with <lxcLink>Add Coral TPU to LXC</lxcLink>."
},
"storage": {
"heading": "Storage Summary",
"intro": "Every block device the kernel knows about, grouped by type. For each disk you get the kernel name (<code>sda</code>, <code>nvme0n1</code>, <code>zram0</code> …), the type tag (<em>SSD</em>, <em>HDD</em>, <em>NVMe SSD</em>), the model string and the negotiated link information. Click any disk to open a hardware-info modal with model, serial, capacity, interface and current vs maximum link speed.",
"imageAlt": "Storage Summary card listing eleven block devices (SATA SSDs, SATA HDDs, NVMe SSDs and zram) with model strings and negotiated link speeds; the two NVMe drives show 3.0 x4 with the current speed highlighted",
"imageCaption": "Eleven devices on this node. SATA links print as <em>SATA &lt;version&gt;, &lt;Gb/s&gt; (current: ...)</em>; NVMe drives print as <em>&lt;PCIe gen&gt; x&lt;width&gt;</em>.",
"nvmeBody": "For NVMe drives the per-card line shows both the negotiated link and the maximum the device supports. When the two don't match (e.g. a Gen3 x4 SSD running at <strong>3.0 x1</strong> because it's sitting in a chipset slot wired to a single lane), the current speed is rendered in amber so the downgrade is visible at a glance — useful when troubleshooting unexpectedly slow disks or after a BIOS update remaps the lanes.",
"nvmeModalAlt": "NVMe drive detail modal for nvme0n1: NVMe SSD type, 953.9 GB capacity, current link speed 3.0 x1 highlighted in amber, maximum link speed 3.0 x4, model WDC CL SN720, serial number, PCIe/NVMe interface",
"nvmeModalCaption": "NVMe modal showing the lane downgrade — drive supports x4 but the slot is wired x1.",
"outro": "SMART data, self-tests, history and the PDF disk report all live one tab over, in <storageLink>Dashboard: Storage tab</storageLink>. The same data feeds the script at <smartLink>SMART Disk Health & Test</smartLink> — running a long test from the script writes the JSON the Monitor displays in <em>Storage → History</em>."
},
"pci": {
"heading": "PCI Devices",
"intro": "Every PCI-addressable device, identified by its <strong>PCI BDF</strong> (Bus:Device.Function — e.g. <code>03:00.0</code>) and its device class (<em>Storage Controller</em>, <em>USB Controller</em>, <em>Graphics Card</em>, <em>Network Controller</em>, <em>Audio Controller</em> …). Each card shows the manufacturer, the device name and the <strong>kernel driver currently bound</strong> — which is the field you actually want when troubleshooting passthrough, IOMMU groups or a card the host isn't driving correctly.",
"imageAlt": "PCI Devices section listing fifteen devices grouped by class: storage controllers on ahci/nvme, USB controllers, graphics cards (one on vfio-pci, one on the native driver), network controllers on igb / tg3, an audio controller alongside a passed-through GPU",
"imageCaption": "Fifteen devices on this node. Note the GPU and its companion audio function both bound to <code>vfio-pci</code> — that's a card prepared for VM passthrough.",
"bdfTitle": "Reading the BDF",
"bdfBody": "<code>03:00.0</code> means PCI bus <code>03</code>, device <code>00</code>, function <code>0</code>. Multifunction devices like discrete GPUs typically claim <code>.0</code> for the GPU and <code>.1</code> for the HDMI audio function — both have to be passed through together, which is why <link>Switch GPU Mode</link> also handles the orphan-audio cleanup when leaving VM mode."
},
"usb": {
"heading": "USB Devices",
"intro": "Every USB device the host enumerates, with manufacturer / product strings, USB version, the <code>bus:device</code> address, the <code>vendor:product</code> ID pair and the kernel driver. The renderer also classifies common roles — <em>Communications</em> (Z-Wave / Zigbee sticks), <em>UPS</em>, storage, HID — so you can spot at a glance which of your sticks is which without cross-referencing IDs.",
"imageAlt": "USB Devices card listing three devices: an Aeotec Z-Wave Z-Stick, a ConBee II Zigbee coordinator and an Ellipse ECO UPS, each with USB version, address, vendor:product ID and bound driver",
"imageCaption": "Three USB devices — two home-automation radios on <code>usbfs</code> and a UPS on <code>usbfs</code> (NUT talks to it through libusb)."
},
"power": {
"heading": "Power Consumption",
"subHeading": "(conditional)",
"intro": "Renders only when the host exposes power telemetry. Two independent sources are surfaced when available:",
"items": [
"<strong>ACPI / IPMI total draw</strong> — whole-system wattage from a board-level sensor or the BMC. Typical on server boards.",
"<strong>CPU package power</strong> — read from the Intel RAPL counters (or AMD equivalent). Useful to separate CPU draw from the rest of the system on consumer boards that don't expose a total figure."
],
"supplyImageAlt": "Power Consumption section showing 198 W total draw via ACPI interface, plus a Power Supplies card with two PSUs both reporting OK (185 W and 5 W output)",
"supplyImageCaption": "Server board with a single ACPI power sensor and dual PSUs reported through IPMI — the second PSU is the redundant one, idling at 5 W.",
"cpuImageAlt": "Power Consumption section on a consumer board showing only CPU Power 8.7 W via Intel RAPL",
"cpuImageCaption": "Consumer board with no whole-system sensor — the section falls back to RAPL CPU-only."
},
"psu": {
"heading": "Power Supplies",
"subHeading": "(conditional)",
"body": "Server-board / dual-PSU machines via IPMI: presence (PSU 1 / PSU 2 / …), input voltage, output wattage, OK / failed flag. The first thing you check after a power blip on a node with redundant PSUs."
},
"fans": {
"heading": "System Fans",
"subHeading": "(conditional)",
"body": "Per-fan RPM with a small sparkline (when supported). On boards without per-fan reporting the section falls back to a single chassis-fan reading."
},
"ups": {
"heading": "UPS Status",
"subHeading": "(conditional)",
"body": "Renders when a NUT (Network UPS Tools) server is configured and reachable. Shows: state (online / on battery / charging / low battery), battery charge percentage, runtime estimate, load percentage, input voltage, model and firmware. The same data feeds the <em>Security & Certificates</em> category of the Health Monitor — a UPS that goes on-battery surfaces immediately."
},
"dataCollected": {
"heading": "How the data is collected",
"headerSection": "Section of the tab",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"section": "Static inventory (PCI, CPU, BIOS)",
"endpoint": "/api/hardware",
"source": "<code>lspci -vmm</code>, <code>/proc/cpuinfo</code>, <code>dmidecode</code>; cached for the lifetime of the process."
},
{
"section": "Live sensor values",
"endpoint": "/api/hardware/live",
"source": "<code>sensors</code> (lm-sensors), package temperatures, fan RPM. Refreshed each request."
},
{
"section": "CPU temperature history",
"endpoint": "/api/temperature/history",
"source": "Time series sampled by the Health Monitor every 5 min and persisted to SQLite."
},
{
"section": "GPU live metrics",
"endpoint": "/api/gpu/<slot>/realtime",
"source": "NVIDIA: <code>nvidia-smi --query-gpu=...</code>. Intel: <code>intel_gpu_top</code>. AMD: sysfs <code>/sys/class/drm/cardN</code>."
}
],
"codeComment1": "# Cross-check inventory against the OS view",
"codeComment2": "# Confirm the GPU card the dashboard sees"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Install NVIDIA Drivers (Host)",
"href": "/docs/hardware/nvidia-host",
"tail": " — what the GPU modal's install button runs."
},
{
"label": "Switch GPU Mode (VM ↔ LXC)",
"href": "/docs/hardware/switch-gpu-mode",
"tail": " — what the inline mode switch on each GPU card does to the host."
},
{
"label": "Install Coral TPU on the Host",
"href": "/docs/hardware/install-coral-tpu-host",
"tail": " — the Coral kernel module / runtime install."
},
{
"label": "SMART Disk Health & Test",
"href": "/docs/disk-manager/smart-disk-test",
"tail": " — the script behind the SMART data shown in the Storage tab's disk drill-in."
},
{
"label": "Dashboard: Storage tab",
"href": "/docs/monitor/dashboard/storage",
"tail": " — full SMART attribute table, self-test history and PDF report."
},
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the CPU & Temperature category that consumes the same sensors."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the hardware and GPU endpoints."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other tabs."
}
]
}
}
@@ -0,0 +1,91 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard | ProxMenux Documentation",
"description": "The dashboard is the main UI of ProxMenux Monitor: nine tabs (System Overview, Storage, Network, VMs & LXCs, Hardware, System Logs, Terminal, Security, Settings) plus the global header with the Health Monitor status pill."
},
"header": {
"title": "Dashboard",
"description": "The dashboard is the everyday view of ProxMenux Monitor — nine tabs each focused on one slice of the host plus a global header with the Health Monitor status pill, the node identity and the quick-refresh control.",
"section": "ProxMenux Monitor"
},
"oneHeader": {
"title": "One header, nine tabs",
"body": "The header (logo, node name, status pill, uptime, refresh, theme toggle) stays visible everywhere. The active tab below it changes the entire content area. The status pill colour mirrors the worst category of the <link>Health Monitor</link> — it's the same data point seen from the dashboard."
},
"tabs": {
"heading": "The nine tabs",
"intro": "Each tab has its own dedicated page. Pages are added incrementally as the documentation is filled in; below is the full list and what each one is responsible for.",
"headerTab": "Tab",
"headerOwns": "What it owns",
"rows": [
{
"name": "System Overview",
"linksTo": "/docs/monitor/dashboard/system-overview",
"owns": "CPU / memory / temperature widgets, active VM & LXC count, historical metrics charts, storage and network summaries. Default landing tab."
},
{
"name": "Storage",
"owns": "Proxmox pools, physical disks, SMART data, ZFS state, wear & lifetime, observation history."
},
{
"name": "Network",
"owns": "Every interface (physical / bond / bridge / OVS), IP/MAC, RX/TX graphs, historical RRD per interface."
},
{
"name": "VMs & LXCs",
"owns": "Inventory of guests, drill-in for config / metrics / logs, start / stop / reboot / shutdown actions."
},
{
"name": "Hardware",
"owns": "CPU model and topology, memory layout, PCIe topology, GPUs with per-slot real-time monitoring."
},
{
"name": "System Logs",
"owns": "Live <code>journalctl</code> with filters, Proxmox task history, notification log, downloadable log bundles."
},
{
"name": "Terminal",
"owns": "Browser shell to host or to any VM/CT, powered by <code>xterm.js</code> over WebSockets."
},
{
"name": "Security",
"owns": "Auth setup, password / 2FA / API tokens, audit log, optional Fail2Ban panel, Secure Gateway deployment."
},
{
"name": "Settings",
"owns": "Notification channels, AI provider, suppression durations, branding, advanced flags."
}
]
},
"headerAnatomy": {
"heading": "Header anatomy",
"items": [
"<strong>Logo + product name</strong> on the left. The logo turns into an \"update available\" variant when a newer Monitor release is detected.",
"<strong>Node identity</strong> — the Proxmox node name resolved from <code>pvesh get /nodes</code>, falling back to <code>hostname</code>.",
"<strong>Health status pill</strong> — Healthy (green), Warning (yellow), Critical (red). Click it to open the Health Monitor modal. An extra blue <em>info</em> badge appears when there are dismissed items still inside their suppression window.",
"<strong>Uptime</strong> — host uptime, formatted human-readable.",
"<strong>Refresh button</strong> — re-issues all the live API calls without a full page reload.",
"<strong>Theme toggle</strong> — light / dark / system. Persisted in <code>localStorage</code>."
]
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "System Overview tab",
"href": "/docs/monitor/dashboard/system-overview",
"tail": " — the landing tab, fully documented."
},
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the modal behind the header status pill, ten categories deep-dive."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tail": " — how the dashboard talks to the Flask backend."
}
]
}
}
@@ -0,0 +1,225 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Network tab | ProxMenux Documentation",
"description": "The Network tab inventories every interface on the host: physical NICs, bridges, bonds, VLANs and the VM/LXC virtual interfaces. Per-interface drill-in shows IP / MAC / state / bond members / traffic since boot and a historical RRD chart."
},
"header": {
"title": "Dashboard: Network tab",
"description": "Every interface the kernel reports — physical NICs, bridges, bonds, VLANs and VM/LXC virtual ports — grouped into three cards. Each row is clickable and opens a drill-in with addressing, traffic counters and historical RRD data.",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "Live + historical, both included",
"body": "Live state comes from <code>psutil.net_if_stats()</code> and <code>ip</code>; historical bandwidth from Proxmox's RRD store via <code>/api/network/&lt;interface&gt;/metrics</code>. The page refreshes every ~5 seconds for live counters and pulls fresh RRD data on demand for the chart."
},
"topRow": {
"heading": "Top row: four stat cards",
"headerCard": "Card",
"headerWhat": "What it shows",
"rows": [
{
"card": "Network Traffic",
"what": "Aggregate RX / TX rate across all interfaces, formatted in the right unit (bps / Kbps / Mbps / Gbps)."
},
{
"card": "Active Interfaces",
"what": "Two counters: <em>Physical X / Y</em> and <em>Bridges X / Y</em> (active over total). The first counter you watch when something stops working."
},
{
"card": "Network Status",
"what": "Quick verdict — Healthy / Warning / Critical based on link state, gateway reachability and bridge integrity. Mirrors the <em>Network Interfaces</em> category of the Health Monitor."
},
{
"card": "Network Latency",
"what": "Round-trip time to the gateway with a sparkline. Clicking the card opens the <strong>Network Latency modal</strong> documented further down — historical view + on-demand ping test against gateway / Cloudflare / Google with a downloadable PDF report."
}
]
},
"groups": {
"heading": "Three interface groups",
"intro": "Below the top row, three cards split the inventory by role. Each card has its own active-count badge in the header. Interface <strong>type</strong> is identified at a glance by a coloured badge on every row:",
"badges": [
"Blue <strong>Physical</strong> — real NIC.",
"Green <strong>Bridge</strong> — Linux bridge or OVS bridge (<code>vmbr*</code>).",
"Purple <strong>Bond</strong> — bond / LACP / active-backup aggregator.",
"Cyan <strong>VLAN</strong> — VLAN sub-interface (<code>vmbr0.10</code>, <code>eno1.42</code>, …)."
],
"clickable": "<strong>Every row is clickable</strong> — physical, virtual, bridge or bond — and opens the per-interface drill-in described further down (basic info, IPs, traffic counters, historical RX/TX chart from Proxmox's RRD store).",
"physicalTitle": "Physical Interfaces",
"physicalBody": "Every NIC the kernel sees as a real device — <code>eno1</code>, <code>enp4s0</code>, <code>eth0</code>, <code>wlp3s0</code>, etc. One row per device with the blue <strong>Physical</strong> badge and the link state. <em>Bond members</em> (NICs enslaved to a bond) are shown here too, with a hint pointing to the parent bond.",
"bridgeTitle": "Bridge Interfaces",
"bridgeBody": "Linux bridges (<code>vmbr0</code>, <code>vmbr1</code>, …) and the OVS bridges Proxmox manages. Each row shows the green <strong>Bridge</strong> badge, the underlying physical interface (when it's a single-port bridge), and the bridge state. Bonds visible at this layer get the purple <strong>Bond</strong> badge; VLAN sub-interfaces get the cyan <strong>VLAN</strong> badge.",
"vmTitle": "VM / LXC Interfaces",
"vmBody": "The <code>tap*</code> and <code>veth*</code> interfaces created when guests start — one per virtual NIC. The card header shows <em>X / Y Active</em>; rows are linked to the VM/CT they belong to so you can jump directly to the guest in the VMs & LXCs tab. Inactive entries hang around briefly after a guest stops; they age out within a refresh cycle."
},
"drillIn": {
"heading": "Per-interface drill-in",
"intro": "Clicking any row opens a modal with five blocks:",
"headerBlock": "Block",
"headerContents": "Contents",
"rows": [
{
"block": "Basic Information",
"contents": "Interface name, type (physical / bridge / bond / VLAN / vm), MAC address, state (up / down), MTU, and the underlying physical interface for non-physical types."
},
{
"block": "Bond Members",
"contents": "Only for bonds. Lists each enslaved NIC with the active / failed flag, the bond mode (active-backup / 802.3ad / balance-alb / …) and the primary interface when configured."
},
{
"block": "IP Addresses",
"contents": "Every IPv4 / IPv6 address with the prefix length. Auto-configured link-local addresses are listed but greyed out."
},
{
"block": "Historical chart",
"contents": "RX / TX bandwidth over the selected timeframe (1 hour / 24 hours / 7 days / 30 days / 1 year), pulled from <code>/api/network/&lt;interface&gt;/metrics</code> (Proxmox RRD)."
},
{
"block": "Traffic since last boot",
"contents": "Total RX / TX bytes and packets since the host last booted, plus error and drop counters."
}
],
"inactiveTitle": "Inactive interfaces still open the drill-in",
"inactiveBody": "For an interface that is <em>down</em>, the modal renders a small \"Interface Inactive\" banner and skips the live counters. Configuration (addresses, bond members) and historical data are still shown — useful when diagnosing why something failed and when."
},
"latency": {
"heading": "Network Latency modal",
"intro": "Clicking the <em>Network Latency</em> card in the top row opens a dedicated modal. It has two modes (historical and on-demand test), three target options and a downloadable PDF report.",
"targetsTitle": "Targets",
"targetsIntro": "A target dropdown at the top of the modal selects what gets pinged:",
"targets": [
"<strong>Gateway</strong> — your LAN router. Tests the local-network leg only; useful when you suspect a switch / cabling issue and want to rule out the WAN.",
"<strong>Cloudflare (1.1.1.1)</strong> — public DNS resolver, anycast network. Tests the WAN leg.",
"<strong>Google (8.8.8.8)</strong> — alternative public target, useful as a sanity check or when Cloudflare is regionally degraded."
],
"mode1Title": "Mode 1 — Historical view",
"mode1Alt": "Network Latency modal in historical mode — Gateway target with a 1-hour timeframe and the past samples plotted",
"mode1Caption": "Historical view — Gateway target over the last hour, fed from the latency-history database written every 60 seconds by the temperature/latency collector thread.",
"mode1Body1": "The default mode when the modal opens. A second dropdown picks the timeframe (<em>1 Hour / 24 Hours / 7 Days / 30 Days / 1 Year</em>); data resolution drops with the window so the chart stays readable. Headline stats — Current / Min / Avg / Max — render above the chart, with a status pill (Excellent / Good / Fair / Poor) reflecting the current value against the thresholds below.",
"mode1Body2": "Source: the same latency samples the Health Monitor uses to detect persistent network slowdowns — sampled every 60 seconds against the gateway by the background <code>_temperature_collector_loop</code> thread, written to a local SQLite history.",
"mode2Title": "Mode 2 — Real-time test",
"mode2Alt": "Network Latency modal running a real-time ping test against Cloudflare — progress bar at 50%, live samples accumulating on the chart",
"mode2Caption": "Real-time test against Cloudflare — 2-minute run with one reading every 5 seconds, samples plotted as they arrive. Click <em>Stop</em> to end early; <em>Test Again</em> appends more samples to the same dataset.",
"mode2Intro": "Switching the target to Cloudflare or Google starts an on-demand ping test. Behaviour:",
"mode2Items": [
"<strong>Duration</strong> — 2 minutes per run, with a progress bar and a remaining-seconds counter.",
"<strong>Cadence</strong> — one reading every 5 seconds (24 readings per run).",
"<strong>Method</strong> — ICMP Echo Request (<code>ping</code>), 3 consecutive pings per sample, latency averaged.",
"<strong>Stop</strong> — ends the test immediately; partial data is preserved.",
"<strong>Test Again</strong> — appends new samples to the existing dataset rather than starting fresh, so you can build a longer record across several runs.",
"<strong>Live status pill</strong> — re-evaluates after every sample using the same Excellent / Good / Fair / Poor thresholds."
],
"thresholdsTitle": "Performance thresholds",
"headerStatus": "Status",
"headerRange": "Range",
"headerImpact": "Practical impact",
"thresholdRows": [
{
"status": "Excellent",
"range": "< 50 ms",
"impact": "Optimal for real-time apps, gaming and video calls."
},
{
"status": "Good",
"range": "50 100 ms",
"impact": "Acceptable for most applications with minimal impact."
},
{
"status": "Fair",
"range": "100 200 ms",
"impact": "Noticeable delay. May affect VoIP and interactive apps."
},
{
"status": "Poor",
"range": "> 200 ms",
"impact": "Significant latency. Investigation recommended."
}
],
"reportTitle": "Network Latency Report (PDF)",
"reportIntro": "Both modes have a <strong>Report</strong> button next to the target selector. Clicking it generates a PDF with everything you'd send to your ISP if you wanted to make a case for poor service.",
"reportPreviewAlt": "First page of the Network Latency Report PDF — Executive Summary with the gauge, latency statistics, the latency graph and the threshold guide",
"reportPreviewCaption": "First page of the Network Latency Report — Executive Summary with the gauge dial and headline stats, the per-second latency graph, and the threshold guide. Page 2 onwards has the per-sample table and methodology.",
"downloadLabel": "Download sample Network Latency report (PDF)",
"sectionsIntro": "The report has six sections:",
"sections": [
"<strong>Executive Summary</strong> — gauge dial (0300+ ms with green / yellow / red zones), the status verdict (EXCELLENT / GOOD / FAIR / POOR), the target / mode / sample count and a one-line packet-loss summary.",
"<strong>Latency Statistics</strong> — Current / Min / Avg / Max as four large tiles, plus Sample Count, Packet Loss (avg) and Test Period.",
"<strong>Latency Graph</strong> — area chart of every sample over the test window with a min/avg/max y-axis grid.",
"<strong>Performance Thresholds</strong> — the same four-tier scale documented above, with a coloured dot per tier.",
"<strong>Detailed Test Results</strong> — numbered table with timestamp, latency, packet loss and status for every sample. Useful for spotting micro-bursts that the headline averages hide.",
"<strong>Methodology</strong> — test method (ICMP Echo Request), samples per test (3 consecutive pings), target name, target IP and a final \"Performance Assessment\" paragraph derived from the verdict."
],
"useCaseTitle": "Use case: claims to your ISP",
"useCaseBody": "Run the real-time test against Cloudflare for 2 minutes during a moment of perceived slowness, then click <em>Test Again</em> a few times to extend the dataset, and finally <em>Report</em>. The PDF carries the full per-sample table plus the methodology block — ISPs typically accept this as evidence, especially when correlated with timestamps from a separate complaint."
},
"excluding": {
"heading": "Excluding noisy interfaces",
"body1": "Like storages, individual interfaces can be excluded from health monitoring — useful for intentionally disabled bridges, test interfaces or NICs that are physically removed but still in the config. The flag is stored in the <code>excluded_interfaces</code> table and respected by the Health Monitor cycle: no warnings, no notifications, no contribution to the header status pill.",
"body2": "From the row's context menu, pick <em>Exclude from monitoring</em>. The interface stays visible in the dashboard with a purple <strong>excluded</strong> badge, and you can re-enable monitoring from the same menu."
},
"dataCollected": {
"heading": "How the data is collected",
"headerSection": "Section of the tab",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"section": "Interface inventory",
"endpoint": "/api/network",
"source": "<code>ip -j addr</code> + <code>ip -j link</code> + bond / bridge introspection."
},
{
"section": "Summary cards",
"endpoint": "/api/network/summary",
"source": "Aggregation over the inventory plus per-interface up/down counts."
},
{
"section": "Per-interface RX/TX time series",
"endpoint": "/api/network/<iface>/metrics",
"source": "<code>/proc/net/dev</code> sampled by the Health Monitor with byte-rate calculation."
},
{
"section": "Latency: current",
"endpoint": "/api/network/latency/current",
"source": "A short <code>ping</code> burst against the configured gateway / target."
},
{
"section": "Latency: historical",
"endpoint": "/api/network/latency/history",
"source": "Persisted samples — every 5 min by the Health Monitor cycle."
}
],
"codeComment1": "# Cross-check the interface state seen by the dashboard",
"codeComment2": "# Verify a current latency probe end-to-end"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the Network category and the latency-history thresholds."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the network and latency endpoints."
},
{
"label": "Integrations",
"href": "/docs/monitor/integrations",
"tail": " — Prometheus scrape exposes the same network metrics."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other tabs."
},
{
"label": "ProxMenux → Network",
"href": "/docs/network",
"tail": " — the actions side: bridge analysis, persistent interface names, backup & restart, iperf3."
}
]
}
}
@@ -0,0 +1,246 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Security tab | ProxMenux Documentation",
"description": "The Security tab groups every protection-related control in two columns: ProxMenux Monitor (Authentication, SSL/HTTPS, API tokens, Secure Gateway) and Proxmox VE (Firewall, Fail2Ban, Lynis audit). Step-by-step Secure Gateway wizard, Lynis audit walkthrough, Fail2Ban install and rule tuning."
},
"header": {
"title": "Dashboard: Security tab",
"description": "Every security control in the dashboard, grouped into two clearly-labelled blocks: configuration of the Monitor itself (auth, SSL, tokens, Secure Gateway) and configuration of the Proxmox host it watches (firewall, Fail2Ban, Lynis).",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "Two scopes, one tab",
"body": "The Security tab is divided into two clearly separated sections: <strong>ProxMenux Monitor</strong> (settings for the dashboard itself) and <strong>Proxmox VE</strong> (settings for the host underneath). Cards render conditionally — Fail2Ban and Lynis only appear once installed."
},
"monitor": {
"heading": "ProxMenux Monitor",
"intro": "Four cards control how the dashboard itself is reached and authenticated."
},
"auth": {
"heading": "Authentication",
"imageAlt": "Authentication card showing status Enabled, Logout, Change Password, Two-Factor Authentication info, Enable Two-Factor Authentication and Disable Authentication buttons",
"imageCaption": "Authentication card with auth enabled — status badge, Change Password, Enable 2FA and the (destructive) Disable Authentication action.",
"intro": "The card lets you manage the dashboard's own login. The full first-launch flow, password policy, TOTP enrolment screens and lost-authenticator recovery are documented in <link>Access & Authentication</link> — this card is the day-to-day surface for those settings:",
"items": [
"<strong>Authentication Status</strong> — badge showing <em>Enabled</em> / <em>Disabled</em> / <em>Declined</em>.",
"<strong>Change Password</strong> — current password + new password + confirmation.",
"<strong>Enable / Disable Two-Factor Authentication</strong> — opens the QR enrolment dialog when enabling, asks for the current password when disabling.",
"<strong>Disable Authentication</strong> — destructive action that re-shows the first-launch <em>Protect your dashboard?</em> dialog on next visit."
]
},
"ssl": {
"heading": "SSL / HTTPS",
"imageAlt": "SSL / HTTPS card showing HTTP No SSL status, detected Proxmox host certificate with Subject, Issuer, Expires, Use Proxmox Certificate button and Use Custom Certificate option",
"imageCaption": "SSL / HTTPS card with HTTPS off. The Monitor detects the certificate already installed on the Proxmox host and offers it as a one-click option, with a fallback to <em>Use Custom Certificate</em> if you have your own files elsewhere.",
"intro": "Serves the dashboard over HTTPS without any reverse proxy in front. The card auto-detects the certificate that Proxmox itself uses (under <code>/etc/pve/local/</code>) and shows the subject, issuer and expiry so you can verify it before activating. Two paths to enable HTTPS:",
"items": [
"<strong>Use Proxmox Certificate</strong> — one click. The Monitor reuses the certificate installed on the host. Good fit for users who already have their PVE running on the same DNS name as the dashboard.",
"<strong>Use Custom Certificate</strong> — paste absolute paths to your own <code>.pem</code> certificate and <code>.key</code> private key. The paths are validated before the service restarts; if loading fails, the dashboard falls back to HTTP automatically (no broken state)."
],
"enabledAlt": "SSL/HTTPS card with HTTPS Enabled status, Active Certificate showing pve-ssl.pem and pve-ssl.key paths, and a Disable HTTPS button",
"enabledCaption": "HTTPS active — the card surfaces the certificate currently in use, the file paths and a <em>Disable HTTPS</em> action that drops back to HTTP on the same port.",
"acmeTitle": "ACME / Let's Encrypt via Proxmox",
"acmeBody": "If your Proxmox node already has Let's Encrypt configured at <em>Datacenter → Certificates → ACME</em>, that's the certificate the host serves to browsers — and that's what the dashboard reuses when you click <em>Use Proxmox Certificate</em>. You don't need separate ACME plumbing for the Monitor.",
"walkthroughLink": "For a step-by-step walkthrough — including how the Monitor auto-detects the ACME-uploaded certificate, what gets written to disk, and how to fall back to a custom <code>.pem</code> / <code>.key</code> pair — see <link>HTTPS for ProxMenux Monitor</link>."
},
"apiTokens": {
"heading": "API Access Tokens",
"emptyAlt": "API Access Tokens card empty state with About API Tokens info box and Generate New API Token button",
"emptyCaption": "API Access Tokens card on a fresh installation — the <em>About API Tokens</em> box summarises lifetime, usage and how to embed the token in <code>Authorization: Bearer</code> headers.",
"intro": "Long-lived tokens (1 year) for unattended integrations — Homepage widgets, Home Assistant REST sensors, Grafana scrapers, n8n flows, custom scripts. The card walks you through three states: empty → form → generated.",
"generateBody": "<strong>Generate a token.</strong> Click <em>Generate New API Token</em>. The form asks for a descriptive <em>Token Name</em> (helps you identify it in the active list later) and your <em>password</em> as second-factor confirmation. If 2FA is enabled, the form additionally asks for the current TOTP code.",
"generateAlt": "API Access Tokens generate form with Token Name input, Password input, Generate Token and Cancel buttons",
"generateCaption": "The Generate API Token form — fill in a name and confirm with your password (and TOTP if 2FA is on).",
"saveBody": "<strong>Save the token immediately.</strong> The full token string is shown <strong>only once</strong> after generation. The card highlights this with an amber notice and a copy button. There's no way to retrieve it later — you'll only see the prefix in the Active Tokens list.",
"generatedAlt": "API token generated successfully with masked token, copy button, instructions for Authorization Bearer header and Active Tokens list with prefix",
"generatedCaption": "Token generated — the value is shown once with a copy button and the exact <code>Authorization: Bearer</code> snippet. Below, the Active Tokens list keeps name + prefix + creation date so you can revoke individual tokens later.",
"outro": "The card shows every active token with a <em>Revoke</em> button per row. Revoking invalidates the token immediately; any integration using it stops working from that moment. Cookbooks for Homepage, Home Assistant, n8n and Prometheus are in <link>Integrations</link>."
},
"gateway": {
"heading": "Secure Gateway",
"cardAlt": "Secure Gateway card with Deploy Secure Gateway button before any gateway has been deployed",
"cardCaption": "Secure Gateway card on a fresh setup — one button starts the wizard.",
"intro": "Reach the dashboard, the Proxmox web UI and any guest from anywhere on your <a>Tailscale</a> tailnet, without exposing any port to the public internet. The Monitor deploys an Alpine LXC container on the host running <code>tailscaled</code> as a subnet router; once approved in the Tailscale admin console, your remote devices reach the host's LAN IP from anywhere.",
"wizardTitle": "Step-by-step wizard",
"wizardIntro": "Before clicking <em>Deploy Secure Gateway</em>, generate an auth key in your Tailscale admin console — the wizard will ask for it in step 2.",
"step0Title": "0. Generate the Tailscale auth key",
"step0Body": "Sign in to <a>login.tailscale.com/admin/settings/keys</a> and click <em>Generate auth key…</em>. Choose a <em>pre-authenticated</em> key (so the gateway doesn't need an interactive Tailscale login), and copy the value — it's shown only once.",
"step0Alt": "Tailscale admin console Settings Keys page with Generate auth key button highlighted",
"step0Caption": "Tailscale admin console — <em>Settings → Keys → Generate auth key…</em>. Use a free Tailscale account if you don't have one yet (link inside the wizard).",
"step1Title": "1. Open the wizard",
"step1Body": "Back on the Security tab, click <em>Deploy Secure Gateway</em>. The first step is an intro with what you'll get and what you need.",
"step1Alt": "Secure Gateway Setup wizard intro step explaining what the gateway provides: VPN access, no port forwarding, end-to-end encryption",
"step1Caption": "Step 1 — overview of what the Secure Gateway provides and a reminder that you'll need a free Tailscale account.",
"step2Title": "2. Tailscale Authentication",
"step2Body": "Paste the auth key from step 0 and pick a hostname (this is what the gateway will appear as in the Tailscale admin console — typically <code>proxmox-gateway</code> or your node name).",
"step2Alt": "Secure Gateway wizard step asking for Tailscale Auth Key and Device Hostname with link to generate the key",
"step2Caption": "Step 2 — paste the pre-auth key and choose the device hostname. The link below the field opens the Tailscale page from step 0 if you skipped ahead.",
"step3Title": "3. Access Scope",
"step3Intro": "Choose what your tailnet can reach through the gateway:",
"step3Items": [
"<strong>Proxmox Only</strong> — only the Proxmox UI and the Monitor. Smallest attack surface.",
"<strong>Full Local Network</strong> — the entire LAN subnet (auto-detected from the host's primary interface). Lets you reach NAS, printers, VMs and any other LAN device.",
"<strong>Custom Subnets</strong> — list specific CIDRs. For multi-VLAN setups where you want to expose some segments but not others."
],
"step3Alt": "Secure Gateway wizard Access Scope step with three options: Proxmox Only, Full Local Network, Custom Subnets",
"step3Caption": "Step 3 — pick the access scope. <em>Full Local Network</em> auto-fills with the detected LAN subnet.",
"step4Title": "4. Advanced Options (optional)",
"step4Intro": "Two optional toggles. Both are <strong>off by default</strong>:",
"step4Items": [
"<strong>Exit Node</strong> — when enabled and selected from a remote device, all that device's internet traffic exits through the Proxmox host's WAN. Useful for travel scenarios where you want your phone's traffic to look like home.",
"<strong>Accept Routes</strong> — let this gateway reach networks advertised by <em>other</em> tailnet subnet routers (for multi-site setups)."
],
"step4Alt": "Secure Gateway wizard Advanced Options step with Exit Node and Accept Routes checkboxes",
"step4Caption": "Step 4 — Exit Node and Accept Routes. Skip both if all you want is dashboard access from your phone or laptop.",
"step5Title": "5. Review & Deploy",
"step5Body": "Final summary before the deploy starts. The wizard reminds you that one manual step in Tailscale admin is still pending after deploy: <strong>approving the subnet route</strong>.",
"step5Alt": "Secure Gateway wizard Review and Deploy step with Configuration Summary showing hostname, access mode, networks, exit node, accept routes and a Deploy Gateway button",
"step5Caption": "Step 5 — review the configuration and deploy. The blue notice at the bottom flags the pending route approval.",
"approvalTitle": "One last manual step in Tailscale admin",
"approvalBody": "After deploy, go back to <a>login.tailscale.com/admin/machines</a> and approve the subnet route the gateway is advertising. Until you do, remote devices on your tailnet won't actually be able to reach LAN IPs through the gateway. Tailscale marks pending routes with a yellow warning on the device row — click <em>Edit route settings</em> and tick the route box."
},
"pve": {
"heading": "Proxmox VE",
"intro": "The host's own protections — firewall, intrusion prevention and security audit. Last two only render when their respective tools are installed."
},
"firewall": {
"heading": "Proxmox Firewall",
"imageAlt": "Proxmox Firewall card showing Cluster Firewall and Host Firewall status, Quick Access Rules for ProxMenux Monitor and Proxmox Web UI, Rules Overview counters and a list of Firewall Rules with Add Rule button",
"imageCaption": "Proxmox Firewall card — cluster-level and host-level enable / disable toggles, common ports as <em>Quick Access Rules</em>, totals across <em>Rules Overview</em>, and the full rule list with <em>+ Add Rule</em>.",
"intro": "The card surfaces the Proxmox VE built-in firewall (which is independent from any host-level <code>iptables</code> / <code>nftables</code> you may run alongside). Three blocks:",
"items": [
"<strong>Cluster Firewall + Host Firewall</strong> — global toggles. The cluster firewall must be active for any host-level rule to take effect; the card flags this dependency inline.",
"<strong>Quick Access Rules</strong> — pre-defined rows for ports that matter to ProxMenux itself: <code>8008/TCP</code> (Monitor), <code>8006/TCP</code> (Proxmox Web UI). Each row shows the current allow / deny / unprotected state. The Proxmox Web UI is allowed via the <em>built-in</em> Proxmox firewall macro and can't be removed accidentally.",
"<strong>Rules Overview</strong> — counters for total rules, accept rules, drop / reject rules and distinct ports protected. Numbers are read from <code>/etc/pve/firewall/cluster.fw</code> and <code>/etc/pve/nodes/&lt;node&gt;/host.fw</code>.",
"<strong>Firewall Rules</strong> — full list with action / protocol / port / source / level. <em>+ Add Rule</em> opens an inline editor; the trash icon on each row removes the rule. Edits write to the same files Proxmox uses, so changes also appear in the Proxmox UI (Datacenter / Node → Firewall)."
]
},
"fail2ban": {
"heading": "Fail2Ban",
"subHeading": "(conditional)",
"whatIs": "<strong>What it is.</strong> Fail2Ban is an open-source intrusion-prevention daemon that watches log files for repeated failed login attempts and bans the offending IP at the firewall level. It's the de-facto answer to brute-force scanners that hit SSH and web login forms 24/7. ProxMenux wires it to three jails by default: SSH, the Proxmox web UI login (port 8006), and the ProxMenux Monitor login (port 8008).",
"notBundled": "Fail2Ban is <strong>not bundled</strong>. The card detects whether it's installed and adapts: when missing it offers a one-click install; once installed it shows live jail status, banned IPs and lets you tune retries / ban time per jail.",
"notInstalledAlt": "Fail2Ban card showing Not Installed state with explanation of what it would configure: SSH, Proxmox web UI and ProxMenux Monitor protection with nftables backend, plus an Install and Configure Fail2Ban button",
"notInstalledCaption": "Fail2Ban card before install — the blue box previews what the install would configure.",
"clickBody": "Click <em>Install and Configure Fail2Ban</em> and you get a confirmation modal listing every change the script will make on the host:",
"confirmAlt": "Install Fail2Ban confirmation modal listing SSH protection aggressive mode, Proxmox web interface protection port 8006, ProxMenux Monitor protection port 8008, auto-detected nftables backend, journald log level adjustment and SSH MaxAuthTries hardening",
"confirmCaption": "Install confirmation — explicit list of jails, tweaks to journald log level (so the auth jail can read SSH events) and an SSH-hardening side effect (<code>MaxAuthTries=3</code>).",
"confirmIntro": "Confirmation triggers a streaming install panel (apt + jail config + tests). Same plumbing as the ProxMenux CLI installer.",
"progressAlt": "Fail2Ban Installation panel showing live install log: package install, journald MaxLevelStore tuned for auth logging, jails configured, nftables backend detected, MaxAuthTries hardening, fail2ban-client communication test, completion message",
"progressCaption": "Install in progress — every step is logged in the panel. Connection-closed at the bottom marks the end of the streaming session.",
"afterInstall": "After install the card flips to the live status view: jails configured, banned IPs counter, recent ban events. The big tabs split <em>Jails & Banned IPs</em> from <em>Recent Activity</em> (the last N entries from the Fail2Ban log).",
"activeAlt": "Fail2Ban card after install with Active status, three jails configured (proxmenux, proxmox, sshd), Banned IPs counter, Total Bans, Failed Attempts, and per-jail rows with retries, ban time, window and gear icon",
"activeCaption": "Fail2Ban active — the three default jails (<code>proxmenux</code>, <code>proxmox</code>, <code>sshd</code>) with their retries / ban time / window settings.",
"tuneBody": "<strong>Tune jail rules.</strong> Click the gear icon on any jail row to adjust <em>Max Retries</em>, <em>Ban Time</em> (use a permanent ban if you want offenders blocked until you manually unban) and <em>Find Time</em> (the rolling window for counting retries). Common values are documented inside the form.",
"configAlt": "Configure sshd jail form with Max Retries, Ban Time in seconds with Permanent Ban option, Find Time, common values reminder, and Save Configuration button",
"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, brute-force protection is best-effort",
"calloutBody": "ProxMenux Monitor has its own <em>application-level</em> ban hook in the Flask request pipeline — but it only takes effect if Fail2Ban is installed and writes to the bans table. Without Fail2Ban, the Monitor logs failed logins to <code>proxmenux-auth.log</code> for future inspection but doesn't actively block IPs."
},
"lynis": {
"heading": "Lynis Security Audit",
"subHeading": "(conditional)",
"whatIs": "<strong>What it is.</strong> Lynis is an open-source security auditing tool that runs ~280 tests across the host (file permissions, kernel hardening, SSH config, package vulnerabilities, crypto policy, scheduled tasks, banner grabbing, etc.) and produces a hardening score 0100, a list of warnings and a list of suggestions. It's the de-facto baseline for \"is this server in good shape\" on Debian-based servers.",
"whyUseful": "<strong>Why it's useful.</strong> Knowing the security posture of your server is hard to do by reading config files one by one. Lynis catches the things that are routinely overlooked: kernel hardening flags missing, weak SSH ciphers enabled, journal not persistent, sudoers <code>NOPASSWD</code> on default accounts, and many more. Re-running it after applying ProxMenux post-install tweaks gives you an objective number for the improvement.",
"notInstalledAlt": "Lynis Security Audit card with Not Installed state and Install Lynis button, listing features: hardening scoring, vulnerability detection, compliance checking and GitHub source",
"notInstalledCaption": "Lynis card before install — the blue box summarises what the tool does.",
"notBundled": "Lynis is also <strong>not bundled</strong>. ProxMenux installs the latest release directly from the official GitHub source (not the Debian package, which lags several minor versions).",
"confirmAlt": "Install Lynis confirmation modal listing what Lynis does: hardening scoring, vulnerability detection, configuration analysis, compliance checking, source from official GitHub repository",
"confirmCaption": "Install confirmation — explicit about the GitHub source.",
"progressAlt": "Lynis Installation streaming panel: installing latest scan tool, version 3.1.6 confirmed, installation completed message",
"progressCaption": "Install in progress — same streaming panel pattern as Fail2Ban.",
"afterInstall": "After install the card shows the version and an empty audit history. Click <em>Run Security Audit</em> to start the first scan.",
"installedAlt": "Lynis Security Audit card after install with version 3.1.6 Installed badge, Last Scan timestamp, Hardening Index 0, Warnings 0, Suggestions 0, an empty audit report row and a Run Security Audit button",
"installedCaption": "Lynis installed, no audit yet. The card prefills the metric tiles with zeros.",
"runningAlt": "Lynis Security Audit card while audit is running showing Security audit in progress message, estimated 2-5 minutes duration, and a disabled Running Audit button",
"runningCaption": "Audit in progress — the action button shows a spinner and the card explicitly warns that the scan can take 25 minutes.",
"finishedBody": "When it finishes, the card flips to the results view: hardening index, warnings, suggestions and an <em>Audit Reports</em> list with each historical scan.",
"resultsAlt": "Lynis Security Audit card with results: Hardening Index 71 with Lynis 66 PVE 71 breakdown, 3 warnings, 40 suggestions, Security Hardening Score progress bar Proxmox Adjusted 71 of 100 in the Good range, audit reports list with PDF download and Run Security Audit button",
"resultsCaption": "Audit results — Hardening Index <strong>71/100 (Good)</strong> on a sample run. The card also shows the \"Lynis raw score\" (66) versus the Proxmox-adjusted score (71) which adds back 11 points for findings the Lynis test corpus flags but are expected behaviour on Proxmox VE.",
"scoreTitle": "Lynis raw score vs Proxmox-adjusted score",
"scoreIntro": "Lynis ships rules tuned for general-purpose Debian. Proxmox legitimately diverges from some of them (services running as root for cluster reasons, custom <code>journald</code> tuning, etc.). The card shows both numbers so you can:",
"scoreItems": [
"Track your <em>Lynis raw score</em> the same way external auditors would.",
"Track the <em>Proxmox-adjusted</em> score — a fairer baseline if you're comparing nodes inside the same cluster."
],
"reportBody": "<strong>The full report.</strong> Each audit row in the list has a <em>PDF</em> button that downloads a multi-page report with the executive summary, system info, security posture, every warning with explanation, every suggestion ranked by impact, and the package inventory. It's the artifact you would attach to a security review.",
"reportAlt": "Sample first page of the Lynis Security Audit Report PDF showing executive summary with hardening 71 of 100, warnings and suggestions counts, system information block with hostname, kernel, Lynis version, report date, security posture overview",
"reportCaption": "First page of a downloaded report — executive summary, system information and security posture overview. The full report continues with detailed warnings, suggestions and the installed-packages list. A <a>sample PDF</a> is attached for reference.",
"runPeriodically": "Run the audit periodically (after major Proxmox upgrades, after applying post-install tweaks, before opening a remote-access path) and keep the reports — the trend matters more than any single number.",
"outro": "The full <em>What it installs / how it's configured / how to uninstall</em> walkthrough and a written sample report breakdown are in <link>ProxMenux → Security → Lynis</link>."
},
"dataCollected": {
"heading": "How the data is collected",
"headerCard": "Card",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"card": "Authentication, 2FA, password change",
"endpoint": "/api/auth/*",
"source": "Local SQLite + JWT issued by the Monitor."
},
{
"card": "SSL / HTTPS",
"endpoint": "/api/auth/ssl/*",
"source": "<code>openssl x509</code> on <code>/etc/pve/local/pve-ssl.pem</code> + <code>/etc/proxmenux/ssl_config.json</code>."
},
{
"card": "API tokens list / mint / revoke",
"endpoint": "/api/auth/api-tokens",
"source": "Token rows kept locally; nothing leaves the host."
},
{
"card": "Secure Gateway (deploy + status)",
"endpoint": "/api/oci/*",
"source": "Provisions Alpine LXC + <code>tailscaled</code> via <code>pct create</code> / <code>pct exec</code>."
},
{
"card": "Firewall status & rules",
"endpoint": "/api/security/firewall/*",
"source": "<code>pve-firewall</code> + <code>/etc/pve/firewall/&lt;cluster|host&gt;.fw</code>."
},
{
"card": "Fail2Ban (only when installed)",
"endpoint": "/api/security/fail2ban/*",
"source": "<code>fail2ban-client status</code>, <code>/var/log/fail2ban.log</code>, <code>/etc/fail2ban/jail.local</code>."
},
{
"card": "Lynis audit (only when installed)",
"endpoint": "/api/security/lynis/*",
"source": "Runs <code>lynis audit system</code> in the background; report parsed from <code>/var/log/lynis-report.dat</code>."
}
]
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — full first-launch flow, 2FA app picker, lost-authenticator recovery, reverse-proxy snippets."
},
{
"label": "Integrations",
"href": "/docs/monitor/integrations",
"tail": " — cookbooks for using API tokens with Homepage, Home Assistant, Prometheus, n8n and the Secure Gateway end-to-end."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tailRich": " — every <code>/api/auth</code>, <code>/api/security</code> and <code>/api/oci</code> endpoint with method, body and curl examples."
},
{
"label": "ProxMenux → Security → Fail2Ban",
"href": "/docs/security/fail2ban",
"tail": " — install walkthrough, jails configured, manual install path."
},
{
"label": "ProxMenux → Security → Lynis",
"href": "/docs/security/lynis",
"tail": " — sample report, score interpretation, when to re-run."
}
]
}
}
@@ -0,0 +1,327 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Settings tab | ProxMenux Documentation",
"description": "The Settings tab groups dashboard preferences (network units, suppression durations, storage / interface exclusions), the embedded notification + AI panel, and a transparent inventory of every ProxMenux post-install optimization currently active on the host with click-through to its source code."
},
"header": {
"title": "Dashboard: Settings tab",
"description": "Dashboard preferences, monitoring exclusions, the embedded notification + AI configuration panel, and a live inventory of the ProxMenux post-install optimizations currently active on the host.",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "Where each setting actually lives",
"body": "The Settings tab is a single surface for several distinct concerns: how the dashboard renders, what gets watched by the Health Monitor, how alerts go out, and what ProxMenux has already changed on the host. Cards that have their own deep documentation page link out rather than duplicating content here — Settings is the entry point, not the manual."
},
"networkUnits": {
"heading": "Network Units",
"imageAlt": "Network Units card with Network Unit Display dropdown set to Bytes",
"imageCaption": "Choose between bits per second and bytes per second for every network rate displayed in the dashboard.",
"body": "Choose how network throughput is displayed across the dashboard: <strong>bits per second</strong> (Mbps / Gbps) or <strong>bytes per second</strong> (MB/s / GB/s). Bits is the default because it's what NIC vendors and ISPs label their products with; bytes is what most file-transfer tools report. The setting affects every chart, badge and tooltip that shows network rate — applied immediately, no reload needed."
},
"health": {
"heading": "Health Monitor",
"intro": "The card surfaces the per-category <strong>Suppression Duration</strong> setting — once an alert is dismissed, how long before the scanner is allowed to re-fire it. Each of the ten Health Monitor categories (CPU, Memory, Storage, Disks, Network, VMs, PVE Services, Logs, Updates, Security) has its own dropdown with these values:",
"items": [
"<strong>24 h</strong> — default for most transient categories.",
"<strong>72 h</strong> — for events you want a few days of silence on.",
"<strong>168 h</strong> (1 week) and <strong>720 h</strong> (1 month) — periodic checks.",
"<strong>8760 h</strong> (1 year) — effectively \"quiet for the foreseeable future\".",
"<strong>-1</strong> — permanent silence until you re-enable it manually.",
"<strong>Custom hours</strong> — any integer if you need an in-between value."
],
"imageAlt": "Settings → Health Monitor card with the per-category suppression dropdowns and the Active Suppressions section",
"imageCaption": "Health Monitor card — the per-category dropdowns set defaults for new dismisses; the Active Suppressions section below lists every alert currently silenced and lets you revert them.",
"editTitle": "Edit mode",
"editBody": "The card is read-only by default. Click <strong>Edit</strong> in the top-right of the card to enable the dropdowns and the Re-enable buttons. <strong>Save</strong> commits every pending change (suppression-duration changes and queued re-enables) in a single batch; <strong>Cancel</strong> discards them all. The Save button only activates when there is at least one pending change.",
"activeTitle": "Active Suppressions",
"activeIntro": "Below the suppression-duration dropdowns, the <strong>Active Suppressions</strong> section lists every alert that is currently silenced — both time-limited dismisses (24 h, 7 days, custom windows) and <em>Permanent</em> ones. Each row shows:",
"activeItems": [
"A coloured badge — <strong>Permanent</strong> (amber) or a countdown such as <strong>24h remaining</strong> / <strong>7d remaining</strong> (blue).",
"The alert identifier, normalized for readability (e.g. <code>pve_storage_full_PBS-Cloud</code> → <em>PVE Storage Full: PBS-Cloud</em>).",
"Category, severity and the timestamp the alert was dismissed.",
"A <strong>Re-enable</strong> button (active only in Edit mode) that queues the alert to be un-acknowledged on the next Save."
],
"activeReenableTitle": "Re-enable flow",
"activeReenableBody": "Clicking <strong>Re-enable</strong> in Edit mode marks the row in green and strikes its identifier — it is queued but not yet applied. Click again on the same row to <strong>Undo</strong> the queue. When you press <strong>Save</strong>, every queued re-enable fires <code>POST /api/health/un-acknowledge</code> in parallel and the affected rows disappear from the list. If the underlying condition is still present and the category supports re-firing, the alert reappears in the Health Monitor's Active list on the next scan cycle.",
"activePermanentNote": "Permanent dismisses (alerts dismissed with <em>Permanently</em> from the Health Monitor modal, or those whose category default is set to <code>-1</code>) <strong>can only be reverted from here</strong>. The dashboard modal does not expose an un-dismiss button for them — the Active Suppressions panel is the single audit log + revert UI.",
"activeAutoRefreshTitle": "Auto-refresh",
"activeAutoRefreshBody": "The list refreshes automatically when you dismiss or un-dismiss an alert from the Health Monitor modal (via an in-browser event), when the browser tab regains focus, and on visibility change. You do not need to reload the page after dismissing an alert from the dashboard.",
"calloutTitle": "Full semantics live in the Health Monitor page",
"calloutBody": "The escalation rules (when a re-fire becomes critical), the auto-resolve behaviour for events whose underlying device disappears, and the difference between dismissed and resolved — all documented under <link>Health Monitor → Dismissing alerts and the Suppression Duration</link>. This card just exposes the per-category dropdowns and the Active Suppressions panel."
},
"thresholds": {
"heading": "Health Monitor Thresholds",
"intro": "Where the previous card decides <em>how long to stay quiet after a dismiss</em>, this one decides <strong>at what value an alert fires in the first place</strong>. Every check the Health Monitor runs is parameterised by a pair of numbers — a <strong>Warning</strong> threshold and a <strong>Critical</strong> threshold — and both are exposed here for the operator to tune.",
"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": [
"A small homelab with a single-disk SSD may want to page earlier on capacity (75 / 90 %) to leave room for snapshots.",
"A datacenter host with redundant Ceph nodes can be more relaxed on memory warnings (a 90 % working set is normal under ZFS ARC).",
"A passively-cooled mini-PC needs lower temperature thresholds than a server with forced-air cooling — same drive class, different physical envelope.",
"A heavily-virtualized host that pegs CPU during builds should not page on every 80 % spike, but must still alert on sustained pressure."
],
"whatForOutro": "Editing a threshold takes effect <strong>on the next scan</strong> — the Health Monitor re-reads the values from <code>/usr/local/share/proxmenux/health_thresholds.json</code> on every cycle, no service restart needed. The same numbers also feed the colour ranges of the dashboard widgets (the temperature line in the disk-temperature modal, the bars on the storage cards) so the visual classification matches what triggers the alert.",
"coloursTitle": "Status colours: how Warning and Critical render in the dashboard",
"coloursIntro": "Every threshold below produces the same three-state classification across the dashboard — same colours for storage bars, CPU/memory rings, temperature chips, and the dot on the disk modal. Reading a colour anywhere in the Monitor maps to a definite range relative to the configured pair:",
"headerColour": "Colour",
"headerRange": "Range",
"headerMeaning": "Meaning",
"colourRows": [
{
"colour": "Green",
"range": "value < Warning",
"meaning": "Normal operating range. No alert fires."
},
{
"colour": "Amber",
"range": "Warning ≤ value < Critical",
"meaning": "Warning state. The Health Monitor fires a WARNING-severity event; notifications respect the channel filters and Quiet Hours."
},
{
"colour": "Red",
"range": "value ≥ Critical",
"meaning": "Critical state. The Health Monitor fires a CRITICAL event; CRITICAL bypasses Quiet Hours and always reaches the channel."
}
],
"sectionsTitle": "Sections and recommended defaults",
"sectionsIntro": "These are the values ProxMenux ships with — the recommended baseline. They're what you see on a fresh host until you override anything. Sections are ordered top-to-bottom from <em>compute</em> → <em>heat</em> → <em>storage capacity</em> so reading down moves from concrete (current load) to accumulated state (free space).",
"headerSection": "Section",
"headerWarning": "Warning",
"headerCritical": "Critical",
"headerGates": "What it gates",
"thresholdRows": [
{
"section": "CPU usage",
"warning": "85 %",
"critical": "95 %",
"gates": "Sustained-load alert when CPU averages above the threshold for the scan window."
},
{
"section": "Memory",
"warning": "85 %",
"critical": "95 %",
"gates": "RAM pressure on the host."
},
{
"section": "Swap (critical only)",
"warning": "—",
"critical": "5 %",
"gates": "Swap actually being used. The number is intentionally low: a healthy Proxmox host should rarely touch swap, so even 5 % is a meaningful signal of RAM pressure."
},
{
"section": "CPU temperature",
"warning": "80 °C",
"critical": "90 °C",
"gates": "CPU package / core temperature reading from <code>lm-sensors</code>."
},
{
"section": "Disk temp — HDD",
"warning": "60 °C",
"critical": "65 °C",
"gates": "Standard spinning drives. Manufacturer envelope tops out around 6065 °C, so Critical is set right at the hard limit."
},
{
"section": "Disk temp — SSD",
"warning": "70 °C",
"critical": "75 °C",
"gates": "2.5'' / M.2 SATA SSDs — run cooler than NVMe but warmer than HDDs."
},
{
"section": "Disk temp — NVMe",
"warning": "80 °C",
"critical": "85 °C",
"gates": "NVMe drives run hotter by design; controllers self-throttle above ~85 °C, so Warning catches the climb before throttling kicks in."
},
{
"section": "Disk temp — SAS",
"warning": "55 °C",
"critical": "65 °C",
"gates": "Enterprise SAS drives share the same ~65 °C manufacturer limit as HDDs, but are normally deployed in rack chassis with active cooling. A reading at 55 °C already signals a cooling problem (failed fan, HVAC issue) <em>before</em> the drive itself is at risk — hence a lower Warning than HDD, not because SAS is less heat-tolerant."
},
{
"section": "Disk space — host",
"warning": "85 %",
"critical": "95 %",
"gates": "Capacity of <code>/</code> and every host mountpoint (<code>/var/lib/vz</code>, <code>/mnt/*</code>…)."
},
{
"section": "Disk space — LXC rootfs",
"warning": "85 %",
"critical": "95 %",
"gates": "Per-container root disk, evaluated against the rootfs size from PVE."
},
{
"section": "LXC mount points",
"warning": "85 %",
"critical": "95 %",
"gates": "Capacity of mountpoints inside running CTs (mp0, mp1, NFS, bind mounts). Excludes rootfs."
},
{
"section": "PVE storage",
"warning": "85 %",
"critical": "95 %",
"gates": "Block-style PVE storages (LVM, LVM-thin, ZFS-pool, RBD/Ceph, PBS)."
},
{
"section": "ZFS pool",
"warning": "85 %",
"critical": "95 %",
"gates": "ZFS pools at host level — independent of PVE registration."
}
],
"defaultsTitle": "Defaults, overrides and reset",
"defaultsBody": "The backend exposes a merged view: every section starts from the ProxMenux defaults (the values you see when the host is fresh) and you override only the knobs you care about. The card shows the <em>effective</em> value — the override if you set one, otherwise the default. A <strong>Reset</strong> button wipes every override and goes back to defaults across all sections at once.",
"validationTitle": "Validation",
"validationBody": "Saving rejects values that don't make sense (percentages outside 0100, critical below warning, negative temperatures). The frontend shows the inline error; the backend validates again before persisting, so the API can't be tricked into a broken threshold by a hand-crafted PUT."
},
"lxcDetection": {
"heading": "LXC Update Detection",
"imageAlt": "LXC Update Detection card with a single switch — when enabled, the Monitor periodically scans running Debian/Ubuntu/Alpine LXC containers for pending package updates.",
"imageCaption": "The toggle for the periodic <code>apt list --upgradable</code> / <code>apk list -u</code> scan across every running CT. Default is ON. The matching notification toggle in Notifications → Services only appears while detection is enabled.",
"intro": "A dedicated toggle for the LXC update scan, sitting between the Health Monitor Thresholds and the Notifications card. When ON, ProxMenux walks every running CT on the host and queries the in-container package manager for pending updates; results land in the Hardware tab badge counts and feed the <code>lxc_updates_available</code> notification. When OFF, the scan stops entirely (no <code>pct exec</code> calls) and any existing LXC entries in <code>managed_installs.json</code> are purged immediately, so the dashboard and the <code>/api/managed-installs</code> endpoint stop reporting LXC update state without waiting for the next 24h cycle.",
"whatRunsTitle": "What the scan actually runs",
"whatRunsIntro": "For each CT in <code>running</code> state with a supported package manager:",
"whatRunsItems": [
"<strong>Cache freshness gate.</strong> If the in-container apt/apk metadata cache is older than <strong>24 hours</strong>, a best-effort refresh runs first (<code>apt-get update -qq</code> on Debian/Ubuntu, <code>apk update</code> on Alpine) with a 60 s timeout. Any failure (no network, broken repo, timeout) is swallowed silently — the listing below still runs against whatever cache exists, so a transient repo issue can never make detection worse than before.",
"<strong>Listing.</strong> Then ProxMenux runs <code>apt list --upgradable</code> / <code>apk list -u</code> and parses the output into a structured count plus a sample of the top package names.",
"<strong>Per-CT dedup.</strong> A fingerprint built from count, security-count and the sorted top names is stored so a stable set of pending updates doesn't re-notify daily, while a meaningfully different set does."
],
"selfUpdateTitle": "CTs that self-update outside apt may legitimately report 0",
"selfUpdateBody": "Detection only sees what the in-container package manager knows about. A CT whose key software updates itself outside apt (Plex's <code>plexupdate</code> cron, Docker containers updated via <code>docker pull</code>, Frigate's built-in updater, etc.) will keep reporting low or zero apt updates even when the appliance is actively staying current — that's correct, not a bug. The apt-level base system on the same CT may still have its own pending updates, which the scan does surface.",
"refreshTitle": "Why the 24 h auto-refresh",
"refreshBody": "Long-running appliance CTs frequently end up with apt caches months out of date because nobody routinely runs <code>apt update</code> inside them. Without the refresh, <code>apt list --upgradable</code> reports 0 updates from a frozen snapshot and the operator never sees the backlog. The threshold matches the rest of the check cycle — if the CT was refreshed within the last 24 h, ProxMenux trusts that signal and skips the refresh.",
"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>. The Hardware tab badges drop to zero on the next dashboard refresh. Turning it back ON repopulates the registry on the next detection cycle (or sooner if you trigger a manual refresh from the API)."
},
"storageExclusions": {
"heading": "Remote Storage Exclusions",
"imageAlt": "Remote Storage Exclusions card listing PBS-Cloud, PBS and PBS2 storages with Health and Alerts toggles per row",
"imageCaption": "Per-storage <em>Health</em> and <em>Alerts</em> toggles. Storages with both toggles off stop counting against the Health Monitor and stop generating notifications — but still render on the Storage tab marked as excluded.",
"intro": "Mark Proxmox-managed storages (NFS / CIFS / PBS / Ceph / iSCSI / etc.) as excluded from monitoring. Two independent toggles per storage:",
"items": [
"<strong>Health</strong> — when off, the storage stops contributing to the Storage category of the Health Monitor. Useful for archive volumes that are intentionally offline most of the time or remote backup targets only powered up on schedule.",
"<strong>Alerts</strong> — when off, alerts about this storage no longer go out through configured channels, even if Health checks remain enabled. Useful when you want the dashboard view but not the notifications."
],
"outro": "Excluded storages still render on the <link>Storage tab</link> with a purple <em>excluded</em> badge so the entry doesn't silently disappear from your inventory. State is persisted in the <code>excluded_storages</code> SQLite table."
},
"interfaceExclusions": {
"heading": "Network Interface Exclusions",
"imageAlt": "Network Interface Exclusions card listing vmbr0, vmbr1, vmbr2, bond0 and eno1 with Health and Alerts toggles per interface",
"imageCaption": "Same shape as Storage Exclusions — per-interface <em>Health</em> and <em>Alerts</em> toggles. Each row shows the interface, type badge (bridge / bond / physical), the IP and the link speed.",
"intro": "Same shape as Storage Exclusions but for network interfaces. Per interface: exclude from Health checks and / or exclude from notifications. Typical use cases:",
"items": [
"An intentionally-down spare bridge.",
"A NIC that was physically removed but still references in <code>/etc/network/interfaces</code>.",
"A VLAN sub-interface used only during maintenance windows.",
"A management bridge that is up but doesn't carry traffic — flapping noisily on every cycle."
],
"outro": "State is persisted in the <code>excluded_interfaces</code> SQLite table. Same purple <em>excluded</em> badge on the <link>Network tab</link> so excluded interfaces stay visible."
},
"notifications": {
"heading": "Notifications & AI",
"body1": "This section of the Settings tab is where ProxMenux Monitor notifications and the AI rewriter are turned on. Pressing <em>Enable Notifications</em> starts the dispatch background thread, registers a Proxmox VE webhook target on the host so PVE-emitted events flow into the same pipeline, and unfolds the channel form so you can connect Telegram, Discord, Email, Gotify and the rest. The AI rewriter sits inside the same panel as a collapsible advanced section.",
"body2": "Both surfaces have a lot of moving parts — channels, per-event toggles, Rich messages, the Display Name, the dispatch pipeline (dedup, cooldown, aggregation, quiet hours), the PVE webhook integration, AI providers, prompt modes — and live on their own dedicated pages rather than being repeated here:",
"items": [
"<notifLink>Notifications</notifLink> — channel walk-throughs (Telegram, Discord, Gotify, Email + Gmail / Microsoft app passwords, ntfy, Slack, Teams, generic webhook), per-event categories, Rich messages, Display Name, dispatch pipeline, PVE webhook integration, history and API.",
"<aiLink>AI Assistant</aiLink> — providers (OpenAI, Anthropic, Gemini, Groq, OpenRouter, Ollama), model selection, prompt modes (default / custom), output language, per-channel detail levels and AI suggestions."
]
},
"optimizations": {
"heading": "ProxMenux Optimizations",
"intro": "A live, transparent inventory of every ProxMenux post-install optimization currently active on the host. Every time you apply a post-install option from the Scripts side — either via the <autoLink>Automated post-install</autoLink> or via the à-la-carte <customLink>Customizable post-install</customLink> — the corresponding script registers itself in <code>/usr/local/share/proxmenux/installed_tools.json</code>. The Monitor reads that file and renders this card so you can see, at a glance, what's been changed on your server.",
"imageAlt": "ProxMenux Optimizations card with grid of installed tools, each row showing a green dot, tool name and version. Examples include APT IPv4 Force, Bashrc Customization, Fastfetch, Log2ram SSD Protection, Memory Settings Optimization, Setting persistent network interfaces, System Limits Increase, APT Language Skip, Entropy Generation haveged with Legacy badge, Kernel Panic Configuration, Logrotate Optimization, Network Optimizations, Subscription Banner Removal, VFIO IOMMU Passthrough — 14 active total",
"imageCaption": "The card lists every active optimization with its name, version, a coloured dot and an orange <em>14 active</em> counter at the top right. Tools whose source is reachable are clickable.",
"dotsTitle": "What the dots mean",
"dotsItems": [
"<green/> <strong>Green dot</strong> — current optimization, registered by the active version of ProxMenux. Source code is reachable: click the row to open it.",
"<amber/> <strong>Amber dot + <em>legacy</em> badge</strong> — applied by an older ProxMenux version whose script has since been renamed or replaced. Still active on the host; the source opens in \"legacy\" mode (with an amber accent) so you can audit what was actually run."
],
"clickTitle": "Click-through to source code",
"clickBody": "Clicking a tool opens a modal with the exact bash function that applied the change, plus the script file path it lives in (<code>auto_post_install.sh</code> for the Automated bundle, <code>customizable_post_install.sh</code> for the à-la-carte side). Comments and shell constructs are syntax-highlighted; a Copy button puts the source on your clipboard. This is the \"show your work\" surface — verify what ProxMenux did to your host before any manual change you make on top.",
"detailAlt": "Tool source code modal for APT IPv4 Force showing the bash function force_apt_ipv4 from customizable_post_install.sh version 1.0 with syntax-highlighted code that configures /etc/apt/apt.conf.d/99-force-ipv4 with Acquire ForceIPv4 true, registers the tool and emits a translate APT IPv4 configuration completed message",
"detailCaption": "Source modal for <em>APT IPv4 Force</em> — exact <code>force_apt_ipv4()</code> function from <code>customizable_post_install.sh v1.0</code>, with syntax highlighting and a one-click Copy.",
"whyTitle": "Why this matters",
"whyBody": "ProxMenux changes things on your host: kernel parameters, repository configuration, network bits, log rotation, GPU passthrough, etc. Knowing exactly what's active is essential before you start adding manual customisation on top — and even more so if a different admin runs the host than the one who set it up. This card is the auditable record of every optimisation currently in effect, with the exact code that produced it.",
"updatesTitle": "Updates available banner",
"updatesBody": "When a post-install optimization gets a newer version on disk than the one currently registered on the host, the card shows an \"Updates available\" banner at the top with the count and an <strong>Apply</strong> button. Clicking <strong>Apply</strong> opens a per-optimization picker (the same one available from the Post-Install menu's <em>Apply available updates</em> entry). Pick which optimizations to lift; ProxMenux re-runs the corresponding function and refreshes the version in the registry. When everything is current the banner disappears.",
"updatesAlt": "ProxMenux Optimizations card with an Updates available banner at the top — count of pending updates plus an Apply button that opens the per-optimization picker",
"updatesCaption": "The banner only renders when at least one optimization has a newer version on disk. See <link>Apply Available Updates</link> for the full update flow and the Path-A equivalent in the shell menu.",
"revertTitle": "Reverting an optimization",
"revertBody": "The card is read-only — to undo an optimization, run the corresponding <link>Uninstall Optimizations</link> option from the ProxMenux Scripts menu. The uninstall step removes the entry from <code>installed_tools.json</code>, so it disappears from this card on the next refresh."
},
"dataCollected": {
"heading": "How the data is collected",
"headerCard": "Card",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"card": "Network Units",
"endpoint": "/api/settings",
"source": "Persisted in the dashboard's SQLite settings table."
},
{
"card": "Health Monitor durations",
"endpoint": "/api/health/settings",
"source": "Per-category suppression durations in the Health DB."
},
{
"card": "Storage / interface exclusions",
"endpoint": "/api/storage/exclusions, /api/network/exclusions",
"source": "SQLite tables <code>excluded_storages</code> and <code>excluded_interfaces</code>."
},
{
"card": "Notifications & AI panel",
"endpoint": "/api/notifications/*",
"source": "See the dedicated <notifLink>Notifications</notifLink> / <aiLink>AI Assistant</aiLink> pages."
},
{
"card": "ProxMenux Optimizations list",
"endpoint": "/api/proxmenux/installed-tools",
"source": "Reads <code>/usr/local/share/proxmenux/installed_tools.json</code>, written by <code>register_tool</code> calls inside the post-install scripts."
},
{
"card": "Optimization source-code modal",
"endpoint": "/api/proxmenux/tool-source",
"source": "Extracts the matching bash function from <code>auto_post_install.sh</code> or <code>customizable_post_install.sh</code> on the host."
}
]
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — channels, per-event toggles, channel overrides, history, test-send."
},
{
"label": "AI Assistant",
"href": "/docs/monitor/ai-assistant",
"tail": " — providers, models, prompt modes, languages, per-channel detail levels."
},
{
"label": "Health Monitor → Dismissing alerts and the Suppression Duration",
"href": "/docs/monitor/health-monitor#dismissing-alerts-and-the-suppression-duration",
"tail": " — the semantics behind the per-category dropdowns above."
},
{
"label": "ProxMenux Scripts → Automated post-install",
"href": "/docs/post-install/automated",
"tailRich": " and <customLink>Customizable post-install</customLink> — the actual scripts that register themselves in the optimization list above."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — how to revert an optimization registered above."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — back to the tab overview."
}
]
}
}
@@ -0,0 +1,268 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Storage tab | ProxMenux Documentation",
"description": "The Storage tab consolidates four views: Proxmox-managed storages with their state, ZFS pools, internal physical disks with SMART data, and external (USB) drives. Each disk drill-in exposes SMART attributes, wear & lifetime and the permanent observation history."
},
"header": {
"title": "Dashboard: Storage tab",
"description": "The host's storage state in one screen — Proxmox pools (NFS / CIFS / LVM / ZFS / dir), ZFS pool health, internal SATA / NVMe disks with SMART, and external USB drives. Click any disk to open a drill-in with the full SMART attribute table and the per-disk observation history.",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "Backed by three sources",
"body": "Proxmox storages come from <code>pvesm status</code>; ZFS state from <code>zpool status</code>; physical disks from <code>lsblk</code> + <code>smartctl</code> (and <code>nvme</code> for NVMe-specific fields). The tab refreshes every ~60 seconds; the per-disk drill-in triggers a fresh SMART read on demand."
},
"thresholds": {
"title": "Status colours and thresholds applied here",
"intro": "Every bar, chip, and dot on this tab follows the same three-state classification — <green/> <strong>green</strong> below Warning, <amber/> <strong>amber</strong> from Warning to Critical, <red/> <strong>red</strong> at Critical and above. Recommended defaults shipped with ProxMenux:",
"items": [
"<strong>Capacity</strong> (host disks, PVE storages, ZFS pools, LXC mounts) — Warning 85 %, Critical 95 %.",
"<strong>Disk temperature</strong> — HDD 60/65 °C · SSD 70/75 °C · NVMe 80/85 °C · SAS 55/65 °C (warning / critical)."
],
"outro": "Every value is configurable per host — <link>Settings → Health Monitor Thresholds</link> is the single source of truth and explains how to tune them."
},
"topRow": {
"heading": "Top row: storage at-a-glance",
"intro": "Opening the Storage tab lands you on a four-card summary of the host's storage state — total capacity, what's used locally, what's used on remote storages, and the physical-disk inventory. Each card is a one-line answer to a common question; the cards below the row are where you drill into the detail.",
"imageAlt": "Storage tab — top row of four stat cards: Total Storage, Local Used, Remote Used, Physical Disks",
"imageCaption": "Top row of the Storage tab — total capacity and disk count, used bytes split into local vs remote storages, and a typed breakdown of physical disks with their health summary.",
"headerCard": "Card",
"headerWhat": "What it shows",
"totalLabel": "Total Storage",
"totalWhat": "Combined raw capacity across every physical disk. Footer line shows the count of physical disks discovered.",
"localLabel": "Local Used",
"localWhat": "Bytes used on local storages (LVM / LVM-thin / ZFS / dir on the host's own disks). Shows the used bytes prominently, with a footer line of <em>X.XX % of Y TB</em> so you see the fill-percentage at the same time.",
"remoteLabel": "Remote Used",
"remoteWhat": "Same shape as Local Used but for remote storages (NFS / CIFS / PBS / Ceph / iSCSI). Counted separately because remote outages don't affect local data and you typically size and monitor them differently.",
"disksLabel": "Physical Disks",
"disksIntro": "Two lines of breakdown for the inventory:",
"disksItems": [
"<strong>By type</strong> — counts of NVMe (purple), SSD (blue) and HDD (blue) discovered. Mixed-disk hosts get all three; an all-NVMe host shows only the NVMe count.",
"<strong>By health</strong> — counts of <em>normal</em> (green), <em>warning</em> (yellow) and <em>critical</em> (red) disks. The healthy state usually shows just \"X normal\"; warnings and critical only appear when something escalated."
]
},
"pveStorage": {
"heading": "Proxmox Storage card",
"intro": "One row per storage configured in <code>/etc/pve/storage.cfg</code>. Each row shows the type badge (<code>nfs</code> / <code>cifs</code> / <code>zfspool</code> / <code>lvm</code> / <code>lvmthin</code> / <code>dir</code> / <code>pbs</code>), the storage name, an active / error / not-monitored badge, the usage percentage and a coloured progress bar:",
"items": [
"<strong>&lt; 75 %</strong> — blue progress bar, value in blue.",
"<strong>75 90 %</strong> — yellow progress bar, value in yellow (Health Monitor warns at this point).",
"<strong>> 90 %</strong> — red progress bar, value in red (Health Monitor escalates).",
"<strong>error</strong> — full row outlined in red, used when the storage is configured but unreachable (NFS server down, CIFS creds expired).",
"<strong>excluded</strong> — purple outline + the badge \"not monitored\". Storages explicitly excluded by the user from health checks (handy for manual / archive volumes that are intentionally offline)."
],
"calloutTitle": "Excluding a noisy storage",
"calloutBody": "From the storage row, the per-storage menu lets you mark it as <em>excluded from monitoring</em>. The flag is stored in the <code>excluded_storages</code> table and respected by both the dashboard view and the Health Monitor cycle — no notifications fire for excluded storages, and they don't bump the header pill."
},
"zfs": {
"heading": "ZFS Pools card",
"intro": "Renders only when ZFS is installed and at least one pool exists. One row per pool with a health badge, size / allocated / free, and an icon mirroring the health state:",
"items": [
"<strong>ONLINE</strong> — green. Everything healthy.",
"<strong>DEGRADED</strong> — yellow. Pool is serving data but at least one device is unavailable; replacement window starts.",
"<strong>FAULTED</strong> / <strong>UNAVAIL</strong> / <strong>SUSPENDED</strong> — red. Pool not serving data; immediate intervention required."
],
"outro": "Both ZFS state and the per-disk SMART status feed the <em>Disks & I/O</em> category of the <link>Health Monitor</link>."
},
"physical": {
"heading": "Physical Disks & SMART Status",
"intro": "Internal disks (SATA / NVMe). Each row condenses the most useful fields at a glance:",
"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 that marks disks the host's OS is running from. The dashboard derives this from the mountpoints of <code>/</code> and <code>/boot</code>: any physical disk hosting them gets the <em>System</em> tag so you don't accidentally wipe or repurpose it. Disks without the tag are pure data drives.",
"<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).",
"<strong>SMART status</strong> — passed / failed / unknown.",
"<strong>Observations badge</strong> — when the permanent <code>disk_observations</code> history has un-dismissed entries for this disk, a blue badge with the count appears (e.g. <em>3 obs.</em>). Click the disk to drill in and review them.",
"<strong>Health badge</strong> — Healthy / Warning / Critical, derived from the SMART check + recent observations."
],
"clickHint": "The whole row is clickable and opens the per-disk drill-in described below.",
"warningTitle": "Don't touch System-tagged disks lightly",
"warningBody": "Disks with the orange <strong>System</strong> badge host the running OS. The dashboard surfaces the tag as a guard rail — destructive actions launched from <link>ProxMenux → Disk Manager → Format / Wipe</link> explicitly refuse to act on them. If you really need to repurpose the boot disk, do it from a rescue environment, not from inside Proxmox."
},
"external": {
"heading": "External Storage (USB)",
"body": "A separate card for USB-attached drives, only renders when at least one is present. Same fields as internal disks plus an orange <strong>USB</strong> tag. USB drives often appear and disappear (cold backups, occasional offload jobs), so the Health Monitor is conservative about them — observations are retained, but I/O errors on a disconnected USB drive don't escalate."
},
"drillIn": {
"heading": "Disk drill-in modal",
"intro": "Clicking any disk row opens a four-tab modal: <strong>Overview</strong> · <strong>SMART</strong> · <strong>History</strong> · <strong>Schedule</strong>. The header always shows the device path, the model + capacity and the orange <em>System</em> badge if applicable.",
"overviewTitle": "Tab 1 — Overview",
"overviewImageAlt": "Disk drill-in modal — Overview tab with health status, Wear & Lifetime ring, and quick SMART attributes",
"overviewImageCaption": "Overview tab — identity, health badge, life-remaining ring with current wear and data written, plus a quick block of the most-watched SMART attributes.",
"overviewIntro": "The default landing tab — everything you need to answer \"is this disk OK?\" without running a test. Three blocks:",
"overviewItems": [
"<strong>Identity</strong> — model, serial, capacity, Health badge (Healthy / Warning / Critical).",
"<strong>Wear & Lifetime</strong> — large life-remaining ring (97 %, 50 %, …) with the source attribute spelled out (<em>Media Wearout Indicator</em>, <em>Percentage Used</em>, …), a wear bar (current consumption %), an <em>Est. Life</em> projection in years and the total Data Written. NVMe drives also show <em>Available Spare</em>.",
"<strong>SMART Attributes</strong> — six headline fields on a 2-column grid: Temperature, Power On Hours (with humanised duration like <em>3y 116d</em>), Rotation Rate (or <em>SSD</em>), Power Cycles, SMART Status, Reallocated Sectors, Pending Sectors, CRC Errors. The full attribute table lives in the SMART tab."
],
"smartTitle": "Tab 2 — SMART",
"smartImageAlt": "Disk drill-in modal — SMART tab with Run SMART Test buttons (Short / Extended), last-test result and the full SMART attribute table",
"smartImageCaption": "SMART tab — run a Short or Extended test, see the last-test outcome, scroll the full SMART attribute table, and generate the full PDF health report.",
"smartIntro": "Where the actions live. Three sections:",
"smartItems": [
"<strong>Run SMART Test</strong> — two buttons. <em>Short Test (~2 min)</em> runs synchronously and shows the result inline. <em>Extended Test (background)</em> can take hours on big drives, runs server-side and fires a notification when it completes.",
"<strong>Last Test</strong> — type, status badge (<em>passed</em> / <em>failed</em>) and timestamp of the most recent run.",
"<strong>SMART Attributes</strong> — the full attribute table (ID / name / value / worst / status with OK / warning / critical icons). For SATA / SAS, the classical numbered list. For NVMe, the structured fields from <code>nvme smart-log</code> (temperature, available spare, percentage used, data units written / read, host reads / writes, controller busy time, power cycles, unsafe shutdowns, media errors, error-log entries, warning / critical composite temperature time)."
],
"pdfTitle": "View Full SMART Report (PDF)",
"pdfIntro": "At the bottom of the SMART tab, the <strong>View Full SMART Report</strong> button generates a printable, archive-ready PDF — the same structured report you'd send to a vendor for an RMA.",
"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 five top-level 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).",
"<strong>SSD Wear & Lifetime</strong> (SSD / NVMe only) — life-remaining ring, source attribute, current wear level, data written, power-on hours.",
"<strong>SMART Attributes (full)</strong> — every attribute the drive reports, with ID, name, value, worst, threshold, raw value and a status pill. The most user-relevant ones (Reallocated Sector Ct, Power On Hours, Reported Uncorrect, UDMA CRC Error Count, Media Wearout Indicator, …) include a one-line plain-language explanation under the row.",
"<strong>Last Self-Test Result + Full Self-Test History</strong> — the latest test (type, result, completion message, at which power-on-hours mark) plus a numbered table of every retained test.",
"<strong>Recommendations</strong> — action items based on the verdict: <em>Disk is Healthy / Schedule periodic tests / Backup strategy</em> for healthy drives, escalating language with replacement guidance when attributes are out of range."
],
"pdfOutro": "The PDF is produced server-side and downloaded with a stable filename pattern (<code>SMART-&lt;short-id&gt;.pdf</code>) so multiple snapshots over time can sit side-by-side in your archive. Useful when you're tracking degradation across months or sending evidence to vendor support.",
"historyTitle": "Tab 3 — History",
"historyImageAlt": "Disk drill-in modal — History tab listing past SMART tests with download and delete actions",
"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 raw <code>smartctl -a</code> output as a text file. Identical to what the PDF report parses, useful when you need the exact line a vendor asks for.",
"<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",
"scheduleImageAlt": "Disk drill-in modal — Schedule tab with the toggle for Automatic SMART Tests, the configured-schedules list and the Add Schedule button",
"scheduleImageCaption": "Schedule tab — pick test type, frequency and retention; the Monitor wires it into <code>cron</code> so tests run unattended.",
"scheduleIntro": "Cron-driven automatic SMART tests, no shell needed. The page has three areas:",
"scheduleItems": [
"<strong>Automatic SMART Tests toggle</strong> — global on/off switch for every schedule on this disk. Useful when you want to pause everything during maintenance without losing the schedule definitions.",
"<strong>Configured Schedules</strong> — one row per existing schedule with the test type badge (<em>short</em> / <em>long</em>), the cron expression in human form (<em>\"Day 1 of month at 03:00\"</em>, <em>\"Every Sunday at 02:00\"</em>), the disks it covers and the retention setting.",
"<strong>Add Schedule / Edit Schedule</strong> — form with: Test Type (<em>Short ~2 min</em> / <em>Long 1-4 h</em>), Frequency (<em>Daily / Weekly / Monthly</em>), Day of Month / Day of Week, Time, Keep Results (<em>Last 5 / 10 / 20</em>)."
],
"scheduleOutro": "The schedule is materialised as a cron entry on the host that calls back into the Monitor; results are saved to the same SMART history shown in Tab 3, and the retention setting auto-prunes the oldest test when a new one finishes.",
"tempTitle": "Temperature history modal",
"tempIntro": "Every disk that exposes a temperature sensor has its readings sampled continuously by the Monitor and persisted to a local time-series. The current value appears as one of the six headline SMART attributes in the Overview tab; clicking that block opens a dedicated temperature-history modal with the full picture.",
"tempImageAlt": "Disk temperature history modal — header with the disk path and model, a timeframe selector (1 Hour / 24 Hours / 7 Days / 30 Days), a row of four stat cards (Current / Min / Avg / Max), and a line chart of the temperature over the selected range coloured by the per-disk-type thresholds",
"tempImageCaption": "Temperature detail — opens from the Overview tab on any disk whose sensor returns a non-zero reading. The chart is coloured against the disk-type threshold (HDD / SSD / NVMe / SAS).",
"tempShowsTitle": "What the modal shows",
"tempShowsItems": [
"<strong>Timeframe selector</strong> with four ranges: <em>1 Hour</em>, <em>24 Hours</em> (default), <em>7 Days</em>, <em>30 Days</em>. Each one queries the same backend with a different downsampling so the chart stays readable at every horizon.",
"<strong>Four stat cards</strong> at the top of the modal: <em>Current</em>, <em>Min</em>, <em>Avg</em>, <em>Max</em> for the selected range. The <em>Current</em> card is coloured by the same status thresholds the Storage tab and the notifications use, so you can see at a glance whether the disk is in normal / warm / hot territory.",
"<strong>Line chart</strong> of the temperature over time, with the line and shaded area coloured by disk type:"
],
"tempDiskTypes": [
"HDD — typically cooler thresholds.",
"SSD — moderate thresholds.",
"NVMe — higher thresholds (NVMe runs hotter by design).",
"SAS — same defaults as HDD."
],
"tempConfigurable": "All four are configurable from <em>Settings → Health Monitor Thresholds</em>.",
"tempWhyTitle": "Why a history matters here",
"tempWhyItems": [
"<strong>Drift detection.</strong> Disks that progressively heat up over weeks (failing fan, dust build-up, neighbour disk dying and pushing hot air across) are invisible to a single \"current temperature\" readout. The 7-day and 30-day views surface the drift.",
"<strong>Spike correlation.</strong> When a backup window or a rebuild pushed the disk briefly over its threshold, the 1-hour and 24-hour ranges show whether it was a one-off or a recurring pattern.",
"<strong>Threshold tuning.</strong> Before raising or lowering a threshold in <em>Settings → Health Monitor Thresholds</em>, the 30-day chart shows the disk's actual operating range so the new value lines up with what the hardware really does rather than a guess."
],
"obsTitle": "Observation history (across tabs)",
"obsIntro": "Modern disks fail gradually. A disk can report SMART <strong>PASSED</strong> and still log occasional read errors in dmesg, drop SATA links, or expose pending sectors that come and go. The standard Proxmox UI shows you the current SMART verdict — it does not keep a history of those <em>signals</em>. ProxMenux does, and surfaces them right inside the disk modal.",
"obsImageAlt": "Disk Details modal Overview tab showing a healthy disk with SMART status Passed, 0 reallocated/pending/CRC errors, and an Observations section listing one recorded I/O Error event with the raw kernel message, a human translation of the ATA error code, first and last occurrence timestamps and an occurrence count",
"obsImageCaption": "A disk that <strong>SMART says is fine</strong> can still have an observation history. The card is the historical signal layer underneath the SMART verdict.",
"obsWhatTitle": "What an observation is",
"obsWhatIntro": "Anything ProxMenux catches in the kernel log, dmesg or SMART output that looks like a disk-level event — and that on its own would be too granular for a notification — is recorded as an <strong>observation</strong>. Each row shows:",
"obsWhatItems": [
"<strong>Type badge</strong> (I/O Error, SMART Error, Filesystem Error, ZFS Pool Error, Connection Error).",
"<strong>Raw kernel message</strong> as it appeared in dmesg — useful when copy-pasting into a search engine or a support ticket.",
"<strong>A human one-liner</strong> under the raw message for known ATA codes (<code>IDNF</code> → \"Sector address not found — possible bad sector or cable issue\", <code>UNC</code> → \"Uncorrectable read error — bad sector\", and the rest of the standard codes).",
"<strong>First and last occurrence timestamps</strong>, plus an <strong>occurrence count</strong> deduplicated by error signature."
],
"obsWhyTitle": "Why ProxMenux records and shows them",
"obsWhyItems": [
"<strong>Disk failure is rarely a single event.</strong> It usually starts with sporadic ATA bus errors, the odd UNC sector, or a couple of medium errors weeks before SMART flips to <em>FAILED</em>. Without persistence those early warnings disappear from dmesg on the next boot.",
"<strong>SMART can lie.</strong> A drive can show all attributes green and still be on the way out — the observation layer catches the symptoms SMART doesn't expose (especially ICRC, IDNF, link resets at lower SATA speeds).",
"<strong>It separates \"is happening now\" from \"happened recently\".</strong> The Health Monitor auto-resolves transient errors as soon as they stop firing, which is great for keeping the active alert list clean — but you still want to see, days later, that this disk had three I/O errors that night. The observation table is the answer.",
"<strong>It feeds the tiered notification model.</strong> The disk_io detector reads observation rate from this table to decide silent / WARNING / CRITICAL (the sliding 24h window introduced in 1.2.1.2). The history is what makes that classification possible."
],
"obsDedupTitle": "How dedup and re-notification work",
"obsDedupBody1": "Observations are deduplicated by their <strong>signature</strong> — a stable fingerprint of the error type, device and key fields of the kernel line. The same event repeating bumps the <code>occurrence_count</code> on the existing row rather than creating a new one. A <strong>different signature</strong> on the same disk creates a new observation and is treated as a new event for notification purposes.",
"obsDedupBody2": "Notifications follow an anti-cascade rule: the first occurrence of a given (disk, signature, severity) combination pages the operator, and ProxMenux then waits 24 hours before pinging again about the same combination — even if the count keeps climbing. Escalating severity (WARNING → CRITICAL) breaks the cooldown so the operator is told when things get worse, not just when they happen.",
"obsDismissTitle": "Dismissing vs resolving",
"obsDismissBody1": "Each row has a <strong>dismiss</strong> action. Dismissing an observation tells ProxMenux \"I've seen this, stop notifying me about it\". It does <strong>not</strong> freeze the occurrence counter — if the same fault keeps happening the count keeps climbing in the background, ready to alert again if it ever escalates to a different severity tier or signature. A dismissed observation stays visible on the card with a muted style, so a future operator can still see \"this disk had history here\".",
"obsDismissBody2": "Resolving on the active-error side (Health Monitor) is independent of observation dismiss — the observation persists past the active error's auto-resolve. That's the whole point: it survives, so a transient warning from last week is still visible on the disk card today. See <link>Health Monitor</link> for the active-error side of the same picture."
},
"dataCollected": {
"heading": "How the data is collected",
"headerSection": "Section of the tab",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"section": "Top summary cards",
"endpoint": "/api/storage/summary",
"source": "Aggregated from <code>lsblk</code>, <code>zpool list</code>, <code>vgs</code> / <code>lvs</code>."
},
{
"section": "Per-disk inventory",
"endpoint": "/api/storage",
"source": "<code>lsblk -O</code> + <code>smartctl -i</code> per device, with stable disk identity cache (cleared on hot-plug events)."
},
{
"section": "Proxmox storages",
"endpoint": "/api/proxmox-storage",
"source": "<code>pvesh get /nodes/&lt;node&gt;/storage</code> with the active/online state of each."
},
{
"section": "SMART current values",
"endpoint": "/api/storage/smart/<disk>",
"source": "<code>smartctl -A &lt;dev&gt;</code> — refreshed on demand, not cached."
},
{
"section": "SMART self-test history",
"endpoint": "/api/storage/smart/<disk>/history",
"source": "Stored under <code>/var/lib/proxmenux-monitor/smart/&lt;disk&gt;/</code> as JSON snapshots."
},
{
"section": "Permanent observations",
"endpoint": "/api/storage/observations",
"source": "SQLite table fed by the Health Monitor every cycle (kept across auto-resolve)."
}
],
"outro": "Verifying the collection chain on the host:",
"codeComment1": "# Pull the current snapshot from a script",
"codeComment2": "# Cross-check what the dashboard sees against the raw OS view"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the disks-and-I/O category and the suppression model."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the storage and SMART endpoints."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tailRich": " — what <code>disk_io_error</code>, <code>storage_unavailable</code> and <code>smart_test_failed</code> trigger downstream."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other tabs."
},
{
"label": "ProxMenux → Disk Manager",
"href": "/docs/disk-manager",
"tail": " — the actions side: format / wipe / SMART tests / import disks into VMs and CTs from the TUI."
},
{
"label": "ProxMenux → SMART Disk Health & Test",
"href": "/docs/disk-manager/smart-disk-test",
"tail": " — the CLI counterpart of this tab: schedule SMART tests, export the JSON the dashboard renders, and the deeper test-type / interpretation reference."
}
]
}
}
@@ -0,0 +1,120 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: System Logs tab | ProxMenux Documentation",
"description": "The System Logs tab consolidates three sources into one screen: live journalctl with filters and download, Proxmox task history (UPIDs), and notification log — all searchable, filterable by severity / time range, and downloadable as text bundles."
},
"header": {
"title": "Dashboard: System Logs tab",
"description": "Three sub-tabs under one roof: the system journal (journalctl with filters), Proxmox task history, and the notification log. All three are searchable, filterable and downloadable as text bundles.",
"section": "ProxMenux Monitor · Dashboard"
},
"readOnly": {
"title": "Read-only by design",
"body": "Nothing on this tab modifies log files. Filters live in the URL / state, downloads are server-side bundles. The dashboard never deletes log entries — for housekeeping use the host's own <code>journalctl --vacuum-time=&lt;N&gt;</code> or <code>logrotate</code>."
},
"topRow": {
"heading": "Top row: four counters",
"items": [
"<strong>Total Entries</strong> — number of log records inside the active filter window.",
"<strong>Errors</strong> — count of severity ≤ 3 (<code>err</code> / <code>crit</code> / <code>alert</code> / <code>emerg</code>).",
"<strong>Warnings</strong> — count of severity 4 (<code>warning</code>).",
"<strong>Backups</strong> — count of vzdump / PBS task entries in the same window."
]
},
"subtabs": {
"heading": "Three sub-tabs",
"logsTitle": "Logs",
"logsIntro": "The system journal, served by <code>journalctl</code> on the backend. Filters available in the toolbar:",
"logsFilters": [
"<strong>Severity</strong> — emerg / alert / crit / err / warning / notice / info / debug, or any combination.",
"<strong>Time range</strong> — last 5 min / 15 min / 1 h / 6 h / 24 h / 7 d / custom.",
"<strong>Free-text search</strong> — substring or regex (<code>journalctl --grep</code>).",
"<strong>Unit filter</strong> — restrict to a specific systemd unit (<code>pveproxy.service</code>, <code>nginx.service</code>, …)."
],
"logsRowsAfter": "Each row shows timestamp, severity badge, source unit and the message. Long messages collapse with a \"show more\" toggle. The <strong>Download</strong> action bundles the current filter into a single <code>.txt</code> file via <code>GET /api/logs/download</code> — useful when you want to share a slice of journal with someone.",
"logDetailsModalTitle": "Log Details modal",
"logDetailsBody": "Clicking any row opens a <strong>Log Details</strong> modal with every structured field journald captured for that single entry — the same view you'd build by hand running <code>journalctl --output=verbose</code> on the host.",
"logDetailsImageAlt": "Log Details modal — single journal entry expanded with Level, Service, Timestamp, Source, Systemd Unit, Process ID, Hostname and the full Message",
"logDetailsImageCaption": "Log Details modal — every structured field journald carries for this entry, with the full untruncated message at the bottom. Useful for cron and service logs where the executed command line matters.",
"fieldsIntro": "Fields shown:",
"fields": [
"<strong>Level</strong> — coloured severity badge (INFO / WARNING / ERROR / CRITICAL).",
"<strong>Service</strong> — short name of the unit / process that emitted the entry.",
"<strong>Timestamp</strong> — full date and time of the log line.",
"<strong>Source</strong> — origin of the entry (journal, kernel, audit, …).",
"<strong>Systemd Unit</strong> — the actual <code>.service</code> / <code>.timer</code> / <code>.socket</code> unit if the entry was associated with one.",
"<strong>Process ID</strong> — PID of the emitting process.",
"<strong>Hostname</strong> — useful when journals are forwarded across cluster nodes.",
"<strong>Message</strong> — the full untruncated message in a monospace block, ready to copy."
],
"maxLevelStoreTitle": "Journald MaxLevelStore",
"maxLevelStoreBody": "On a fresh Proxmox install, journald defaults to <code>MaxLevelStore=warning</code>, which silently drops info-level messages. The Monitor detects this on startup and adds a drop-in (<code>/etc/systemd/journald.conf.d/proxmenux-loglevel.conf</code>) raising the threshold to <code>info</code> so the Logs tab actually has something to show across all severities.",
"backupsTitle": "Backups",
"backupsBody": "Proxmox task history filtered to backup-related entries. One row per task (<code>vzdump</code>, PBS transfers, Garbage Collect, Verify) with the status (OK / WARNINGS / ERROR), guest involved, source storage, duration and the UPID. Click a row to load the full task log via <code>GET /api/task-log/&lt;upid&gt;</code> — the same data Proxmox exposes through <em>Datacenter → Tasks</em>, scoped to backups.",
"notificationsTitle": "Notifications",
"notificationsBody1": "Every notification dispatched by the Monitor — Telegram, Discord, Email, Gotify, ntfy, Slack, Teams, webhook. Each row: timestamp, channel, event type, severity, the rendered title, the rendered body, and (if AI is enabled) a toggle to view the AI rewrite next to the original.",
"notificationsBody2": "Use this tab to verify a channel is actually delivering and to compare what the AI rewrite produced vs the template baseline. Channel configuration lives in the <link>Notifications</link> deep page."
},
"dataCollected": {
"heading": "How the data is collected",
"headerSubtab": "Sub-tab",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"subtab": "Logs (live filter)",
"endpoint": "/api/logs",
"source": "<code>journalctl --output json --since &lt;range&gt;</code> with severity / unit / search filters applied server-side."
},
{
"subtab": "Download",
"endpoint": "/api/logs/download",
"source": "Same query, returned as plain text for grep / less."
},
{
"subtab": "Backups",
"endpoint": "/api/backups",
"source": "PVE task history filtered by <code>vzdump</code>, PBS transfers, Garbage Collect, Verify."
},
{
"subtab": "Backup task drill-in",
"endpoint": "/api/task-log/&lt;upid&gt;",
"source": "Plain-text full task log read from <code>/var/log/pve/tasks/&lt;index&gt;/&lt;upid&gt;</code>."
},
{
"subtab": "Notifications history",
"endpoint": "/api/notifications/history",
"source": "SQLite <code>notification_history</code> table fed by the dispatch loop."
}
],
"apiIntro": "Both the live filter and the downloads are also reachable via the API:",
"codeComment1": "# Last hour of errors and worse, with a keyword",
"codeComment2": "# Download the full journal of the last 6 hours as plain text",
"codeComment3": "# Look up the full output of a specific task by UPID"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the System Logs category that watches for persistent / spike / cascade patterns."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — the journal watcher reads the same source and turns matches into notifications."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the logs and task-log endpoints with their query parameters."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other tabs."
}
]
}
}
@@ -0,0 +1,153 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: System Overview tab | ProxMenux Documentation",
"description": "The default landing tab of ProxMenux Monitor: four metric cards (CPU, Memory, Active VMs & LXCs, Temperature) with live updates and sparkline, the historical metrics chart, and condensed Storage and Network panels with click-through to their dedicated tabs."
},
"header": {
"title": "Dashboard: System Overview tab",
"description": "The first tab the dashboard opens on. Four live metric cards across the top, the historical-metrics chart in the middle, and condensed storage / network panels at the bottom — all derived from the same APIs that drive the dedicated tabs.",
"section": "ProxMenux Monitor · Dashboard"
},
"readOnly": {
"title": "A read-only snapshot",
"body": "Nothing on this tab is a control surface — every panel is informational. Actions live in the dedicated tabs they link to: drill into Storage to manage disks, into VMs & LXCs to start / stop guests, into the Security tab to configure auth, and so on."
},
"captureAlt": "System Overview tab — four metric cards (CPU, Memory, Active VMs, Temperature), node metrics chart, and Storage / Network summary cards",
"captureCaption": "The System Overview tab — what the dashboard opens on. The four cards are live, the chart below is historical, and the two cards at the bottom summarise Storage and Network.",
"topRow": {
"heading": "Top row: live metric cards",
"intro": "Four cards in a 2×2 grid on mobile, single row on desktop. Each updates from <code>/api/system</code> every few seconds.",
"headerCard": "Card",
"headerWhat": "What it shows",
"headerSource": "Source",
"rows": [
{
"card": "CPU Usage",
"what": "Current percentage with a progress bar. Updates ~1 s via the vital-signs sampler.",
"source": "psutil.cpu_percent()"
},
{
"card": "Memory Usage",
"what": "Used GB, percentage, total GB. Progress bar tracks the percentage.",
"source": "psutil.virtual_memory()"
},
{
"card": "Active VM & LXC",
"what": "Count of currently running guests, with a Running / Stopped breakdown badge and a footer line for total VMs and LXCs.",
"source": "/api/vms (consolidated)"
},
{
"card": "Temperature",
"what": "CPU temperature in °C with status badge (cool / warm / hot) and a 5-minute sparkline behind it. Shows <em>N/A</em> when no sensor is detected. Click to open the temperature detail modal.",
"source": "sensors / coretemp"
}
],
"thresholdsTitle": "Status colours and thresholds applied here",
"thresholdsIntro": "Every ring, bar, and sparkline on the four metric cards follows the same classification — <green/> <strong>green</strong> below Warning, <amber/> <strong>amber</strong> from Warning to Critical, <red/> <strong>red</strong> at Critical and above. Recommended defaults shipped with ProxMenux:",
"thresholdsItems": [
"<strong>CPU usage</strong> — Warning 85 %, Critical 95 %.",
"<strong>Memory</strong> — Warning 85 %, Critical 95 % (Swap also fires Critical at 5 % used — a healthy Proxmox host should rarely touch swap).",
"<strong>CPU temperature</strong> — Warning 80 °C, Critical 90 °C."
],
"thresholdsOutro": "Every value is configurable per host — <link>Settings → Health Monitor Thresholds</link> is the single source of truth and explains how to tune them.",
"sparklineTitle": "The sparkline is meaningful",
"sparklineBody": "The temperature card draws a 5-minute trace under the value, with the line and gradient colour following the same Warning/Critical pair documented above. It's the fastest way to see whether the host is in a thermal climb without opening the detail modal."
},
"middle": {
"heading": "Middle: node metrics charts",
"body1": "Below the top row sits the <code>NodeMetricsCharts</code> component — historical CPU, memory and disk-I/O graphs sourced from Proxmox's own RRD store via <code>/api/node/metrics</code>. A timeframe selector switches between <em>1 hour / 24 hours / 7 days / 30 days / 1 year</em>; data resolution drops as the window grows so the chart stays smooth.",
"body2": "These are the same graphs that the Proxmox web UI renders for a node, just consolidated into the Monitor's dark theme and aligned with the other panels."
},
"bottom": {
"heading": "Bottom row: Storage & Network summaries",
"storageTitle": "Storage Overview card",
"storageIntro": "A condensed view of the host's storage state, broken into three blocks:",
"storageItems": [
"<strong>Total Node Capacity</strong> — sum of all VM/LXC storages plus the local system storage, with a gradient progress bar of the total used / free split.",
"<strong>Total Capacity / Physical Disks</strong> — raw capacity headline and the count of physical disks discovered.",
"<strong>VM/LXC Storage</strong> — used / free / percentage for the storages where guests live, plus a counter when more than one is configured.",
"<strong>Local Storage (System)</strong> — the host's own root / system mount, separately from the guest pool."
],
"storageDrillIn": "Drill-in lives in the <link>Storage tab</link> — per-disk SMART, ZFS pool details, observation history, etc.",
"networkTitle": "Network Overview card",
"networkBody1": "Top line shows the count of active interfaces (physical + bridges combined). Below that, two rows of coloured badges for the interfaces that are <code>up</code> — physical NICs in blue, bridges in a secondary colour. A timeframe selector at the top right (1 hour / 24 hours / 7 days / 30 days / 1 year) controls a small RX / TX traffic chart.",
"networkBody2": "Per-interface drill-in (IP/MAC, RRD chart, bridge members, bond mode, etc.) lives in the <link>Network tab</link>."
},
"refresh": {
"heading": "Refresh model",
"intro": "Each panel manages its own loading state (<code>loadingStates.cpu</code>, <code>loadingStates.storage</code>, …) so a slow source doesn't block the rest. While a panel is fetching, it shows a pulse-animated skeleton; failed fetches degrade gracefully — for example, a missing temperature sensor renders the card as <em>N/A</em> instead of an error.",
"items": [
"<strong>Top metric cards</strong> — refresh every ~5 s. The CPU and temperature panels also receive a 1 s push from the vital-signs sampler.",
"<strong>Node metrics chart</strong> — refresh every 30 s, or on timeframe change.",
"<strong>Storage card</strong> — refresh every 60 s. SMART data is cached longer (the Storage tab triggers a fresh read on demand).",
"<strong>Network card</strong> — refresh every 5 s on the active timeframe.",
"<strong>Manual refresh</strong> — the Refresh button in the header forces all panels to re-fetch immediately."
]
},
"dataCollected": {
"heading": "How the data is collected",
"headerCard": "Card",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"card": "Header status pill",
"endpoint": "/api/health",
"source": "The cached overall status produced by the Health Monitor each cycle."
},
{
"card": "CPU / RAM / Swap / Uptime",
"endpoint": "/api/system",
"source": "<code>/proc/stat</code>, <code>/proc/meminfo</code>, <code>/proc/uptime</code> with short-window CPU sampling."
},
{
"card": "Host info (kernel, BIOS, distro)",
"endpoint": "/api/info",
"source": "<code>uname -a</code>, <code>dmidecode</code>, PVE version. Cached per process."
},
{
"card": "Storage / network / VMs cards",
"endpoint": "/api/storage/summary, /api/network/summary, /api/vms",
"source": "See the dedicated tabs for each. The header cards show a compacted view from the same endpoints."
},
{
"card": "Refresh cadence",
"endpoint": "—",
"source": "CPU / network 5 s; storage / VMs 30 s; static info every 5 min. The Refresh button in the header forces an immediate re-fetch on every panel."
}
],
"codeComment1": "# Single call that backs the header pill",
"codeComment2": "# public, no token",
"codeComment3": "# Authenticated snapshot used by the cards"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the modal behind the header status pill (ten categories, dismissals, suppression)."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the system, info and health endpoints."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — how the same statuses turn into Telegram / Discord / Email messages."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other eight tabs at a glance."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tail": " — the background threads and APIs that power this view."
}
]
}
}
@@ -0,0 +1,169 @@
{
"meta": {
"title": "ProxMenux Monitor — Dashboard: Terminal tab | ProxMenux Documentation",
"description": "Browser-based shell to the Proxmox host: up to 4 terminals at once with grid view, mobile-friendly keyboard helpers (ESC, TAB, arrows, Ctrl combos), an integrated commands cheatsheet powered by cheat.sh, JWT-protected."
},
"header": {
"title": "Dashboard: Terminal tab",
"description": "A real shell session in the browser, on the Proxmox host. Up to four terminals at once, mobile-friendly keyboard helpers, an integrated commands cheatsheet — all in the same theme as the rest of the dashboard.",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "A real PTY in the browser",
"body": "The terminal allocates a server-side PTY through <code>flask_terminal_routes</code>, pipes it over a WebSocket to <code>xterm.js</code> in the browser, and runs as <code>root</code> (the systemd unit's user). Anything you can do in <code>ssh root@&lt;host&gt;</code> works here — including <code>vim</code>, <code>tmux</code>, ncurses tools and Proxmox CLIs (<code>qm</code>, <code>pct</code>, <code>pvesh</code>, <code>pvecm</code>)."
},
"singleAlt": "ProxMenux Monitor Terminal tab — single terminal session showing Fastfetch system summary on login",
"singleCaption": "One host terminal open — the toolbar above shows the count (<em>1 / 4 terminals</em>), <em>+ New</em>, <em>Search</em>, <em>Clear</em> and <em>Close</em>. The mobile keyboard helpers appear under the terminal on touch devices.",
"target": {
"heading": "Connection target",
"body1": "The Terminal tab opens a shell on the <strong>Proxmox host itself</strong> — the same login you would get over SSH. Each tab opens a brand-new host terminal.",
"body2": "To reach an <strong>LXC container</strong> from the browser, use the dedicated <em>Console</em> button on every running CT card in the <link>VMs & LXCs tab</link>. It opens a modal that runs <code>pct enter &lt;vmid&gt;</code> and reuses the same mobile-friendly toolbar described below."
},
"fourTerminals": {
"heading": "Up to four terminals at once",
"intro": "The tab lets you open up to four host terminals simultaneously. Each one gets its own PTY and its own WebSocket — they are fully independent sessions. Two layouts switch with the icons next to the \"New\" button:",
"items": [
"<strong>Tabs view</strong> — one terminal visible at a time, the others as named tabs at the top (<em>Terminal 1</em>, <em>Terminal 2</em>…). Best for working on one task with the rest as background.",
"<strong>Grid view</strong> — all open terminals visible at once in a 2×2 grid. Useful for watching <code>htop</code> on one panel, <code>iftop</code> on another, and editing on a third without switching back and forth."
],
"outro": "The toolbar shows the current count (<em>1/4 terminals</em>, <em>4/4 terminals</em>). New tabs open with <strong>+ New</strong> and individual ones close from the small <code>×</code> on the tab header. The big red <strong>Close</strong> button at the top tears down all terminals at once."
},
"gridAlt": "ProxMenux Monitor Terminal tab — grid view with four host terminals running ls, network config, iftop and the ProxMenux main menu side by side",
"gridCaption": "Grid view (4 / 4 terminals) — four independent host PTYs running in parallel: directory listing, <code>/etc/network/interfaces</code> on one side, <code>iftop</code> on another, and the ProxMenux main menu on the fourth. Switch between grid and tabs with the layout toggle in the toolbar.",
"keyboard": {
"heading": "Mobile-friendly keyboard helpers",
"intro": "Phone and tablet keyboards usually don't expose ESC, TAB, the arrow keys or modifier combinations. Without them, navigating <code>vim</code>, <code>nano</code>, <code>htop</code> or any TUI menu is impossible. The Terminal tab solves that by rendering a row of touch-friendly buttons under the terminal whenever the device is small enough or touch-capable:",
"headerButton": "Button",
"headerSends": "Sends",
"headerUse": "Typical use",
"rows": [
{
"button": "ESC",
"sends": "\\x1b",
"use": "Exit insert mode in <code>vim</code>, cancel a TUI dialog, leave a search."
},
{
"button": "TAB",
"sends": "\\t",
"use": "Path autocompletion, field navigation in dialog/whiptail."
},
{
"button": "↑ ↓ ← →",
"sends": "\\x1bO[ABCD]",
"use": "Shell history, cursor movement, menu navigation."
},
{
"button": "↵ Enter",
"sends": "\\r",
"use": "Confirm. Some on-screen keyboards swap Enter for Go/Done — this button is unambiguous."
},
{
"button": "Ctrl ▾",
"sends": "Dropdown",
"useRich": true
}
],
"ctrlIntro": "Three control sequences:",
"ctrlItems": [
"<code>Ctrl+C</code> — cancel / interrupt the running command (<code>\\x03</code>).",
"<code>Ctrl+X</code> — exit <code>nano</code> (<code>\\x18</code>).",
"<code>Ctrl+R</code> — reverse history search in bash (<code>\\x12</code>)."
],
"modalTitle": "Same toolbar in the LXC console modal",
"modalBody": "The container console you launch from <link>VMs & LXCs → Console</link> renders the same keyboard helpers under the modal. The modal also auto-types <code>pct enter &lt;vmid&gt;</code> on connect, so you land directly inside the container."
},
"lxcAlt": "ProxMenux Monitor LXC console modal — Terminal: ubuntu (ID: 103) with the same mobile-friendly toolbar (ESC, TAB, arrows, Enter, Ctrl) under the terminal",
"lxcCaption": "The LXC console modal — opened from <em>VMs & LXCs → Console</em>. The header shows the target container (<em>Terminal: ubuntu (ID: 103)</em>) and the same touch-friendly toolbar appears under the terminal.",
"search": {
"heading": "Search Commands — integrated cheatsheet",
"intro": "The blue <strong>Search</strong> button in the toolbar opens a modal with a fuzzy command lookup. Type a few letters of any Linux or Proxmox command (<code>ls</code>, <code>tar</code>, <code>qm</code>, <code>pct</code>, <code>zpool</code>, <code>systemctl</code>…) and the modal lists usage examples with one-tap <em>Send to active terminal</em>. It removes the \"wait, what flag was that\" round-trip to a separate browser tab.",
"modalAlt": "ProxMenux Monitor Search Commands modal — fuzzy lookup for Linux and Proxmox commands powered by cheat.sh, showing several ls usage examples",
"modalCaption": "The Search Commands modal querying <code>ls</code> — each result shows the command, its description and a small \"send\" arrow that pipes it to the active terminal. Bottom-right corner indicates the data source (<em>Powered by cheat.sh</em>).",
"aboutLabel": "About cheat.sh:",
"aboutBody": "is a community-curated, open-source unified cheatsheet that aggregates short, practical usage examples for hundreds of Linux commands, sysadmin tools and programming languages. Originally designed to be queried from a terminal with <code>curl cheat.sh/&lt;command&gt;</code>, it's also reachable from any browser. ProxMenux Monitor proxies the queries server-side so the modal keeps working under the same origin as the dashboard.",
"headerSource": "Source",
"headerWhen": "When it's used",
"headerWhat": "What you see",
"onlineLabel": "(online)",
"onlineWhen": "When the host has internet access and the cheat.sh proxy responds.",
"onlineWhat": "Several real-world examples per command, typed with their description on top. The status dot in the modal header is <green>green</green>.",
"fallbackLabel": "Local fallback",
"fallbackWhen": "When cheat.sh is unreachable (offline host, restrictive firewall, cheat.sh outage).",
"fallbackWhat": "A bundled list of common Linux + Proxmox commands. Smaller catalogue but always available. The status dot is <red>red</red>.",
"sendingNote": "<strong>How sending works</strong>: clicking the small \"send\" arrow next to a result forwards the command text to whichever terminal is currently active (the focused tab, or the one you last clicked in grid view). The modal closes automatically so you can hit Enter immediately."
},
"auth": {
"heading": "Authentication",
"items": [
"The WebSocket upgrade carries the JWT in the <code>Authorization</code> header. If auth is enabled and the token is missing or expired, the connection is rejected with HTTP 401 before a PTY is allocated.",
"If the Monitor sits behind a reverse proxy, the proxy must forward WebSocket upgrades. See the <link>Access & Authentication</link> page for Nginx / Caddy / Traefik snippets."
]
},
"clipboard": {
"heading": "Clipboard, scrollback and resize",
"items": [
"<strong>Copy / paste</strong> — uses the browser's native clipboard. Select text with mouse / trackpad and use the OS shortcut (<code>Cmd+C</code> on macOS, <code>Ctrl+Shift+C</code> on Linux/Windows). Linux desktops also support middle-click paste.",
"<strong>Scrollback</strong> — wheel / two-finger scroll. xterm.js keeps the last several thousand lines in memory.",
"<strong>Resize</strong> — the terminal re-negotiates the PTY window size when you resize the dashboard pane, so <code>htop</code> and <code>vim</code> render properly.",
"<strong>Reconnect on tab focus</strong> — if you switch apps on a phone or tablet (a common iPad behaviour), the WebSocket would normally drop. The Terminal tab detects the visibility change and reconnects automatically when you come back, with a 15-second timeout for slow VPN paths."
]
},
"disconnect": {
"heading": "Disconnect causes",
"intro": "The most common reasons a session ends and what to do about each:",
"headerCause": "Cause",
"headerFix": "Fix",
"rows": [
{
"cause": "Session JWT expired (24 h window).",
"fix": "Refresh the page and log in again. The terminal isn't designed for unattended sessions, so the JWT lifetime matches the regular dashboard login."
},
{
"cause": "Reverse proxy idle timeout.",
"fix": "Bump <code>proxy_read_timeout</code> on Nginx or the equivalent on Caddy / Traefik (snippets in Access & Authentication)."
},
{
"cause": "Phone or tablet sleep.",
"fix": "When the device wakes back up the tab auto-reconnects (15 s timeout for VPN paths). If it doesn't, reload the tab."
},
{
"cause": "Service restart on the host.",
"fix": "Any restart of <code>proxmenux-monitor.service</code> drops every PTY. Open new terminals after the dashboard finishes reloading."
}
]
},
"warning": {
"title": "The terminal is a root shell on the host",
"body": "The terminal inherits the systemd unit's identity (<code>root</code>) and therefore has full privileges over the Proxmox host. Configure a username, password and 2FA in <authLink>Access & Authentication</authLink> before exposing the dashboard beyond your local network: anyone who reaches port 8008 without authentication would land directly in a root shell — no extra prompts, no SSH credentials. For access from outside the LAN, route the dashboard through <gatewayLink>Secure Gateway</gatewayLink> (Tailscale) or a reverse proxy with HTTPS, instead of opening the port to the public internet."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — reverse-proxy snippets including the WebSocket upgrade lines required for the terminal."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tail": " — the WebSocket transport (HTTP via flask-sock vs HTTPS / WSS via gevent)."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — the /ws/terminal and /ws/script/<sid> WebSocket endpoints alongside the rest of the API."
},
{
"label": "Integrations → Secure Gateway",
"href": "/docs/monitor/integrations",
"tail": " — when you want terminal access from outside the LAN without exposing port 8008."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tail": " — the other tabs."
}
]
}
}
@@ -0,0 +1,248 @@
{
"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 drill-in shows configuration, resources, backups, full guest logs, notes, and Start / Shutdown / Reboot / 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).",
"section": "ProxMenux Monitor · Dashboard"
},
"intro": {
"title": "The control surface for guests",
"body": "Other tabs are read-only; this is the one you act from. Anything that changes guest state goes 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. There is no force-shutdown without going through the dedicated Stop button."
},
"topRow": {
"heading": "Top row: four stat cards",
"intro": "Opening the VMs & LXCs tab lands you on a four-card summary of guest state — totals, CPU utilisation, memory commitment vs host capacity, and disk allocation.",
"imageAlt": "VMs & LXCs tab — top row of four stat cards: Total VMs & LXCs, Total CPU, Total Memory, Total Disk",
"imageCaption": "Top row of the VMs & LXCs tab — totals + Running / Stopped badges, current CPU utilisation, memory broken down into used / running-allocated / total-allocated (with a Within Limits badge), and allocated disk space.",
"headerCard": "Card",
"headerWhat": "What it shows",
"totalLabel": "Total VMs & LXCs",
"totalWhat": "Total count with two badges — <em>X Running</em> (green) and <em>Y Stopped</em> (red, only when > 0). The number you watch when something didn't come back up after a reboot.",
"cpuLabel": "Total CPU",
"cpuWhat": "Aggregate live CPU utilisation across all guests as a percentage of the host's physical CPU, with a footer line <em>\"Allocated CPU usage\"</em>.",
"memoryLabel": "Total Memory",
"memoryIntro": "Three readings stacked vertically:",
"memoryItems": [
"<strong>Currently used</strong> — large value (e.g. <em>15.4 GB</em>) plus <em>X.X % of Y GB</em> against the host's total RAM. A blue progress bar tracks the percentage.",
"<strong>Running allocated</strong> + <strong>Total allocated</strong> — sum of <code>maxmem</code> across guests that are <em>currently up</em> next to the same sum across <em>every</em> guest including stopped ones. The first matters today; the second matters when you start everything at once.",
"<strong>Within Limits</strong> badge (green) — flips to <em>Over-committed</em> if total allocated exceeds the host's RAM. Healthy memory over-commit is fine on hosts with KSM, but the badge is the early warning when it's no longer comfortable."
],
"diskLabel": "Total Disk",
"diskWhat": "Sum of disk space allocated across all guests, in the appropriate unit (GB / TB), with the footer line <em>\"Allocated disk space\"</em>."
},
"inventory": {
"heading": "Virtual Machines & Containers list",
"intro": "One row per guest. The list is single-sourced from <code>/api/vms</code>, which consolidates <code>qm list</code> + <code>pct list</code> + <code>pvesh /cluster/resources</code> on the host.",
"imageAlt": "Virtual Machines & Containers list — one row per guest with status, type badge, name, ID and inline CPU / memory / disk percentages",
"imageCaption": "The mobile-optimized layout of the inventory — the same data the desktop view shows, restacked into a single column with the percentages and status indicators kept compact.",
"rowsIntro": "Each row shows:",
"rows": [
"<strong>Status icon</strong> — green play (running) or red square (stopped). For stopped guests, the rest of the row dims so you instantly see what's offline.",
"<strong>Type badge</strong> — <em>LXC</em> (cyan) for containers, <em>VM</em> (purple) for virtual machines.",
"<strong>Name</strong> — guest hostname / display name.",
"<strong>VMID</strong> — the Proxmox numeric ID below the name.",
"<strong>Inline metrics</strong> — three percentages with their icon (CPU %, Memory %, Disk %). Each icon turns orange when the metric crosses an attention threshold (e.g. memory above 90 %), so a quick scan tells you which guest is under pressure without opening it."
],
"clickHint": "Clicking any row — running or stopped — opens the drill-in modal described below.",
"mobileTitle": "The list is built mobile-first",
"mobileBody": "On phones and narrow windows the inventory reflows into a single column with type badge, name, ID and the three metric percentages on one line each — exactly the screenshot above. On wider viewports the same data spreads horizontally with extra room for the percentages. Either way, every row is the same full target: tap to drill in."
},
"drillIn": {
"heading": "Per-guest drill-in modal",
"intro": "The modal opens with a header showing the guest name, VMID, type badge (LXC / VM), state badge (RUNNING / STOPPED / …) and current uptime. Below the header are <strong>two tabs</strong> — <em>Status</em> and <em>Backups</em> — and a fixed action bar at the bottom of the modal with the four lifecycle controls (Start / Shutdown / Reboot / Force Stop) and, on running LXC containers, a Console button.",
"statusTitle": "Tab 1 — Status",
"statusImageAlt": "Per-guest drill-in modal — Status tab with CPU / Memory / Disk live cards, Disk and Network I/O totals, the OS distro logo, and the Resources / IP Addresses block",
"statusImageCaption": "Status tab — live CPU / Memory / Disk with progress bars at the top, accumulated I/O totals (disk read/write, network down/up) below, then the static Resources block with Notes and + Info expansions and the IP Addresses pill list.",
"statusIntro": "The default tab — the \"is this guest behaving?\" view. Three blocks:",
"liveTitle": "1. Live metrics row",
"liveItems": [
"<strong>CPU Usage (X cores)</strong> — current percentage with a progress bar. The header shows the configured core count so you know what 100 % would mean.",
"<strong>Memory</strong> — <em>used / max</em> in GB with a progress bar.",
"<strong>Disk</strong> — <em>used / max</em> across the guest's primary disk image, same shape."
],
"ioTitle": "2. I/O totals + OS logo",
"ioItems": [
"<strong>Disk I/O</strong> — accumulated read (↓) and write (↑) totals since boot. Useful to spot a guest that's suddenly become I/O-heavy compared to its baseline.",
"<strong>Network I/O</strong> — accumulated download (↓) and upload (↑). Same idea on the network side.",
"<strong>OS distro logo</strong> — the Debian / Ubuntu / Alpine / Windows / etc. icon detected from the guest's OS type. A quick visual cue when scrolling several modals open."
],
"resourcesTitle": "3. Resources block",
"resourcesIntro": "The configuration of the guest as Proxmox sees it — CPU Cores, Memory (configured <code>maxmem</code>), Swap. Two collapsible buttons in the block header:",
"resourcesItems": [
"<strong>Notes</strong> — the guest's description field. Editable: typing here and saving calls <code>PUT /api/vms/&lt;vmid&gt;/config</code> and writes back to <code>/etc/pve/qemu-server/&lt;vmid&gt;.conf</code> or <code>/etc/pve/lxc/&lt;vmid&gt;.conf</code>.",
"<strong>+ Info</strong> — extra fields that are too verbose for the default view: bios mode, machine type, agent state, hostpci passthrough entries, mount points (CT), boot order."
],
"ipsTitle": "4. IP Addresses",
"ipsBody": "Pill list of every IPv4 / IPv6 address the guest currently exposes — green pill per address. Empty when the guest is stopped or when the QEMU agent isn't installed in a VM (LXCs always report addresses directly).",
"mountsTitle": "Tab 2 — Mounts (LXC only)",
"mountsImageAlt": "LXC drill-in modal — Mounts tab listing every mount point the container is using: PVE volumes, host binds, binds from PVE storage and ad-hoc NFS/CIFS mounts the operator mounted from inside the CT. Each card carries a type badge, capacity bar, used/total bytes, mount options, and a colour-coded state dot (green healthy, amber readonly/divergent, red stale)",
"mountsImageCaption": "Mounts tab — only renders for LXC containers, and only when at least one mount point or ad-hoc remote mount is present. A CT without mounts gets no tab.",
"mountsIntro": "Proxmox's own UI shows the mount-point entries defined in the container config (<code>mpX</code>) but stops there — anything you mount from inside the CT later (<code>mount.cifs</code>, NFS via <code>autofs</code>, …) is invisible. This tab merges <strong>both views</strong>: the configured mounts <strong>and</strong> the runtime mounts ProxMenux probes from inside the container, with a per-mount health status and a capacity bar wherever the backend can resolve one.",
"mountTypesTitle": "Types of mount detected",
"mountTypesItems": [
"<strong>PVE volume</strong> — backed by a Proxmox-managed storage (a ZFS subvol, a directory entry, a Ceph RBD, …). Capacity comes from the PVE storage stats so the bar matches what Proxmox itself shows.",
"<strong>Bind from PVE storage</strong> — <code>mpX</code> entry pointing at a path on a PVE-known storage.",
"<strong>Bind from host</strong> — <code>mpX</code> entry pointing at an arbitrary host path (<code>/mnt/something</code>). Capacity is the <code>df</code> of that host path.",
"<strong>Ad-hoc inside CT</strong> — mount that <em>only</em> exists in the container's mount namespace (e.g. an NFS share that the CT mounts on its own). Capacity is read via <code>pct exec &lt;vmid&gt; df</code>, which is the only way to see it — <code>/proc/&lt;pid&gt;/root</code> from the host doesn't expose the remote mount's real stats."
],
"mountStateTitle": "Per-card state dot and warnings",
"mountStateItems": [
"<green/> <strong>Green</strong> — mount is healthy and reachable.",
"<amber/> <strong>Amber</strong> — divergent (configured but not actually mounted), read-only, or <em>zombie bind</em> (the host source was removed but the CT still sees the bind as mounted — typical when a USB drive was unplugged or a manual <code>umount</code> happened on the host).",
"<red/> <strong>Red</strong> — stale: the runtime probe couldn't reach the mount (common with NFS exports whose server is down)."
],
"mountsCalloutTitle": "What this gives you over the native UI",
"mountsCalloutBody": "A truthful, capacity-aware view of every place the container reads or writes. NFS or CIFS shares mounted from inside the CT — invisible to the Proxmox web UI — appear here with the same look and the same health probe as any configured mount point. Stale remote mounts and zombie binds are flagged before they bite during a backup.",
"backupsTitle": "Tab 3 — Backups",
"backupsImageAlt": "Per-guest drill-in modal — Backups tab with the available backups list, destination tag, sizes and the Create Backup button",
"backupsImageCaption": "Backups tab — every backup stored on configured Proxmox storages for this guest, sorted newest first. The tab header carries the count badge.",
"backupsIntro": "Lists every backup stored across configured Proxmox storages for this guest, sorted newest first. The tab title carries a count badge so you see at a glance whether the guest is backed up. Per row:",
"backupsItems": [
"<strong>Timestamp</strong> — date and time of the run.",
"<strong>Destination tag</strong> — the storage where it lives (PBS-Cloud, PBS-Local, NFS-Backup, …) coloured by status.",
"<strong>Size</strong> — final on-disk size of the backup."
],
"backupsOutro": "The <strong>+ Create Backup</strong> button at the top right kicks off a new run on the storage marked as \"Backup target\" in the Proxmox storage config. Restore lives in the Proxmox web UI — the Monitor exposes the \"is this guest backed up recently?\" view, not the recovery flow.",
"updatesTitle": "Updates badge (LXC only)",
"updatesImageAlt": "LXC drill-in modal — clickable violet 'updates available' badge in the header of a container that has pending apt or apk updates. Clicking it expands a panel listing every upgradable package with its current and target versions, plus a security-only counter when the underlying repo flags any of them as security",
"updatesImageCaption": "The badge only appears on running LXC containers that have at least one upgradable package. Click it to open the package list inside the modal — no separate tab in the nav strip.",
"updatesIntro": "ProxMenux probes every running container on the host once a day and counts the upgradable packages. Currently supported in this phase: <strong>Debian / Ubuntu</strong> via <code>apt list --upgradable</code> and <strong>Alpine</strong> via <code>apk list -u</code>. Containers running other distributions (CentOS, Arch, …) are skipped for now — they show no badge instead of a misleading zero.",
"updatesPanelTitle": "What the panel shows",
"updatesPanelItems": [
"<strong>Total upgradable count</strong> at the top, plus a separate <strong>security</strong> counter when the underlying repository flags any of the packages as security (Debian/Ubuntu \"-security\" suite). Alpine doesn't expose a separate security suite via apk metadata, so security is always 0 on Alpine containers.",
"<strong>Per-package list</strong> with name, current version and target version. Use this to decide whether to run the upgrade now or wait for a maintenance window."
],
"updatesScopeTitle": "What the system tracks vs what the script counts",
"updatesScopeBody": "This update detector follows whatever is already installed inside the container — it does <strong>not</strong> install anything new and does <strong>not</strong> know about applications that were deployed outside apt / apk (a Docker container running inside the LXC, a Vaultwarden installed from source, a binary dropped into <code>/usr/local/bin</code>). It is a <em>package-manager</em> view, not an <em>application</em> view. Future phases of this work will integrate community-script application metadata so per-app upstream tracking (Vaultwarden, Jellyfin, …) becomes possible.",
"updatesToggleTitle": "Detection vs notification — toggle semantics",
"updatesToggleCalloutTitle": "Detection is always on; the toggle only controls the notification",
"updatesToggleCalloutBody": "The package-update detection on running containers runs unconditionally — the badge appears in this modal whenever there are updates pending, regardless of any other setting. The <code>lxc_updates_available</code> notification toggle in <strong>Settings → Notifications</strong> only controls whether a grouped \"N CT(s) have pending updates\" message is delivered to your channels. This keeps the toggle semantics consistent with every other update stream (NVIDIA driver, Coral driver, ProxMenux optimizations): turning notifications off never hides the information in the dashboard.",
"updatesApplyTitle": "Applying the updates",
"updatesApplyBody": "Open the container shell from the bottom action bar, or use <code>pct exec &lt;vmid&gt; -- apt full-upgrade -y</code> / <code>pct exec &lt;vmid&gt; -- apk upgrade -y</code> from the host. The dashboard re-scans on its 24h cycle (or after the next manual refresh) and the badge updates.",
"firewallTitle": "Tab 5 — Firewall",
"firewallIntro": "Reads the per-guest Proxmox firewall log straight from the host (no extra service, no polling). The tab is always present in the navigation strip; the panel decides what to render depending on whether the firewall is enabled for that guest and whether any rule is actually logging:",
"firewallItems": [
"<strong>Firewall disabled</strong> — an amber notice explains exactly where to enable it in the Proxmox UI (<em>&lt;Container|VM&gt; → Firewall → Options</em>) and reminds you that at least one rule needs <code>log: info</code> (or higher) before packets show up.",
"<strong>Firewall enabled, no events yet</strong> — empty-state hint with the same logging requirement, useful when you just turned the firewall on.",
"<strong>Events present</strong> — a scrollable monospace pane with the raw entries coloured by action: <green>ACCEPT</green> (green), <orange>REJECT</orange> (orange), <red>DROP</red> (red). A count badge in the header shows how many entries are currently loaded."
],
"firewallRefresh": "A <em>Refresh</em> button at the top right of the panel pulls the latest entries on demand — there is no auto-refresh inside the modal, so the list is a snapshot of the moment you opened the tab or pressed refresh. The data comes from the per-guest log file that Proxmox writes under <code>/var/log/pve-firewall.log</code> filtered by VMID, exposed via <code>GET /api/vms/&lt;vmid&gt;/firewall/log</code>.",
"firewallCalloutTitle": "Why have it here when the Proxmox UI already shows it?",
"firewallCalloutBody": "Two reasons: it removes the round-trip through the Proxmox web UI when you're already inspecting a guest from the dashboard, and it keeps the same VMID-scoped view the rest of the modal uses — start the guest, check its mounts, look at recent firewall hits and stop it again without leaving the panel. The Monitor never edits firewall rules; rule editing stays in the native Proxmox interface where it belongs.",
"actionBarTitle": "Bottom action bar",
"actionBarIntro": "Always visible at the foot of the modal regardless of which tab is active:",
"consoleItem": "<strong>Console</strong> (LXC only, running) — opens a modal that runs <code>pct enter &lt;vmid&gt;</code> and lands you inside the container. Same xterm.js + WebSocket plumbing as the standalone <link>Terminal tab</link>, including the <strong>mobile-friendly toolbar</strong> with ESC, TAB, arrow keys, Enter and the Ctrl combos (Ctrl+C / Ctrl+X / Ctrl+R) under the terminal — making the modal usable from a phone or tablet keyboard. VMs do not expose a Console button here; use the Proxmox web console (noVNC) for guest access.",
"lifecycleIntro": "Below it, four lifecycle buttons in a 2×2 grid. Each fires <code>POST /api/vms/&lt;vmid&gt;/control</code> with the matching <code>action</code>; enabled state depends on whether the guest is currently running:",
"headerButton": "Button",
"headerEnabled": "Enabled when",
"headerAction": "Action sent to host",
"lifecycleRows": [
{
"button": "Start",
"color": "green",
"enabled": "Guest is stopped.",
"action": "qm start / pct start"
},
{
"button": "Shutdown",
"color": "blue",
"enabled": "Guest is running.",
"action": "qm shutdown / pct shutdown — graceful, ACPI"
},
{
"button": "Reboot",
"color": "blue",
"enabled": "Guest is running.",
"action": "qm reboot / pct reboot — graceful restart"
},
{
"button": "Force Stop",
"color": "red",
"enabled": "Guest is running.",
"action": "qm stop / pct stop — hard power-off"
}
],
"forceStopTitle": "Force Stop is the kill switch, not the polite option",
"forceStopBody": "<strong>Force Stop</strong> bypasses the guest's shutdown sequence — equivalent to pulling the power cable. Use <strong>Shutdown</strong> when the guest is responsive; reach for Force Stop only when Shutdown hangs and you accept the data-loss risk of an uncoordinated power-off. The button is red and labelled deliberately so you don't click it by reflex."
},
"dataCollected": {
"heading": "How the data is collected",
"headerSection": "Section of the tab",
"headerEndpoint": "Endpoint",
"headerSource": "Source",
"rows": [
{
"section": "Inventory list",
"endpoint": "/api/vms",
"source": "<code>pvesh get /cluster/resources --type vm</code> for VMs and CTs."
},
{
"section": "Detail panel (config, network, disks)",
"endpoint": "/api/vms/<vmid>",
"source": "<code>qm config &lt;id&gt;</code> for VMs / <code>pct config &lt;id&gt;</code> for CTs."
},
{
"section": "Per-guest metrics chart",
"endpoint": "/api/vms/<vmid>/metrics",
"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 task logs (modal)",
"endpoint": "/api/vms/<vmid>/logs",
"source": "Tasks for that <code>vmid</code> from <code>/var/log/pve/tasks/index</code>."
},
{
"section": "Backups available for guest",
"endpoint": "/api/vms/<vmid>/backups",
"source": "<code>pvesm list &lt;storage&gt;</code> filtered by VMID."
},
{
"section": "Per-guest firewall log (Firewall tab)",
"endpoint": "/api/vms/<vmid>/firewall/log",
"source": "<code>/var/log/pve-firewall.log</code> filtered by VMID."
},
{
"section": "Power buttons (Start / Stop / Reboot / Shutdown)",
"endpoint": "/api/vms/<vmid>/control",
"source": "<code>qm start|stop|reboot|shutdown</code> or <code>pct</code> equivalents."
}
],
"codeComment1": "# Cross-check what the dashboard sees against PVE",
"codeComment2": "# Inspect a specific guest's config exactly as the modal sees it",
"codeComment3": "# VM",
"codeComment4": "# CT"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tailRich": " — the VMs & Containers category (failed boot, QMP timeouts, CT shutdown failures)."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tailRich": " — what the <code>vm_*</code>, <code>ct_*</code>, <code>migration_*</code> and <code>backup_*</code> events trigger downstream."
},
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tailRich": " — the VM and backup endpoints."
},
{
"label": "Dashboard index",
"href": "/docs/monitor/dashboard",
"tailRich": " — the other tabs."
},
{
"label": "ProxMenux → Create VM",
"href": "/docs/create-vm",
"tailRich": " — provisioning side: System NAS templates (Synology and others), Linux / Windows VMs, defaults tailored for Proxmox."
}
]
}
}
@@ -0,0 +1,369 @@
{
"meta": {
"title": "Proxmox Health Monitor — CPU, Memory, Storage, SMART, ZFS, Logs | ProxMenux",
"description": "Proactive Proxmox VE health monitoring: ten categories scanned every five minutes (CPU & temperature, memory & swap, storage, disks/SMART, network, VMs, services, logs, updates, security), four severity levels, per-category suppression durations, automatic cleanup of resolved errors, a permanent disk observation history and the path from a raw event to a Telegram, Discord, Gotify or email notification.",
"ogTitle": "Proxmox Health Monitor — CPU, Memory, Storage, SMART, ZFS, Logs",
"ogDescription": "Proactive Proxmox VE health monitoring across ten categories with severity levels, suppression durations and event-driven notifications.",
"twitterTitle": "Proxmox Health Monitor | ProxMenux",
"twitterDescription": "Proactive Proxmox VE health monitoring across ten categories with severity levels and notifications."
},
"header": {
"title": "Health Monitor",
"description": "The continuous self-check that scans ten categories of host state on a five-minute cycle, samples vital signs continuously between cycles, deduplicates findings into a structured event stream, and feeds the dashboard, the notification engine and the optional AI rewriter from one source of truth.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "One scanner, three consumers",
"body": "A background thread runs the full health cycle every 5 minutes, persists each finding into SQLite under a stable <code>error_key</code>, and lets <strong>(1)</strong> the dashboard render the current state, <strong>(2)</strong> the notification engine fan out new events to the configured channels, and <strong>(3)</strong> the optional AI assistant rewrite alerts in plain language. You configure the scanner once; everything downstream stays in sync."
},
"howItWorks": {
"heading": "How it works",
"intro": "The Health Monitor runs on two parallel lanes inside the Monitor process. A lightweight <strong>vital signs sampler</strong> reads CPU, memory and temperature every few seconds so that sustained-threshold conditions are detected fast; in parallel, the <strong>full health cycle</strong> runs every five minutes and exercises every category from end to end. Both lanes converge into the same SQLite tables — and from there, three consumers read the state independently.",
"scannerTitle": "From sample to stored finding",
"scannerCaption": "The scanner. Vital signs are sampled fast so sustained-CPU / sustained-memory pressure can be detected before the next 5-min cycle. The full cycle reads those buffers and runs the heavier checks (SMART, ZFS pool state, journal scanning, service health, etc.) before writing the structured findings to SQLite.",
"scannerArrowLabel": "step",
"scannerNodes": {
"samplerLabel": "Vital signs sampler",
"samplerDetail": "CPU usage 30 s\nMemory 30 s\nTemperature 15 s\n→ history buffers",
"cycleLabel": "Full health cycle",
"cycleDetail": "Every 5 min\nReads buffers\n+ live probes\n(SMART, ZFS,\nservices, journal…)",
"checksLabel": "Per-category checks",
"checksDetail": "Ten categories\n(CPU, memory,\nstorage, disks,\nnetwork, VMs,\nservices, logs,\nupdates, security)",
"sqliteLabel": "SQLite",
"sqliteDetail": "errors table\n(active +\ndismissed)\n+ disk_observations\n(permanent\nper-disk history)"
},
"notifTitle": "From stored finding to user",
"notifCaption": "The notification path. The same errors table also drives the dashboard view (Active / Dismissed lists rendered live) and is consumed by the cleanup routine at the end of each cycle to auto-resolve stale entries — both run from the same data without going through the dispatcher.",
"notifArrowLabel": "event",
"notifNodes": {
"errorsLabel": "errors table",
"errorsDetail": "Active +\nDismissed rows\nkeyed by\nerror_key",
"dispatcherLabel": "Notification dispatcher",
"dispatcherDetail": "New + escalated\nevents queued\nThrough toggles\n+ cooldown",
"templatesLabel": "Templates + AI rewrite",
"templatesDetail": "Per-event\ntemplate\n→ optional AI\nplain-language\nrewrite",
"channelsLabel": "Channels",
"channelsDetail": "Telegram\nDiscord\nGotify\nEmail (SMTP)"
}
},
"categories": {
"heading": "The ten categories",
"imageAlt": "Health Monitor view showing the ten categories with their current statuses (CPU, Memory, Storage, Disks, Network, VMs, Services, Logs, Updates, Security)",
"imageCaption": "Health Monitor view — the ten categories with their current status. Categories on a healthy host all show OK; warnings and critical events appear inline with the rows that produced them.",
"intro": "Every cycle exercises ten independent checkers. Each produces one of four statuses (<strong>OK</strong>, <strong>INFO</strong>, <strong>WARNING</strong>, <strong>CRITICAL</strong>) plus a structured payload — device names, sample log lines, exact thresholds — that surface in the dashboard and travel through to the notification body.",
"headerCategory": "Category",
"headerChecks": "Sub-checks",
"headerEvents": "Typical events",
"rows": [
{
"category": "CPU & Temperature",
"checks": "CPU usage with hysteresis, sensor temperature",
"events": "High sustained load; CPU temperature crossing the vendor warning / critical thresholds."
},
{
"category": "Memory & Swap",
"checks": "RAM usage, swap usage",
"events": "Sustained memory pressure; OOM-killer activity; swap exhaustion."
},
{
"category": "Storage",
"checks": "Proxmox storages, root filesystem",
"events": "Storage offline (NFS server unreachable, CIFS expired creds); root mount > 90 %; LVM thin pool nearing full."
},
{
"category": "Disks & SMART",
"checks": "SMART, dmesg I/O errors, ZFS pools, LVM, filesystem errors",
"events": "SMART health failed; reallocated / pending sectors; ATA I/O errors; ZFS pool DEGRADED / FAULTED; ext4 read-only remount."
},
{
"category": "Network",
"checks": "Connectivity, link state, gateway latency",
"events": "Bridge or bond down; gateway unreachable; persistent latency spikes."
},
{
"category": "VMs & Containers",
"checks": "QMP communication, VM startup, container startup",
"events": "Failed VM boot; CT shutdown failure; QMP socket timeout; missing config / disk after a clone."
},
{
"category": "PVE Services",
"checks": "<code>pveproxy</code>, <code>pvedaemon</code>, <code>pvestatd</code>, <code>pve-cluster</code>, cluster mode",
"events": "Service crashed; cluster quorum lost; <code>pmxcfs</code> stuck."
},
{
"category": "System Logs",
"checks": "Persistent errors, error spikes, error cascades, critical kernel messages",
"events": "Repeated identical errors; sudden burst of warnings (cascade pattern); <code>BUG:</code> / <code>OOPS:</code> / <code>oom-killer</code> in dmesg."
},
{
"category": "System Updates",
"checks": "Pending updates, security updates, kernel / PVE version, system age",
"events": "Security updates available; pinned kernel several minor versions behind; host uptime > 90 days."
},
{
"category": "Security & Certificates",
"checks": "Login attempts, certificates expiring, optional Fail2Ban jail status",
"events": "Repeated SSH / web auth failures; PVE certificate < 30 days from expiring; Fail2Ban active bans."
}
]
},
"severity": {
"heading": "Severity model",
"headerStatus": "Status",
"headerColour": "Colour",
"headerMeaning": "Meaning",
"headerNotification": "Notification",
"rows": [
{
"status": "OK",
"colour": "Green",
"meaning": "Healthy. No findings in this category.",
"notification": "Silent."
},
{
"status": "INFO",
"colour": "Blue",
"meaning": "Transient or already-resolved condition worth noting once. Also used for categories that have <em>only</em> dismissed items left.",
"notification": "Optional. Each event type can be opted in or out per channel."
},
{
"status": "WARNING",
"colour": "Yellow",
"meaning": "Attention is needed but the host is still functional. Cause is non-trivial — read the details.",
"notification": "Sent when the per-event toggle is on for the channel."
},
{
"status": "CRITICAL",
"colour": "Red",
"meaning": "Functionality broken or data loss possible. Action required.",
"notification": "Sent when the per-event toggle is on for the channel. CPU temperature CRITICAL is treated as a safety alert that re-fires even if previously dismissed."
}
],
"infoNote": "A category that is <strong>OK</strong> but has dismissed events still inside their suppression window is rendered as <strong>INFO</strong> — to remind you that something is being silenced rather than that nothing was ever wrong.",
"unknownTitle": "UNKNOWN, when a check can't complete",
"unknownBody": "A check that fails to produce a verdict for three cycles in a row (a probe that times out, a sensor that disappeared, a tool that exits with an error) is recorded internally as <code>UNKNOWN</code>. The dashboard surfaces this as a yellow status — the overall view caps <code>UNKNOWN</code> at <strong>WARNING</strong> so it never escalates a healthy host to CRITICAL on its own."
},
"dashboardView": {
"heading": "The dashboard view",
"intro": "The Health Monitor lives inside the <strong>Overview</strong> tab. The header status pill (Healthy / Warning / Critical) opens a modal that splits findings into two lists:",
"items": [
"<strong>Active</strong> — every category with an unresolved finding. Each row expands to show the individual checks that produced the status, the raw <code>reason</code> string, the device or VM ID involved, and (for categories that link to a tab) a click-through into Storage / Network / VMs / Logs / Hardware to investigate.",
"<strong>Dismissed</strong> — items previously acknowledged by the user that are still inside their suppression window. Each row shows how much of the suppression remains and the configured duration. When the window expires, the item disappears from this list; if the underlying condition is still present and the category supports re-firing, it re-appears in <em>Active</em>."
],
"pillTitle": "The pill mirrors the worst category",
"pillBody": "The dashboard header colour is the highest severity across the ten categories: any CRITICAL → red, else any WARNING → yellow, else any INFO → blue, else green. The same logic drives the favicon dot and the PWA badge."
},
"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 Health Monitor solves this with two coupled 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; if no per-event window is selected the category's default is used. Permanent dismisses are tagged with a distinct amber <em>Permanent</em> badge in the Dismissed list and never re-fire.",
"step2": "<strong>Per-category Suppression Duration setting</strong>. From the Settings → Health Monitor card (or <code>POST /api/health/settings</code>), each of the ten categories has its own default window applied when a Dismiss is fired without a per-event choice:",
"imageAlt": "Per-category Suppression Duration settings card in Settings → Health Monitor",
"imageCaption": "Suppression Duration card — one dropdown per category. Pick a longer window for noisy events (e.g. pending updates) and shorter for ones you want to re-evaluate quickly. Active Suppressions are listed underneath (see below).",
"outro": "While an event is suppressed, the scanner still runs and updates the row's <code>last_seen</code> timestamp, but no new notification is dispatched and the dashboard stays calm. When the window expires, the next cycle re-evaluates the condition and either re-fires fresh or, if the condition has cleared on its own, drops the row from the lists.",
"activeSuppressionsTitle": "Reviewing and reverting dismisses — the Active Suppressions panel",
"activeSuppressionsBody": "Every currently-silenced alert (time-limited and permanent) is listed under <strong>Settings → Health Monitor → Active Suppressions</strong>. Each row shows the alert identifier, category, severity, when it was dismissed and how much time is left, plus a <strong>Re-enable</strong> button that clears the acknowledgment so the alert can fire again on the next scan. Permanent dismisses can only be reverted from here; time-limited ones can also be force-revived without waiting for the countdown. The Re-enable action is gated by the Health Monitor <em>Edit</em> mode at the top of that card — toggle Edit, click Re-enable on each row you want to revive (queued rows show a green border and a strike-through), then click Save to commit. Cancel discards the queue.",
"autoTitle": "Auto-suppression when you change the Duration",
"autoBody": "Setting a category's Suppression Duration to anything other than the default 24 h has a second effect beyond user-initiated dismissals: <strong>future findings in that category enter the table already acknowledged</strong> with that duration. This is by design — if you've told the Monitor that you want disk-related events silenced for a week, brand-new disk findings honour that intent without you having to dismiss each one by hand. They appear directly in the Dismissed list with the configured remaining time. Categories left at 24 h are unaffected and behave the classic way (new findings land in Active until you act).",
"tempTitle": "CPU temperature CRITICAL is the safety override",
"tempBody": "One specific finding bypasses the suppression entirely: <strong>CPU temperature CRITICAL</strong>. If the sensor crosses the critical threshold, the alert re-fires regardless of any prior dismissal — a cooked CPU is a cooked CPU. This is the only built-in override of the dismiss model.",
"nonDismissableTitle": "Findings that cannot be dismissed",
"nonDismissableBody": "A handful of findings are flagged non-dismissable on purpose — they signal a condition where silencing the alert could cost data, hardware or connectivity. The Dismiss button is hidden for these rows; the alert clears only when the underlying condition recovers and the auto-resolve cleanup picks it up. Other findings (transient I/O events on a healthy disk, recovered states) are also marked non-dismissable but for the opposite reason: there's nothing to silence because the row is already informational and self-clearing.",
"headerFinding": "Finding",
"headerWhy": "Why it can't be dismissed",
"rows": [
{
"finding": "CPU temperature warning / critical",
"why": "Hardware risk — sustained over-temperature damages silicon. Silencing would let a cooking CPU run unnoticed."
},
{
"finding": "Filesystem space critical (root mount)",
"why": "Data loss risk — a full root prevents writes and corrupts state. The alert must remain visible until you free space."
},
{
"finding": "ZFS pool DEGRADED / FAULTED",
"why": "Data integrity risk — pool failure threatens every dataset on it. Silencing while the pool is unhealthy is never the right answer."
},
{
"finding": "Disk I/O errors with SMART FAILED",
"why": "Drive failure confirmed by SMART — masking hides real hardware dying. The alert stays until the device is replaced (or removed from the host)."
},
{
"finding": "Network interface DOWN",
"why": "Connectivity loss — bridges, bonds and physical interfaces with active traffic must stay visible. Silencing them would mask a remote-management outage."
},
{
"finding": "I/O events on healthy disks (INFO)",
"why": "Transient ATA / dmesg events on a disk whose SMART says OK — flagged INFO and self-clearing. Nothing to dismiss because the next cycle already removes them."
}
],
"principle": "Everything else can be dismissed. The principle is: alerts that indicate \"real damage in progress\" or that have already self-resolved are kept off the dismiss path; alerts about sustained conditions you may want to acknowledge and re-check later (high CPU usage, pending updates, certificate near expiry, log warnings, VM startup hiccups, etc.) all expose the Dismiss button."
},
"autoresolve": {
"heading": "Auto-resolution and cleanup",
"intro": "Many alerts should clear themselves when the condition goes away — a VM that was failing to start and is now running, a disk that's no longer in the system, a temperature that dropped back to normal. A cleanup routine runs at the end of each five-minute cycle and applies these rules:",
"headerTrigger": "Trigger",
"headerAction": "Action",
"rows": [
{
"trigger": "CPU usage back to normal range after a CPU-related warning.",
"action": "Marked resolved. Drops out of the Active list."
},
{
"trigger": "Memory pressure back below the warning threshold after an OOM / memory warning.",
"action": "Marked resolved."
},
{
"trigger": "VM / CT referenced by the error no longer exists (<code>qm status</code> / <code>pct status</code> non-zero).",
"action": "Marked resolved as resource removed."
},
{
"trigger": "Disk referenced by the error no longer present in <code>/dev/</code>.",
"action": "Marked resolved as device removed. The permanent observation history is preserved (see next section)."
},
{
"trigger": "Findings sourced from the journal (<code>logs</code> category, SMART entries, ATA / I/O errors) when their suppression window expires.",
"action": "Removed cleanly. Each scan inspects fresh journal entries from that point forward; the same historic line in the journal is not re-emitted."
},
{
"trigger": "Resolved errors older than seven days.",
"action": "Deleted from the database to keep the table small. Notification history is independent and kept longer."
}
],
"permanentTitle": "Permanent suppression is not the same as resolved",
"permanentBody": "Setting a category's Suppression Duration to <code>-1</code> (<em>permanent</em>) silences future alerts for items you dismiss in that category — but it does not skip the auto-resolve check above. If the underlying condition disappears (resource deleted, threshold no longer breached), the item is still cleaned up automatically."
},
"observations": {
"heading": "Disk observations — the permanent history",
"intro": "Disk events are special. A SMART warning on <code>/dev/sdh</code> at 02:14 AM is something you want to remember even after the I/O storm subsided and the error auto-resolved — the disk has a track record now. For that purpose, the Health Monitor keeps a separate <strong>permanent</strong> table: <code>disk_observations</code>.",
"headerProperty": "Property",
"headerErrors": "<code>errors</code> table (Active)",
"headerObs": "<code>disk_observations</code> table",
"rows": [
{
"property": "Purpose",
"errors": "Drives the <em>current</em> health view + notification dispatch.",
"obs": "Permanent per-disk audit trail."
},
{
"property": "Auto-resolve",
"errors": "Yes — rows are cleared when the condition disappears.",
"obs": "No — entries persist forever unless the user explicitly dismisses them."
},
{
"property": "Dedup key",
"errors": "<code>error_key</code> (e.g. <code>smart_sdh</code>).",
"obs": "<code>(disk_registry_id, error_type, error_signature)</code> with stable signatures stripped of volatile data."
},
{
"property": "Where shown",
"errors": "Health Monitor modal (Active / Dismissed lists).",
"obs": "Disk detail card in the <strong>Storage</strong> tab, with an \"X obs.\" badge per disk."
},
{
"property": "What it records",
"errors": "Whatever is currently failing.",
"obs": "SMART warnings (sector issues / temperature / CRC / failed self-tests), I/O errors (ATA / NVMe / dm), filesystem errors, ZFS pool events."
}
],
"outro": "Practical consequence: an alert can clear from the dashboard while the same incident is still recorded in the disk's history. When you click into a disk under Storage, the card shows the count of outstanding observations and a list with timestamps, severity and the original raw message — useful when you're deciding whether a drive needs replacement.",
"renameTitle": "Cross-device renames are merged automatically",
"renameBody": "Disks sometimes appear under transient names (<code>ata8</code>, <code>nvme0n1p3</code>) before getting a stable block-device name. The observation layer consolidates entries by serial number when known: if an event was first recorded as <code>ata8</code> and the same disk is later identified as <code>sdh</code>, the historic observations are reattached to <code>sdh</code> on the next cycle so the history isn't fragmented."
},
"notification": {
"heading": "From a finding to a notification",
"intro": "Every active error is also a candidate for the notification engine. The flow:",
"items": [
"The scanner records the finding with category + severity + structured details.",
"If the event type is <strong>enabled</strong> in the global notification settings, and the channel hasn't silenced this category, an event is queued.",
"The template engine renders a (title, body) pair from the structured details. If the AI rewriter is enabled, the same pair is also passed through the configured provider for a plain-language version.",
"The channel implementation ships it: Telegram message, Discord embed, Gotify push or email. The dispatch outcome is stored in <code>notification_history</code>.",
"If a dismiss arrives later, the suppression window kicks in and any further re-fires of the same <code>error_key</code> stay queue-side until the window closes."
],
"outro": "Channel configuration (Telegram bot token, webhook URLs, AI provider keys, per-event toggles, channel overrides) is documented in <notifLink>Notifications</notifLink> and <aiLink>AI Assistant</aiLink>."
},
"rest": {
"heading": "REST endpoints",
"intro": "Everything the modal does is callable from the API — handy for scripts, custom dashboards or your own chat-bot integration.",
"headerEndpoint": "Endpoint",
"headerMethod": "Method",
"headerUse": "Use",
"rows": [
{
"endpoint": "/api/health",
"method": "GET",
"use": "Small health probe — returns JSON with <code>status</code>, <code>timestamp</code> and <code>version</code>. Suitable for Uptime Kuma keyword checks; the receiver must send the bearer header."
},
{
"endpoint": "/api/health/status",
"method": "GET",
"use": "Overall health verdict — single severity + summary string. Authenticated."
},
{
"endpoint": "/api/health/details",
"method": "GET",
"use": "All ten categories with their per-category statuses and the structured payload that produced each one."
},
{
"endpoint": "/api/health/full",
"method": "GET",
"use": "Full snapshot — categories + active errors + dismissed list + custom suppression settings. Backs the modal in one round-trip and uses a 6-min background cache for instant response."
},
{
"endpoint": "/api/health/active-errors",
"method": "GET",
"use": "Just the Active list. Filterable by <code>?category=&lt;name&gt;</code>."
},
{
"endpoint": "/api/health/dismissed",
"method": "GET",
"use": "Just the Dismissed list, with remaining suppression hours."
},
{
"endpoint": "/api/health/acknowledge",
"method": "POST",
"use": "Body: <code>'{'\"error_key\":\"smart_sdh\"'}'</code>. Dismiss an alert with the category's configured window."
},
{
"endpoint": "/api/health/settings",
"method": "GET / POST",
"use": "Read or write the per-category Suppression Duration values."
},
{
"endpoint": "/api/health/cleanup-orphans",
"method": "POST",
"use": "Manual cleanup of errors whose underlying device / VM is gone. Idempotent."
}
],
"codeComment1": "# Snapshot the current health for a script",
"codeComment2": "# Dismiss a specific error",
"codeComment3": "# Set the disks-category suppression to a week"
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "Dashboard",
"href": "/docs/monitor/dashboard",
"tail": " — where the Health Monitor modal is opened from in the UI."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — channels, per-event toggles, the AI rewrite hook, history."
},
{
"label": "AI Assistant",
"href": "/docs/monitor/ai-assistant",
"tail": " — provider configuration (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter), prompt mode, per-channel detail level, language."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tailRich": " — the SQLite schema (<code>errors</code>, <code>disk_observations</code>, <code>events</code>) and the background-thread cadence."
}
]
}
}
+151
View File
@@ -0,0 +1,151 @@
{
"meta": {
"title": "ProxMenux Monitor — Self-hosted Web Dashboard for Proxmox VE | ProxMenux",
"description": "ProxMenux Monitor is a self-hosted web dashboard for Proxmox VE: real-time host metrics, storage and SMART data, network, VMs and containers, hardware, logs, an integrated web terminal, a proactive Health Monitor, notifications to Telegram / Discord / Email, an optional AI assistant, a REST API and integrations with tools like Homepage and Home Assistant.",
"ogTitle": "ProxMenux Monitor — Self-hosted Web Dashboard for Proxmox VE",
"ogDescription": "Real-time Proxmox VE dashboard: host metrics, storage SMART, network, VMs and containers, hardware, logs, web terminal, Health Monitor, notifications, AI assistant, REST API.",
"twitterTitle": "ProxMenux Monitor | ProxMenux",
"twitterDescription": "Self-hosted Proxmox VE dashboard with Health Monitor, notifications, AI assistant and REST API."
},
"header": {
"title": "ProxMenux Monitor",
"description": "A self-hosted web dashboard for Proxmox VE shipped as an AppImage. It runs on the host as a single systemd service, listens on TCP 8008, and serves both the API and the UI from one process.",
"section": "ProxMenux Monitor"
},
"atGlance": {
"title": "At a glance",
"body": "Single AppImage on the Proxmox host → Flask backend (port 8008) collecting live data via <code>psutil</code>, <code>pvesh</code>, <code>smartctl</code>, <code>journalctl</code> → Next.js dashboard served from the same process. Optional auth (password + 2FA), optional AI assistant, optional notifications, REST API for integrations."
},
"hero": {
"alt": "ProxMenux Monitor dashboard — system overview screen with CPU, memory, temperature and uptime widgets",
"caption": "Default landing screen — host-level metrics and health state at a glance."
},
"coverage": {
"heading": "What the dashboard covers",
"intro": "Eight first-class sections, each backed by its own API endpoints:",
"tableSection": "Section",
"tableWhat": "What it shows",
"sections": [
{
"name": "Health Monitor",
"description": "Active and dismissed alerts across CPU, memory, storage, disks, network, services, logs, VMs, updates and security. Drives the notification engine."
},
{
"name": "Storage",
"description": "Proxmox storage pools, physical disks (SATA / NVMe / USB), SMART attributes, ZFS pool status, wear & lifetime, I/O activity."
},
{
"name": "Network",
"description": "All interfaces (physical, bonds, bridges, OVS), IP/MAC/state, real-time RX/TX graphs, historical RRD data per interface."
},
{
"name": "VMs & Containers",
"description": "Inventory of all VMs and LXCs with status, resources and uptime. Drill-in shows config, historical metrics, full guest logs and start/stop/reboot/shutdown actions."
},
{
"name": "Hardware",
"description": "CPU model and topology, memory layout, PCIe devices, GPU list with driver and per-slot real-time monitoring (NVIDIA / Intel iGPU)."
},
{
"name": "Logs & Events",
"description": "Live <code>journalctl</code> with severity / time-range / keyword filters, Proxmox task history, notification log, downloadable log bundles."
},
{
"name": "Terminal",
"description": "Browser shell to the host or to any VM/CT, powered by <code>xterm.js</code> over WebSockets. Authenticated and audited like the rest of the API."
},
{
"name": "Security",
"description": "Authentication failures, Fail2Ban jail status, recent ban events, integration with the host's <code>[proxmenux]</code> jail."
}
],
"footer": "Every section has a dedicated documentation page under <link>Dashboard</link> in the sidebar."
},
"howItRuns": {
"heading": "How it runs",
"intro": "ProxMenux Monitor ships as a self-contained AppImage. A single systemd unit (<code>proxmenux-monitor.service</code>) starts a Flask process that:",
"bullets": [
"Listens on <strong>TCP 8008</strong> on the host (HTTP).",
"Serves the Next.js dashboard as static assets under <code>/</code> and the API under <code>/api/*</code> from the same process.",
"Pulls live data with standard host tools: <code>psutil</code>, <code>pvesh</code>, <code>smartctl</code>, <code>journalctl</code>, <code>zpool</code>, <code>ip</code>, <code>nvidia-smi</code>, etc.",
"Persists its own state in a local SQLite database (<code>/usr/local/share/proxmenux/health_monitor.db</code>): dismissed alerts, disk observations, notification config, AI config. Authentication state lives separately in <code>/root/.config/proxmenux-monitor/auth.json</code>."
],
"footer": "The full request flow, file layout and the systemd integration are described in <link>Architecture</link>."
},
"noAgent": {
"title": "No agent on the guests",
"body": "The Monitor reads everything from the host. VMs and CTs do not need any agent installed — guest data comes from the Proxmox API and from the host's own kernel-level visibility into the running guests."
},
"access": {
"heading": "Accessing the dashboard",
"intro": "Two access patterns are supported and the application detects which one is in use:",
"codeComment1": "# 1) Direct access on the host",
"codeComment2": "# 2) Via reverse proxy (Nginx / Caddy / Traefik)",
"afterCode": "When fronted by a reverse proxy, the Monitor honours <code>X-Forwarded-For</code>, <code>X-Forwarded-Proto</code> and <code>X-Forwarded-Host</code> so URLs and CORS behave correctly without manual configuration.",
"footer": "First-launch setup, password + TOTP 2FA, and reverse-proxy snippets are covered in <link>Access & Authentication</link>."
},
"mobile": {
"heading": "Mobile use and home-screen install",
"intro": "The dashboard is responsive and ships as a Progressive Web App. The packaged <code>public/manifest.json</code> declares <code>display: standalone</code> with an app name, icon and theme colour, so adding the URL to the home screen produces a real standalone launcher — no browser address bar, custom splash, dark theme matched to the dashboard.",
"phoneAlt": "ProxMenux Monitor running on a phone — main dashboard view",
"phoneCaption": "Main dashboard on a phone — the layout reflows for small viewports.",
"addHeading": "Add to home screen",
"iosLabel": "iOS Safari:",
"iosBody": "share button → <em>Add to Home Screen</em>. The icon comes from <code>/apple-touch-icon.png</code> shipped in the AppImage.",
"androidLabel": "Android Chrome / Edge:",
"androidBody": "three-dot menu → <em>Install app</em> (or <em>Add to Home screen</em> on older versions).",
"afterInstall": "Once installed, opening the icon launches the dashboard in standalone mode with its own task switcher entry.",
"onlineOnlyTitle": "Online-only",
"onlineOnlyBody": "The PWA is installable but it is <strong>not</strong> offline-capable — there is no service worker. The launcher behaves like a native app, but the device still needs to reach the host on TCP 8008 (LAN, VPN or reverse-proxied HTTPS) for the dashboard to load."
},
"health": {
"heading": "The Health Monitor and notifications",
"alt": "Health Monitor screen showing the 10 categories tracked (CPU, memory, storage, disks, network, services, logs, VMs, updates, security) with current status",
"caption": "Health Monitor view — the 10 categories tracked, with their current status. Active and dismissed alerts appear here when the system raises any.",
"body1": "Inside the dashboard, the <strong>Health Monitor</strong> runs continuously in the background and produces a structured stream of events: high CPU temperature, disk SMART warnings, ZFS pool degradation, OOM kills, VM/CT failures, security incidents, and so on. Each event has a category, a severity (INFO / WARNING / CRITICAL) and a stable <code>error_key</code> so duplicates collapse instead of flooding the screen.",
"feedsIntro": "Events feed three things at the same time:",
"feedsHealth": "The <strong>Health Monitor view</strong> in the dashboard (active + dismissed lists).",
"feedsChannels": "The <strong>notification engine</strong> — Telegram, Discord, Email, Gotify and Apprise (multi-channel). Each channel is configured independently and per-event categories can be silenced.",
"feedsAI": "The optional <strong>AI assistant</strong> — when enabled, the configured provider (OpenAI, Anthropic, Gemini, Groq, Ollama or OpenRouter) explains incoming events in plain language and, if enabled in the AI settings, proposes next steps.",
"suppressionTitle": "Suppression instead of mute-all",
"suppressionBody": "Each category has its own <em>Suppression Duration</em>: once you dismiss an alert, the same alert is silenced for that window (default 24 hours, configurable per category up to permanent). Real escalations — e.g. CPU temperature crossing the critical threshold — always re-trigger regardless of suppression."
},
"api": {
"heading": "REST API and integrations",
"intro": "Everything the UI shows is available as JSON over HTTP/HTTPS. The same endpoints power Homepage widgets, Home Assistant sensors, Grafana dashboards (via the Prometheus exporter at <code>/api/prometheus</code>), Uptime Kuma probes and any custom script that speaks <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": "Tokens travel as <code>Authorization: Bearer …</code>. Public endpoints (<code>/api/health</code>, <code>/api/auth/*</code>) work without a token so external uptime probes can hit the host without handing out credentials.",
"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": {
"heading": "Service control",
"intro": "Day-to-day, the Monitor is managed exactly like any other systemd service. It is also exposed as two entries inside the ProxMenux TUI under <em>Settings</em>:",
"codeComment": "# Manual control",
"footer": "See <link>Settings → ProxMenux Monitor</link> for the in-menu toggle and status verification flow."
},
"nextSteps": {
"heading": "Where to next",
"items": [
{
"label": "Architecture",
"description": "— Flask backend, systemd unit, SQLite schema, AI providers, notification channels."
},
{
"label": "Access & Authentication",
"description": "— first launch, password setup, TOTP 2FA, reverse-proxy configuration, Fail2Ban integration."
},
{
"label": "Dashboard",
"description": "— every section of the UI, one page each."
},
{
"label": "API Reference",
"description": "— every endpoint, request / response shape and token management."
},
{
"label": "Integrations",
"description": "— Homepage, Home Assistant, Grafana / Prometheus, Uptime Kuma, generic cURL pattern."
}
]
}
}
@@ -0,0 +1,255 @@
{
"meta": {
"title": "Proxmox Integrations — Homepage, Home Assistant, Grafana, Prometheus | ProxMenux Monitor",
"description": "Copy-paste recipes for connecting ProxMenux Monitor to your homelab dashboards: Homepage, Home Assistant, Grafana via Prometheus, Uptime Kuma. Each recipe with the exact config the dashboards expect, the API endpoints used, and the auth header pattern.",
"ogTitle": "Proxmox Integrations — Homepage, Home Assistant, Grafana, Prometheus",
"ogDescription": "Cookbook for connecting ProxMenux Monitor to Homepage, Home Assistant, Grafana, Prometheus and Uptime Kuma.",
"twitterTitle": "Proxmox Integrations | ProxMenux Monitor",
"twitterDescription": "Recipes for Homepage, Home Assistant, Grafana, Prometheus and Uptime Kuma."
},
"header": {
"title": "Integrations",
"description": "Copy-paste recipes for plugging ProxMenux Monitor into the dashboards and tools your homelab already uses — Homepage, Home Assistant, Grafana via Prometheus, Uptime Kuma. Each recipe shows the exact config the receiving tool expects, the Monitor endpoint it talks to, and the auth header pattern that holds it together.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "What you can build from this page",
"body": "Every recipe below is ready to copy into your tool of choice. The API endpoints used here are documented in the <link>API Reference</link> — this page is the \"here's how to actually use them in Homepage / Home Assistant / Grafana\" companion. Screenshots show the real output you'll see once the recipe is in place."
},
"auth": {
"heading": "Authentication: the one thing every recipe needs",
"intro": "Most endpoints used by these integrations are authenticated. You have two ways to satisfy that requirement.",
"optAtitle": "Option A — API token (recommended for integrations)",
"optAbody1": "Open the dashboard and go to <strong>Settings → Security → API Tokens</strong>. Click <em>Generate token</em>, give it a name (e.g. <em>homepage</em>, <em>home-assistant</em>, <em>prometheus</em>), and copy the token — it's shown <em>once</em>. Long-lived (one-year expiry by default), individually revocable, and what you should be using for any non-browser client.",
"optAbody2": "From that point every request is just:",
"optBtitle": "Option B — login flow (username + password)",
"optBbody": "Useful for scripts that authenticate as a human user. The returned token is short-lived; most integrations should prefer Option A.",
"outro": "The TOTP field is only required when 2FA is enabled on the account. Token rotation, revocation, password policy and the audit log live in <link>Access & Authentication</link>.",
"httpsTitle": "Using HTTPS instead of HTTP",
"httpsIntro": "Every recipe below uses <code>http://</code> in the URLs to keep the examples short. If you've enabled TLS on the Monitor (<strong>Settings → Security → SSL/HTTPS</strong>), swap <code>http://</code> for <code>https://</code> in every URL — that's the only change. Two notes specific to certain tools:",
"httpsItems": [
"<strong>Self-signed certificates.</strong> Home Assistant's <code>rest:</code> integration verifies TLS by default. If the Monitor is using its own self-signed cert, add <code>verify_ssl: false</code> to each REST block (alongside <code>scan_interval:</code>), or import the Monitor's CA into HA's trust store. Same for any tool that refuses untrusted certs.",
"<strong>Prometheus</strong> already has <code>scheme: https</code> ready in the scrape config below; uncomment / leave it as <code>https</code> if TLS is enabled on the Monitor."
]
},
"homepage": {
"heading": "Homepage",
"headingHref": "https://gethomepage.dev",
"intro": "Homepage is a fully static, customizable application dashboard. ProxMenux Monitor plugs into it via the built-in <code>customapi</code> widget — paste a service entry into <code>services.yaml</code>, restart Homepage, and the card appears with live numbers.",
"iconCalloutTitle": "The official ProxMenux logo is on dashboardicons.com",
"iconCalloutBody": "The recipes below use <code>icon: proxmenux.png</code>. Homepage automatically resolves bare filenames against <a1>dashboardicons.com</a1> — a curated icon library for self-hosted dashboards. The ProxMenux entry lives at <a2>dashboardicons.com/icons/external/proxmenux</a2> and Homepage pulls it on first render. Same lookup works for thousands of other tools (Telegram, Discord, Grafana, Tailscale, etc.) — just write <code>icon: &lt;name&gt;.png</code> in any service entry.",
"imageAlt": "Homepage dashboard showing three ProxMenux Monitor cards (EDGE, VOID, DREAM) with uptime, CPU, RAM and temperature for each Proxmox host",
"imageCaption": "Three ProxMenux Monitor instances rendered as Homepage cards — uptime, CPU, RAM and CPU temperature read live from <code>/api/system</code> on each host every 10 s.",
"basicTitle": "Basic widget — no authentication",
"basicIntro": "Use this when ProxMenux Monitor is on a trusted network and you haven't enabled authentication on the Monitor side yet. The simplest possible <code>services.yaml</code> entry:",
"authedTitle": "Authenticated widget",
"authedIntro": "Generate an API token in <strong>Settings → Security → API Tokens</strong> on the Monitor, copy it, and paste it into the <code>Authorization</code> header below — replace the example token shown after <code>Bearer</code> with the one you just copied:",
"authedOutro": "Restart Homepage and the card lights up with live values. Reuse the same token across all Homepage widgets pointing at the same ProxMenux Monitor host.",
"multiTitle": "Multi-widget setup — system, storage, network",
"multiIntro": "For a richer view, render three separate cards backed by different endpoints — one for system metrics, one for storage, one for network. Use the same token in every card; it's the same Monitor instance.",
"multiCalloutTitle": "Multiple Proxmox hosts",
"multiCalloutBody": "Repeat the entry block per host to get the multi-card layout in the screenshot above — each entry points at the <code>http://&lt;host&gt;:8008</code> URL of its own ProxMenux Monitor instance. The token can be different per host (one secret entry per host) or shared, depending on how you generate them."
},
"homeAssistant": {
"heading": "Home Assistant",
"headingHref": "https://www.home-assistant.io",
"intro": "There is no native HACS integration for ProxMenux Monitor (yet) — but you don't need one. The built-in <code>rest</code> integration in Home Assistant can pull every endpoint documented in the <link>API Reference</link> and turn the responses into sensors, attributes and triggers. The complete reference build below exposes ~25 sensors covering system resources, the Health Monitor, VMs / CTs, storage, network, gateway latency and ProxMenux update status — drop the YAML into <code>configuration.yaml</code>, restart, and you have a full Proxmox observability layer inside HA.",
"imageAlt": "Home Assistant dashboard showing ProxMenux Monitor entities — health status badge, CPU / RAM / Temp gauges, VM count, storage usage and active errors counter",
"imageCaption": "ProxMenux Monitor as a first-class Home Assistant integration — sensors built from the YAML recipe below.",
"step1Title": "1 · Store the API token",
"step1Body": "Drop the token into Home Assistant's <code>secrets.yaml</code> so it never leaks into a config dump. The whole bearer prefix goes in one line — that lets the YAML reference it directly as a header value. Filename and location depend on your HA install (typically <code>/config/secrets.yaml</code> for HA OS / Container).",
"step2Title": "2 · Drop in the REST configuration",
"step2Body": "Six REST blocks cover the full surface — one per major Monitor area. Each block has a sensible <code>scan_interval</code> tuned to how often the underlying data changes (system resources every 30 s, health every 60 s, slowly-changing inventories every 5-10 min). Paste into <code>configuration.yaml</code>:",
"step3Title": "3 · Add binary sensors and template helpers",
"step3Body": "Two binary sensors and a couple of template sensors round out the integration — they make automations and Lovelace conditional cards much cleaner than chaining Jinja in every place.",
"step4Title": "4 · Reload & verify",
"step4Body": "From the HA UI: <em>Developer Tools → YAML → Check Configuration</em> first to validate the syntax, then <em>All YAML configuration</em> reload (or full restart). After it comes back, filter <em>Settings → Devices & Services → Entities</em> by <em>proxmenux</em> — you should see all ~25 entities populating within one scan interval.",
"replaceTitle": "Replacing an earlier version of this recipe?",
"replaceBody": "If you tried a previous version of these YAML blocks, Home Assistant's entity registry may have cached the old entity IDs and stale entities will still appear (with <em>Entidad no encontrada</em> warnings in your Lovelace cards). Clean state in two steps: delete the previous <code>rest:</code> and <code>template:</code> blocks from <code>configuration.yaml</code>, reload, and then under <em>Settings → Devices & Services → Entities</em> filter by <em>proxmenux</em> and remove any entries marked \"Restored\" or showing as unavailable. Then paste the current YAML and reload again — the new entities register cleanly.",
"step5Title": "5 · Lovelace dashboard",
"step5Body": "The YAML below is a single <strong>vertical-stack</strong> card that combines all the sub-cards in one block — header with logo, quick KPIs, system detail, VMs, storage, network and a conditional health-issues card. To use it: open your dashboard, click the pencil (edit), click <em>Add card</em>, scroll to the bottom and pick <em>Manual</em>, then paste:",
"viewTipTitle": "Want it as a full dashboard view instead of a single card?",
"viewTipBody": "Open the dashboard's 3-dot menu → <em>Raw configuration editor</em> and add a new view with this header (above the <code>cards:</code> list from the YAML above):",
"viewTipOutro": "That gives you a dedicated tab/view in your dashboard with its own icon and title, instead of one long card on an existing view.",
"altViewTitle": "Alternative — a dedicated dashboard view",
"altViewIntro": "If you'd rather have a full dedicated page (its own tab in the dashboard sidebar) than a single card inside an existing view, Home Assistant lets you create a new view directly with YAML. Steps:",
"altViewSteps": [
"Open the dashboard where you want the new tab.",
"Click the pencil (edit dashboard) at the top right.",
"Click the <em>+</em> tab at the end of the existing tabs to create a new view.",
"In the dialog that opens, switch to the <em>Code editor</em> tab (top right of the dialog — toggles between visual editor and YAML).",
"Paste the YAML below.",
"Save. The new <em>ProxMenux Monitor</em> tab appears in the sidebar with all cards rendered."
],
"twoEditorsTitle": "Two YAML editors in HA — pick the right one",
"twoEditorsIntro": "Home Assistant has two YAML editors that look similar but expect different formats:",
"twoEditorsItems": [
"<strong>Single-view editor</strong> (this recipe) — opened from the <em>+</em> tab or from <em>Edit view → Code editor</em>. Expects the body of one view directly: <code>title:</code>, <code>path:</code>, <code>cards:</code> at the top level, no leading dash.",
"<strong>Whole-dashboard Raw editor</strong> — opened from the dashboard's 3-dot menu. Expects the entire <code>views:</code> list, with each view as a list item (leading <code>-</code>)."
],
"twoEditorsOutro": "Pasting view-body YAML into the whole-dashboard editor (or vice versa) leaves you with a <em>Vista sin nombre</em> and <code>cards: []</code>. The YAML below is for the single-view editor — paste exactly as shown.",
"viewImageAlt": "Home Assistant dedicated view rendering ProxMenux Monitor — picture-entity header, glance KPIs, and System / VMs / Storage / Network entity cards laid out automatically by HA across multiple columns",
"viewImageCaption": "The dedicated <em>ProxMenux Monitor</em> view as Home Assistant renders it on a wide screen — HA's default layout splits the cards into multiple columns automatically.",
"twoColTipTitle": "Want a fixed two-column layout instead of the auto layout?",
"twoColTipBody": "Replace any pair of cards (e.g. <em>System</em> + <em>VMs</em>, or <em>Storage</em> + <em>Network</em>) with a single <code>horizontal-stack</code> wrapping both, so they always render side by side regardless of screen width:",
"twoColTipOutro": "On mobile the row stays compressed; HA's auto layout (no horizontal-stack) reflows better at narrow widths.",
"step6Title": "6 · Automations",
"step6Body": "Three automations that cover the most common reactive scenarios — replace <code>notify.mobile_app_&lt;your_phone&gt;</code> with whichever notify service you use:",
"logoTitle": "About the ProxMenux logo",
"logoBody": "The picture-entity card at the top of the Lovelace YAML pulls the official ProxMenux logo from <a1>dashboardicons.com</a1> — a free icon library curated for self-hosted dashboards. The ProxMenux entry lives at <a2>dashboardicons.com/icons/external/proxmenux</a2>. Home Assistant fetches the SVG over HTTPS on first render and caches it.",
"logoBrokenTitle": "If the logo card shows a broken image",
"logoBrokenIntro": "Some HA installs (firewalled networks, content blockers, hosts without public internet) can't reach jsdelivr.net at render time. The fix is a local copy:",
"logoBrokenSteps": [
"Download the SVG from <a>cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/proxmenux.svg</a>.",
"Save it to <code>/config/www/icons/proxmenux.svg</code> on your HA host.",
"In the Lovelace YAML, replace the <code>image:</code> URL with <code>/local/icons/proxmenux.svg</code>. Save and reload — the image renders from the local file, no internet needed."
],
"scanTipTitle": "scan_interval rule of thumb",
"scanTipBody": "<code>/api/system</code> is cheap to call — 30 s is fine. <code>/api/health/full</code> uses an internal 6-min cache, so polling it more often than ~60 s gains you nothing. <code>/api/storage/summary</code> changes slowly — every 5 min is plenty. <code>/api/proxmenux/update-status</code> only matters once an hour. Tune to your hardware budget if you have many sensors across many hosts."
},
"grafana": {
"heading": "Prometheus + Grafana",
"promHref": "https://prometheus.io",
"grafanaHref": "https://grafana.com",
"intro": "ProxMenux Monitor exposes a Prometheus-format scrape endpoint at <code>GET /api/prometheus</code> (authenticated) returning OpenMetrics text. Wire it into Prometheus, then build a Grafana dashboard on top — same data the dashboard UI shows, in the format your TSDB expects.",
"imageAlt": "Grafana dashboard rendering ProxMenux Monitor metrics — CPU usage gauge, memory usage timeseries, running VMs count, network throughput",
"imageCaption": "A basic Grafana dashboard built from the ProxMenux Prometheus scrape — CPU, memory, running VMs, network throughput. The full metric catalogue lives in the <link>API Reference → Prometheus metrics</link>.",
"step1Title": "1 · Add the scrape job to Prometheus",
"step1Body": "Pass the API token via Prometheus' native <code>authorization</code> block (cleaner than custom headers and works with secret stores):",
"step1After": "Reload Prometheus (<code>kill -HUP</code> or <code>systemctl reload prometheus</code>, or <code>docker compose restart prometheus</code> if you run it as a container) and check <em>Status → Targets</em> — the proxmenux job should turn green within one scrape interval. Each metric carries a <code>node=\"&lt;hostname&gt;\"</code> label so you can distinguish hosts in queries.",
"tokenTipTitle": "Token via file or env, not inline",
"tokenTipBody": "For production deployments avoid inlining the token. Prometheus supports <code>credentials_file: /etc/prometheus/secrets/proxmenux.token</code> as an alternative — keep the token in a 0600 file and let Prometheus read it.",
"step2Title": "2 · Verify the scrape with a couple of queries",
"step2Body": "Before configuring Grafana, confirm Prometheus actually has the data. Open Prometheus' own UI at <code>http://&lt;prometheus-host&gt;:9090</code>, click <em>Query</em> and run any of these — you should get back live numbers from your Proxmox host:",
"headerQuery": "Query",
"headerConfirms": "What it confirms",
"verifyRows": [
{
"query": "up{job=\"proxmenux\"}",
"confirms": "Returns <code>1</code> if Prometheus is successfully scraping the Monitor, <code>0</code> if not. The fastest sanity check."
},
{
"query": "proxmox_cpu_usage",
"confirms": "Current CPU usage % of the Proxmox host. Should change if you refresh the query a few seconds apart."
},
{
"query": "proxmox_vms_running",
"confirms": "Number of running guests. Compare against what you see in the Proxmox UI."
},
{
"query": "proxmox_uptime_seconds / 86400",
"confirms": "Host uptime in days. Should match the value you'd see in <code>uptime</code> on the Proxmox shell."
}
],
"calloutTitle": "The 401 you may see when clicking the endpoint URL is fine",
"calloutBody": "On the <em>Status → Targets</em> page, clicking the endpoint link (<code>/api/prometheus</code>) makes your browser fetch it directly — without the bearer header that Prometheus uses for its own scrapes. So you'll see <code>'{'\"error\":\"Authentication required\"'}'</code>. That confirms the API is properly protected; Prometheus itself authenticates correctly because it has the token from the scrape config. Trust the green <em>State: UP</em>, not the click-through.",
"step3Title": "3 · Add Prometheus as a Grafana data source",
"step3Body": "In Grafana: <em>Connections → Data sources → Add new → Prometheus</em>. Set the URL to your Prometheus instance (e.g. <code>http://prometheus.lan:9090</code>), save and test. No extra auth needed at this layer — Prometheus has already authenticated to ProxMenux.",
"step4Title": "4 · Build panels with these PromQL queries",
"step4Body": "A starter set that maps directly to what users typically watch on a Proxmox host:",
"headerPanel": "Panel idea",
"headerPromql": "PromQL query",
"panelRows": [
{
"panel": "CPU usage gauge per host",
"promql": "proxmox_cpu_usage"
},
{
"panel": "Memory usage gauge per host",
"promql": "proxmox_memory_usage_percent"
},
{
"panel": "Memory used vs total (timeseries)",
"promql": "proxmox_memory_used_bytes / 1024 / 1024 / 1024"
},
{
"panel": "Running VMs / CTs per host",
"promql": "proxmox_vms_running"
},
{
"panel": "CPU temperature",
"promql": "proxmox_cpu_temperature_celsius"
},
{
"panel": "Network throughput RX (bytes/s)",
"promql": "rate(proxmox_interface_bytes_received_total[5m])"
},
{
"panel": "Network throughput TX (bytes/s)",
"promql": "rate(proxmox_interface_bytes_sent_total[5m])"
},
{
"panel": "Load average (1m)",
"promql": "proxmox_load_average{period=\"1m\"}"
},
{
"panel": "Disk space used % per mountpoint",
"promql": "proxmox_disk_usage_percent"
},
{
"panel": "UPS battery charge",
"promql": "proxmox_ups_battery_charge_percent"
},
{
"panel": "GPU temperature per slot",
"promql": "proxmox_gpu_temperature_celsius"
}
],
"outro": "Add each query as a Grafana panel, set the right visualization (<em>Stat</em> for gauges, <em>Time series</em> for trends), and group panels into rows by category. Use the <code>node</code> label as a dashboard variable (<em>Settings → Variables → New → Query → label_values(proxmox_cpu_usage, node)</em>) to filter all panels by host."
},
"uptimeKuma": {
"heading": "Uptime Kuma and other status checkers",
"href": "https://github.com/louislam/uptime-kuma",
"intro": "For external probes, use <code>GET /api/system-info</code> — it is the one endpoint that works without a token, returning a small JSON payload with hostname, uptime and the overall health status (mapped to <code>healthy</code> / <code>warning</code> / <code>critical</code>). That's exactly what a keyword-based monitor needs.",
"kumaTitle": "Uptime Kuma — HTTP keyword monitor",
"kumaSteps": [
"In Uptime Kuma, click <em>+ Add New Monitor</em>.",
"Monitor Type: <em>HTTP(s) - Keyword</em>.",
"Friendly Name: <em>ProxMenux Monitor — pve01</em>.",
"URL: <code>http://pve01.lan:8008/api/system-info</code>.",
"Keyword: <code>healthy</code> (the value of <code>health.status</code> when the host is OK).",
"Heartbeat Interval: 60 seconds is enough.",
"Save. No headers needed — the endpoint is public."
],
"healthchecksTitle": "healthchecks.io / cron-style pings",
"healthchecksBody": "Same endpoint, same shape — point your cron-style ping at <code>/api/system-info</code> and assert <code>.health.status == \"healthy\"</code>. Most of these services accept a 2xx HTTP status as the \"up\" signal too, in which case even a curl without parsing is enough.",
"richTitle": "Want richer health data",
"richBody": "For the full state (the ten Health Monitor categories + active errors + dismissed list), use <code>GET /api/health/full</code> instead — that one needs an API token but gives you everything the dashboard modal renders in a single response."
},
"workflows": {
"heading": "n8n, Zapier and custom scripts",
"intro": "For workflow tools and ad-hoc scripts that need to <em>raise</em> notifications through the Monitor (a CI failure, a smart-home sensor, a cron job that ran too long), the recipe is one POST to <code>/api/notifications/send</code>. The event flows through the same dispatch pipeline as anything emitted internally — dedup, cooldown, optional AI rewrite, fan-out to the configured channels.",
"n8nBody": "In n8n, the equivalent is an <em>HTTP Request</em> node with method POST, the URL above, an <em>Authorization</em> header set to <code>Bearer '{''{'$credentials.proxmenux.token'}''}'</code> (using n8n credentials), and a JSON body matching the curl payload. Wire any preceding node as the trigger (cron, webhook, condition).",
"severityBody": "Severity values are <code>INFO</code>, <code>WARNING</code> or <code>CRITICAL</code> (uppercase). The <code>data</code> payload is free-form JSON — the AI rewriter, when enabled, will pull anything useful from it for the rendered body. Full event-type semantics live in <link>Notifications → Event catalogue</link>."
},
"pveWebhook": {
"heading": "Native Proxmox VE webhook (inbound)",
"intro1": "Proxmox VE 8.1+ has its own notification system. ProxMenux Monitor registers itself as a webhook target so that everything PVE emits on its own (HA fencing, replication, vzdump from the GUI, certificate renewal) lands in the same dispatch pipeline as the Monitor's own events. This happens automatically when you press <em>Enable Notifications</em> on the Settings tab — no integration work required on the user side.",
"intro2": "Mechanics, the body template PVE sends, the entries written to <code>/etc/pve/notifications.cfg</code>, and behaviour in clusters are documented in <link>Notifications → PVE webhook integration</link>."
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "API Reference",
"href": "/docs/monitor/api",
"tail": " — every endpoint with method, path and the full Prometheus metric catalogue."
},
{
"label": "Notifications",
"href": "/docs/monitor/notifications",
"tail": " — event sources, channels, the dispatch pipeline, the PVE webhook integration in detail."
},
{
"label": "AI Assistant",
"href": "/docs/monitor/ai-assistant",
"tail": " — the optional rewriter that turns templated bodies into plain language before they reach Telegram / Discord / email / Gotify."
},
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tail": " — minting and revoking the API tokens these recipes consume, audit log, TLS configuration."
}
]
}
}
@@ -0,0 +1,483 @@
{
"meta": {
"title": "Proxmox Notifications — Telegram, Discord, Email, Gotify, Apprise | ProxMenux Monitor",
"description": "Send Proxmox VE notifications to Telegram, Discord, Email, Gotify and ~80 extra services via Apprise. ProxMenux Monitor turns events from the Health Monitor, the journal watcher and the Proxmox VE webhook into rich messages with deduplication, cooldown, burst aggregation, an optional AI rewrite and a complete history.",
"ogTitle": "Proxmox Notifications — Telegram, Discord, Email, Gotify, Apprise",
"ogDescription": "Send Proxmox VE alerts to Telegram, Discord, Email, Gotify and ~80 extra services via Apprise — with deduplication, cooldown, burst aggregation and an optional AI rewrite.",
"twitterTitle": "Proxmox Notifications | ProxMenux Monitor",
"twitterDescription": "Send Proxmox VE alerts to Telegram, Discord, Email, Gotify and ~80 extra services via Apprise."
},
"header": {
"title": "Notifications",
"description": "The fan-out engine that takes events from every collector inside the Monitor and delivers them to Telegram, Discord, Email, Gotify and ~80 extra services via Apprise — with deduplication, cooldown, burst aggregation, per-event and per-channel toggles, an optional AI rewriter, and a queryable history.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Where messages come from",
"body": "Notifications are not a separate scanner. They are the output side of every collector already running inside the Monitor — the <link>Health Monitor</link>, the journal watcher, the Proxmox task watcher, the PVE webhook hook, the polling collector and the in-process events emitted by ProxMenux scripts. Each event runs through the same dispatch pipeline before reaching a phone or an inbox."
},
"howItWorks": {
"heading": "How it works",
"intro": "Every notification follows the same path through the Monitor process. Events are produced by a handful of independent collectors, normalised into a structured payload, passed through a dispatch pipeline that decides whether to send and in what shape, optionally rewritten by an LLM, and finally fanned out to whichever channels the user has configured.",
"arrowLabel": "event",
"caption": "High-level flow. Every actual dispatch attempt — successful, aggregated or failed — is recorded in the SQLite history table for retrospective inspection. Events suppressed by the cooldown stage are not logged.",
"nodes": {
"sourcesLabel": "Sources",
"sourcesDetail": "Health Monitor\nJournal watcher\nTask watcher\nPVE webhook hook\nPolling collector\nIn-process emitters",
"dispatchLabel": "Dispatch pipeline",
"dispatchDetail": "Per-event toggle\nFingerprint dedup\nCooldown\nBurst aggregation",
"aiLabel": "AI rewrite (opt.)",
"aiDetail": "OpenAI / Anthropic\nGemini / Groq\nOpenRouter / Ollama\n(off by default)",
"channelsLabel": "Channels",
"channelsDetail": "Telegram\nDiscord\nEmail (SMTP)\nGotify\nApprise (~80 services)"
}
},
"enabling": {
"heading": "Enabling the panel",
"intro": "On a fresh install the Notifications card on the Settings tab shows a <em>Disabled</em> badge and a single <em>Enable Notifications</em> button. Nothing is dispatched and no PVE config is touched until you press it.",
"disabledAlt": "Notifications card on a fresh install showing Disabled badge and a single Enable Notifications button",
"disabledCaption": "The first state — one click to enable.",
"stepsIntro": "Pressing the button does three things in sequence:",
"steps": [
"Flips the panel to its <em>Active</em> state and unfolds the channel form below.",
"Registers a Proxmox VE webhook target in <code>/etc/pve/notifications.cfg</code> pointing at <code>POST http://127.0.0.1:8008/api/notifications/webhook</code>. From this moment on, anything Proxmox VE emits on its own (HA, replication, vzdump from the GUI) flows into the same pipeline as the Monitor's own events. See <pvelink>PVE webhook integration</pvelink> below for the full mechanics.",
"Starts the dispatch background thread. The thread polls the event queue and walks every event through the pipeline diagrammed above."
],
"activeAlt": "Notifications card after enabling — Active badge, channel tabs (Telegram, Gotify, Discord, Email), Display Name field and Advanced AI Enhancement collapsible section",
"activeCaption": "Active state — channel tabs at the top (Telegram / Gotify / Discord / Email), the Display Name field, the per-channel category list, and the collapsible <em>Advanced: AI Enhancement</em> section."
},
"sources": {
"heading": "Event sources",
"intro": "Six independent collectors feed the notification engine. They run as background threads inside the Monitor process and emit a structured <code>NotificationEvent</code> every time something happens.",
"headerCollector": "Collector",
"headerWatches": "Watches",
"headerEvents": "Typical events",
"rows": [
{
"collector": "Health Monitor",
"watches": "Ten categories, every 5 minutes",
"events": "<code>new_error</code>, <code>error_resolved</code>, <code>error_escalated</code>, <code>health_degraded</code>, <code>health_persistent</code>."
},
{
"collector": "Journal watcher",
"watches": "<code>journalctl --follow</code> with pattern matching for SSH / web auth failures, Fail2Ban bans (when the optional jail is installed), kernel I/O errors, OOM, smartd events.",
"events": "<code>auth_fail</code>, <code>ip_block</code>, <code>oom_kill</code>, <code>disk_io_error</code>, <code>service_fail</code>."
},
{
"collector": "Task watcher",
"watches": "Polls <code>/var/log/pve/tasks/index</code> for new task UPIDs and follows their per-file logs.",
"events": "<code>backup_start</code>, <code>backup_complete</code>, <code>backup_warning</code>, <code>backup_fail</code>, <code>migration_*</code>, <code>snapshot_complete</code>."
},
{
"collector": "Proxmox webhook hook",
"watches": "Listens on <code>POST /api/notifications/webhook</code>. Proxmox VE 8.1+ pushes its own notifications here once the integration is set up (see <pvelink>below</pvelink>).",
"events": "Anything PVE emits — including events the Monitor would otherwise miss (HA, replication, vzdump from the GUI)."
},
{
"collector": "Polling collector",
"watches": "Periodic comparisons (cluster nodes online, certificate expiry, GPU passthrough state, PVE / ProxMenux update availability).",
"events": "<code>node_disconnect</code>, <code>node_reconnect</code>, <code>pve_update</code>, <code>proxmenux_update</code>, <code>gpu_mode_switch</code>, <code>pci_passthrough_conflict</code>."
},
{
"collector": "In-process emitters",
"watches": "Direct calls from ProxMenux scripts and from the Monitor itself (<code>notification_manager.emit_event(...)</code>).",
"events": "<code>system_startup</code>, <code>system_shutdown</code>, <code>system_reboot</code>, <code>ai_model_migrated</code>, custom test events."
}
],
"after1": "Every event carries a stable <code>event_type</code> (the catalogue is below), a <code>severity</code> (<code>INFO</code>, <code>WARNING</code>, <code>CRITICAL</code>), a <code>category</code> (used for emoji enrichment and per-group filters) and a <code>data</code> payload with anything the template needs (<code>vmid</code>, <code>device</code>, <code>source_ip</code>, <code>reason</code>…).",
"after2": "Each <code>event_type</code> has a matching template in <code>notification_templates.py</code> that renders the structured event into a plain-text body before anything else happens. That templated body is what travels through the dispatch pipeline, and what the optional AI layer rewrites if enabled. See the <ailink>AI Assistant page</ailink> for how the rewrite layer interacts with this templated body."
},
"channels": {
"heading": "Channel walkthroughs",
"intro": "Five channels are currently supported: Telegram, Discord, Gotify, Email (SMTP) and Apprise. The first four are native — each one has its own tab inside the Notifications panel with a <em>+ setup guide</em> link opening an in-app modal. Apprise is a generic hub that adds ~80 additional services (ntfy, Matrix, Pushover, Slack, Teams, Pushbullet, AWS SNS, Mattermost…) through a single URL field. They are all documented step by step below.",
"credsTitle": "Where credentials live",
"credsBody": "Tokens, webhook URLs and SMTP passwords are stored locally in the Monitor's SQLite database under <code>/usr/local/share/proxmenux/</code>. They never leave the host except to reach their respective services. A backup of that directory is enough to recover the configured channels."
},
"telegram": {
"heading": "Telegram",
"intro": "Two pieces of information are required: a <strong>Bot Token</strong> (one per bot, reusable across chats) and a <strong>Chat ID</strong> (where the bot should post — your private chat, a group, or a topic inside a supergroup). The in-app guide below contains the full step-by-step; the rest of this section repeats it as text plus the two shapes the Chat ID can take.",
"guideAlt": "Telegram Bot Setup Guide modal with four numbered sections: Create a Bot with BotFather, Get the Bot Token, Get Your Chat ID and For Groups or Channels",
"guideCaption": "The <em>+ setup guide</em> link inside the Telegram tab opens this modal — the four numbered steps go from no bot to a working channel in about two minutes.",
"step1Title": "1 · Create a bot with BotFather",
"step1Items": [
"Open Telegram and start a chat with <a>@BotFather</a> (the one with the blue verification tick — copies are common).",
"Send <code>/newbot</code>.",
"Pick a display name (e.g. <em>ProxMenux Lab</em>). It can be changed later.",
"Pick a username ending in <code>bot</code> (e.g. <em>proxmenux_lab_bot</em>). It must be unique across Telegram.",
"BotFather replies with a token of the form <code>123456789:ABCdef…</code> — that is the Bot Token. Treat it as a password."
],
"step2Title": "2 · Get the Chat ID",
"step2Intro": "The Chat ID identifies <em>where</em> the bot posts. It takes one of two shapes depending on the target.",
"privateLabel": "Private chat (you receive the alerts on your own account):",
"privateItems": [
"Start a chat with your new bot and send any message (e.g. <code>/start</code>).",
"Open a chat with <a1>@userinfobot</a1> (or <a2>@myidbot</a2>) and send <code>/start</code>. It replies with your numeric user ID — that is the Chat ID. It is a positive number."
],
"privateAlt": "Telegram channel form filled with Bot Token (masked), positive Chat ID for a private chat and an empty optional Topic ID field",
"privateCaption": "Private chat with the bot — Chat ID is a positive number (your personal user ID).",
"groupLabel": "Group or supergroup with topics:",
"groupItems": [
"Add the bot to the group as a member (and make it admin if the group requires it to post).",
"Send any message in the group.",
"Open <code>https://api.telegram.org/bot&lt;YOUR_TOKEN&gt;/getUpdates</code> in a browser. Look for <code>chat.id</code> in the JSON response — for groups it is a negative number, for supergroups it starts with <code>-100</code>.",
"For supergroups with <em>Topics</em> enabled, also note the <code>message_thread_id</code> of the topic you want to target — that goes in the optional <em>Topic ID</em> field."
],
"groupAlt": "Telegram channel form with Bot Token (masked), negative Chat ID prefixed with -100 indicating a supergroup, and Topic ID 3 set to deliver into a specific topic",
"groupCaption": "Supergroup — Chat ID starts with <code>-100…</code> and the optional <em>Topic ID</em> targets a specific thread.",
"step3Title": "3 · Save and test",
"step3Body": "Paste the Bot Token and Chat ID into the Telegram tab, save, and press <em>Send Test</em> at the bottom of the panel. A test message should arrive within a second; if it doesn't, the History section records the failure with the exact reason (invalid token, bot not in group, blocked by user, etc.)."
},
"discord": {
"heading": "Discord",
"intro": "Discord channels accept incoming messages through a <em>Webhook URL</em> tied to a single channel. The Monitor needs that URL and nothing else.",
"items": [
"In Discord, open the server where you want notifications to land and go to <em>Server Settings → Integrations → Webhooks</em>.",
"Click <em>New Webhook</em>. Give it a name (e.g. <em>ProxMenux</em>) and pick the channel it should post to. An avatar is optional.",
"Click <em>Copy Webhook URL</em> — it looks like <code>https://discord.com/api/webhooks/&lt;id&gt;/&lt;token&gt;</code>.",
"Paste it in the Webhook URL field of the Discord tab in the Notifications panel and save."
],
"imageAlt": "Discord channel form with Webhook URL field starting with https://discord.com/api/webhooks/",
"imageCaption": "Discord — paste the Webhook URL from <em>Server Settings → Integrations → Webhooks</em>."
},
"gotify": {
"heading": "Gotify",
"intro": "Gotify is a self-hosted push server. You need its base URL and an <em>Application Token</em> generated from the Gotify admin UI.",
"items": [
"If you don't already have a Gotify instance, install one — see the <a>official install guide</a>.",
"Open the Gotify web UI, log in as admin, go to <em>Apps</em> → <em>Create Application</em>. Give it a name (e.g. <em>ProxMenux</em>). Gotify generates a token — copy it.",
"In the Gotify tab of the Notifications panel, set <em>Server URL</em> to the base URL of your instance (e.g. <code>https://gotify.example.com</code>) and paste the App Token.",
"Save and press <em>Send Test</em>."
],
"imageAlt": "Gotify channel form with Server URL field set to https://gotify.example.com and an App Token field with placeholder A_valid_gotify_token",
"imageCaption": "Gotify — server URL of your self-hosted instance plus the App Token from the Gotify admin UI."
},
"email": {
"heading": "Email (SMTP)",
"intro": "Email is the most flexible channel — and the one with the most fields. You need an SMTP server, a port, a TLS mode, optionally a username and password, a sender address and at least one recipient.",
"imageAlt": "Email channel form with SMTP Host, Port, TLS Mode dropdown, Username, Password, From Address, To Addresses comma-separated and Subject Prefix fields",
"imageCaption": "Email — SMTP host / port / TLS mode, optional username + password, sender address, comma-separated recipients and a subject prefix to make alerts easy to filter inbox-side.",
"appNote": "If you use a personal Gmail or Microsoft 365 account, the password field cannot be your normal account password — both providers require an <strong>app password</strong> generated specifically for third-party clients. The two flows are below.",
"gmailTitle": "Gmail app password",
"gmailIntro": "Gmail app passwords require <strong>2-Step Verification</strong> to be active on the Google account. If it isn't, the <em>App passwords</em> page won't exist.",
"gmailItems": [
"Open <a>myaccount.google.com/security</a> and turn on <em>2-Step Verification</em> if it's not already on.",
"Go to <a>myaccount.google.com/apppasswords</a>.",
"Type a name (e.g. <em>ProxMenux</em>) and click <em>Create</em>. Google shows a 16-character password — copy it.",
"Fill the Email tab with: <em>Host</em> <code>smtp.gmail.com</code>, <em>Port</em> <code>587</code>, <em>TLS Mode</em> <code>STARTTLS</code>, <em>Username</em> your Gmail address, <em>Password</em> the 16-character app password."
],
"outlookTitle": "Microsoft / Outlook app password",
"outlookIntro": "Microsoft now requires <strong>two-step verification</strong> on the personal account before an app password can be created. Enterprise tenants where the admin has disabled SMTP basic auth need a different path (OAuth2) which is not currently supported by the Monitor — point those at an SMTP relay you control instead.",
"outlookItems": [
"Open <a>account.microsoft.com/security</a> and enable two-step verification.",
"Open <em>Advanced security options</em>, scroll to <em>App passwords</em> and click <em>Create a new app password</em>.",
"Microsoft shows a long random password — copy it.",
"Fill the Email tab with: <em>Host</em> <code>smtp-mail.outlook.com</code>, <em>Port</em> <code>587</code>, <em>TLS Mode</em> <code>STARTTLS</code>, <em>Username</em> your Outlook / Microsoft 365 address, <em>Password</em> the generated app password."
],
"relayTitle": "Self-hosted SMTP relay",
"relayBody": "If you run your own SMTP relay (Postfix, msmtp, etc.) on the LAN, point the Monitor at it and skip the app-password dance entirely. The relay handles auth upstream and the Monitor sends in cleartext on a trusted network."
},
"apprise": {
"heading": "Apprise (generic hub for ~80 services)",
"intro": "Apprise is an open-source notification library that speaks the protocol of around 80 different services through a single URL format. Adding it as one more channel inside the Monitor means you can deliver alerts to services that don't have a dedicated tab — ntfy, Matrix, Pushover, Slack, Microsoft Teams, Mattermost, Pushbullet, AWS SNS, Pushsafer, Rocket.Chat, Signal API and many others — without ProxMenux having to implement each integration separately.",
"listIntro": "The full list of supported services and the exact URL format for each one lives in the official Apprise wiki:",
"listItems": [
"<a>github.com/caronc/apprise/wiki</a> — full index of supported services.",
"<a>URL basics</a> — how Apprise URLs are structured."
],
"stepsTitle": "Steps",
"steps": [
"Pick the target service in the <a>Apprise wiki</a> and copy the URL template for it. Each service page shows the exact scheme to use (<code>ntfy://</code>, <code>matrix://</code>, <code>pover://</code>, <code>slack://</code>…) plus any required tokens, channels or hostnames.",
"Fill in the placeholders with your own credentials. For example, an ntfy.sh topic looks like <code>ntfy://ntfy.sh/my-topic</code>; a Pushover URL looks like <code>pover://user@token</code>; a Matrix URL looks like <code>matrix://user:pass@host:port/#room</code>.",
"Paste the final URL into the <em>Apprise URL</em> field in the Apprise tab of the Notifications panel and save.",
"Press <em>Send Test</em> to verify the URL is reachable and the credentials are accepted."
],
"deliveredTitle": "What gets delivered",
"deliveredBody": "Apprise receives the same payload as the other channels — title, body and a severity (info / success / warning / failure). Severity is mapped to whatever the destination service exposes (icon, priority, colour). Rich-message formatting and the AI rewrite layer all run before the URL is invoked, exactly like for Telegram or Email.",
"fanoutTitle": "One URL per Apprise channel",
"fanoutBody": "The Monitor exposes a single URL slot per Apprise channel. If you need to fan-out to several Apprise services at once (e.g. ntfy.sh plus a Matrix room), the cleanest approach is to host a small <a>Apprise API server</a> with a tagged config and point the Monitor at its endpoint — the server then broadcasts to every URL behind that tag."
},
"rich": {
"heading": "Rich messages, categories and per-channel filtering",
"intro": "Below the channel form every channel exposes the same three controls: a <em>Rich messages</em> toggle at the top (highlighted with the arrow in the screenshot), eleven collapsible <em>Notification Categories</em> with per-event toggles, and a <em>Send Test</em> button at the bottom.",
"imageAlt": "Notification Categories panel with Rich messages master toggle highlighted at top, collapsible sections for VM/CT, Backups, Resources, Storage, Network, Security, Cluster, Services, Health Monitor, Updates each with toggle and event count, and a Send Test button",
"imageCaption": "Top arrow — the per-channel <em>Rich messages</em> toggle. Below — the eleven collapsible categories with per-event toggles. <em>Send Test</em> sits at the bottom of the channel.",
"richTitle": "Rich messages",
"richIntro": "With <em>Rich messages</em> on, every event header is prefixed with a category emoji and the body is rendered using the channel's native formatting (Telegram HTML, Discord embed with severity colour). With it off, the Monitor sends a plain-text version with the same information minus the visual cues. Same content, different presentation:",
"plainHeader": "Plain — Rich messages off",
"richHeader": "Rich — Rich messages on",
"richOutro": "The toggle is per-channel: leave Email plain for inbox-rule readability while letting Telegram and Discord render the rich version. Channels that don't support inline formatting (plain-text email, Gotify) ignore the formatting and fall back to text either way.",
"togglesTitle": "Per-event categories",
"togglesIntro": "Around seventy event types are grouped into eleven UI categories. Each event has a master toggle and a per-channel override — two layers that decide whether a given event reaches a given channel:",
"togglesItems": [
"<strong>Per-event master toggle.</strong> If <code>vm_start</code> is off everywhere, no channel ever sees a <code>vm_start</code>. Toggles persist as <code>event_toggles[event_type] = true | false</code>.",
"<strong>Per-channel overrides.</strong> An event type can also be muted for a specific channel (<em>\"send <code>backup_complete</code> to Discord but not to Telegram\"</em>). These live in <code>channel_overrides[channel_name][event_type]</code> and only apply if the event passed the master toggle."
],
"togglesOutro": "Each category header in the screenshot also shows the count of events <em>currently enabled</em> / <em>total</em> for that group, and a category-level toggle that flips every event inside it on or off in one click — the shortcut for muting a whole group (e.g. all <code>info</code> backups, all update-related events) without expanding the section."
},
"quiet": {
"heading": "Quiet Hours",
"intro": "Quiet Hours is a per-channel time window during which the dispatcher only lets <strong>CRITICAL</strong> events through. Everything else — INFO, WARNING, action events — is held back, persisted to disk, and delivered as a single grouped summary the moment the window closes. The channel still gets the urgent things in real time; the noise waits until you're likely to want it.",
"imageAlt": "Channel settings showing both knobs side-by-side: Quiet Hours card with toggle on, Start 22:00 and End 07:00 plus a live preview of the next transition, and right below it the Daily digest card with its own toggle, a delivery time picker set to 09:00 and the note that CRITICAL and WARNING are never delayed",
"imageCaption": "Both knobs live side-by-side inside each channel's settings card — Quiet Hours on top, Daily digest underneath. Independent per channel.",
"purposeTitle": "What it is for",
"purposeItems": [
"<strong>Don't wake me at 03:00 for an update notice.</strong> Backups, app updates, post-install optimisations and other INFO-level events stop pinging your phone at night.",
"<strong>But still wake me for a fire.</strong> Disk failures, OOM kills, host shutdowns, fail2ban bans — anything classified as CRITICAL — bypass the window and arrive immediately.",
"<strong>Don't miss anything either.</strong> The events suppressed during the window aren't silently dropped — they sit in a SQLite buffer until you're back on the clock."
],
"howTitle": "How it works",
"howItems": [
"<strong>Per-channel toggle.</strong> Each channel has its own Quiet Hours config — Telegram can be silent 22:0007:00 while email keeps receiving everything 24/7.",
"<strong>Start and end time</strong> in your local timezone, half-open interval (start inclusive, end exclusive). The window can cross midnight (e.g. 22:0007:00 means tonight until tomorrow morning).",
"<strong>Live preview line</strong> right below the inputs shows whether the window is currently active and when the next transition happens. Saves opening a clock.",
"<strong>During the window:</strong> CRITICAL events still fire through the normal dispatch pipeline. INFO and WARNING events are routed to a persistent buffer (<code>quiet_pending</code> table in the Monitor's SQLite DB).",
"<strong>When the window closes:</strong> a single grouped notification is sent with everything that accumulated — one line per buffered event, in chronological order. The buffer is cleared only after the channel confirms delivery, so a transient Telegram / SMTP outage doesn't lose the night's context.",
"<strong>Across restarts.</strong> If the Monitor restarts mid-window, the buffer is intact on disk. If the restart happens just after the window closed, the next dispatch cycle detects the pending rows and flushes them with a single \"recovery\" summary — no notifications are lost to a deploy or a reboot."
],
"criticalTitle": "What counts as CRITICAL",
"criticalBody": "Severity is set at event creation, not at dispatch time. Disk failures, OOM kills, cluster split-brain, host shutdowns and the \"hard\" tier of disk I/O errors ship as CRITICAL by design. Everything else (backups OK, updates available, INFO logs, rate-limit hits) defaults to INFO or WARNING and is therefore quietable. You can verify a given event's default severity in the <link>Event catalogue</link> further down this page."
},
"digest": {
"heading": "Daily digest of INFO events",
"intro1": "The Daily Digest is the opposite knob: an <strong>opt-in</strong> setting that says \"don't send me every successful backup or update notice as it happens — collect them and send me one summary per day at 09:00 (or whatever hour I choose)\". Same goal as Quiet Hours (less noise) but a different mechanism (time-based summary instead of a daily window).",
"intro2": "It lives in the same channel-settings card as Quiet Hours (see the figure under <link>Quiet Hours</link>), right underneath. You enable each one independently.",
"purposeTitle": "What it is for",
"purposeItems": [
"<strong>The morning \"everything that happened\" recap.</strong> If you check on the host once a day with a coffee, one digest at 09:00 carries the same information as 20 individual pings throughout the previous day, without you reading 20 Telegram bubbles.",
"<strong>Separate noise from signal.</strong> INFO events answer \"what happened\"; CRITICAL and WARNING answer \"what do I need to do right now\". The digest handles the first; everything else keeps its live delivery."
],
"howTitle": "How it works",
"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>What goes into the digest:</strong> any event the channel would have received live whose severity is <strong>INFO</strong>. Examples — <em>vzdump complete</em>, <em>Tailscale update available</em>, <em>ProxMenux optimisation update available</em>, <em>APT security updates pending</em>, <em>rate-limit hit</em>.",
"<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."
],
"neverDelayedSub": [
"<strong>CRITICAL</strong> events always go through immediately.",
"<strong>WARNING</strong> events always go through immediately.",
"Live-action events (VM/CT start / stop / shutdown / restart, vm_fail / ct_fail, backup start / fail, replication start / fail, host shutdown / reboot) bypass the digest even at INFO severity — you opted in to see those live, the digest would defeat that opt-in."
],
"comboTitle": "Combining Quiet Hours and Daily Digest",
"comboBody": "The two work together. A channel can have <em>both</em> active — Quiet Hours from 22:00 to 07:00 plus a Daily Digest at 09:00. INFO events during the quiet window go to the quiet buffer and arrive at 07:00 as the close-of-window summary; INFO events during the day go to the digest buffer and arrive at 09:00 the next morning. CRITICAL and WARNING always cut through both. Choose Quiet Hours when the goal is a <em>window of silence</em>, the Daily Digest when the goal is a <em>fixed-time summary</em>; many setups want both."
},
"displayName": {
"heading": "Display Name",
"intro": "Every notification carries a <em>Display Name</em> — the label that identifies which host produced the alert. It is the value you see at the bottom of the rich-messages example above (<code>🏠 home-lab</code>) and inside the email subject prefix.",
"imageAlt": "Display Name field with the value amd shown as example, label Name shown in notifications - edit to customize or leave empty to use the system hostname",
"imageCaption": "The Display Name field — leave empty to use the system hostname, or override with anything you want.",
"outro": "If the field is empty, the Monitor falls back to the system hostname. The override is mostly useful when you run several ProxMenux hosts that send to the same Telegram chat or inbox — a friendlier label (<em>home-lab</em>, <em>office-pve</em>) is easier to read than <code>pve01.lan</code> or <code>pmx-prod-01</code>."
},
"dispatch": {
"heading": "Dispatch pipeline",
"intro": "Between an event being raised and a message leaving the host, three stages run in this order:",
"headerStage": "Stage",
"headerWhat": "What it does",
"headerTunable": "Tunable?",
"rows": [
{
"stage": "1. Fingerprint dedup",
"what": "Each event is hashed into a fingerprint (<code>event_type + key fields from data</code>). Identical fingerprints inside a short window are considered duplicates of the first one.",
"tunable": "No — internal dispatcher logic."
},
{
"stage": "2. Cooldown",
"what": "After a fingerprint is sent, the same fingerprint is suppressed for the per-severity cooldown duration. Stored in the <code>notification_last_sent</code> SQLite table so it survives restarts. Defaults: <code>CRITICAL</code> 60 s, <code>WARNING</code> 300 s, <code>INFO</code> 900 s, plus a per-category override on top (e.g. <code>resources</code> 900 s, <code>updates</code> 86 400 s).",
"tunable": "No — defaults baked into the dispatcher."
},
{
"stage": "3. Burst aggregation",
"what": "When N events of a kind arrive inside a short window (e.g. an SSH brute-force flood), they are merged into a single <code>burst_*</code> message with a count and a sample.",
"tunable": "No — window and threshold are hard-coded per event type."
}
],
"calloutTitle": "Dispatch happens in a background thread",
"calloutBody": "The dispatch loop runs in its own thread. The HTTP request that emits an event returns as soon as the event is queued — it does not wait for Telegram, SMTP or webhook RTT. Every send result is recorded in the history table for retrospective inspection."
},
"aiRewrite": {
"heading": "Optional AI rewrite",
"body1": "Any event can be passed through an LLM that rewrites its body in plain language and (optionally) in the target user's language before fan-out. The AI rewriter is off by default. When enabled it runs in the dispatch thread; if the provider call fails or times out, the original templated body is used instead.",
"body2": "Six providers are supported (OpenAI, Anthropic, Google Gemini, Groq, OpenRouter and local Ollama), with per-channel detail level (<code>brief</code>, <code>standard</code>, <code>detailed</code>), output language, prompt mode (<code>default</code> or <code>custom</code>) and an optional custom prompt. Full configuration walk-through, captures and prompt examples live in the dedicated <link>AI Assistant</link> page.",
"privacyTitle": "Privacy note",
"privacyBody": "AI rewrite sends the event body — which can include hostnames, IP addresses, usernames, error messages and journal lines — to the configured provider. Ollama keeps everything on-host; the other five providers transmit data to their respective endpoints. Disable the rewriter, or use Ollama, if the host runs in an environment where event content cannot leave the network."
},
"pveWebhook": {
"heading": "PVE webhook integration",
"intro1": "Proxmox VE 8.1+ has its own notification system with built-in <em>endpoints</em> (sendmail, gotify, SMTP, webhook). When you enable Notifications on the Monitor, it registers itself as one of those endpoints — a <code>webhook</code> target that points back at the Monitor's own API. From that moment on, anything Proxmox itself emits (HA fencing, replication, vzdump from the GUI, certificate renewal, etc.) flows through the same dispatch pipeline as the Monitor's own events.",
"intro2": "The target is visible from the Proxmox GUI at <em>Datacenter → Notifications → Notification Targets</em>:",
"imageAlt": "Proxmox VE Edit Webhook dialog showing the auto-created proxmenux-webhook target with method POST, URL http://127.0.0.1:8008/api/notifications/webhook and a JSON body template using escape title, escape message, escape severity, escape timestamp and json fields",
"imageCaption": "The PVE-side webhook target as Proxmox sees it (the GUI is in the host's configured locale — Spanish in this example). Same fields apply in any language.",
"registeredIntro": "What gets registered:",
"registeredItems": [
"<strong>Method & URL.</strong> <code>POST http://127.0.0.1:8008/api/notifications/webhook</code>. Loopback only — PVE talks to the Monitor process running 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>Companion priv block.</strong> An empty <code>webhook: proxmenux-webhook</code> entry is appended to <code>/etc/pve/priv/notifications.cfg</code>. PVE refuses to instantiate any webhook endpoint without a matching private block, even when no secrets are needed — so the Monitor writes a header-only stub there. No tokens, headers or HMAC are configured on the PVE side."
],
"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:",
"securityItems": [
"<strong>Loopback (<code>127.0.0.1</code> / <code>::1</code>).</strong> Rate-limit only. The endpoint trusts the loopback interface — only processes running on the host can reach it, and PVE itself cannot send custom auth headers in the body it generates. This is the path every PVE-emitted notification travels.",
"<strong>Remote callers.</strong> Five layers stack on top of rate-limiting: a shared secret in the <code>X-Webhook-Secret</code> header, a freshness timestamp in <code>X-ProxMenux-Timestamp</code> (rejected if it drifts more than the configured window), a replay-cache lookup, and an optional IP allowlist. The shared secret lives in the Monitor's SQLite settings table — not in <code>/etc/pve/priv/notifications.cfg</code> — and is generated at first setup. This path exists for custom integrations posting from outside the host; the PVE-configured target never exercises it."
],
"practiceTitle": "In practice",
"practiceBody": "The PVE setup writes the target as <code>http://127.0.0.1:8008</code>, so PVE-emitted notifications always go through the loopback path with rate-limit-only security. The remote-caller path with the shared secret is opt-in for custom integrations — point an external service at <code>https://&lt;monitor-host&gt;:&lt;port&gt;/api/notifications/webhook</code> and supply the <code>X-Webhook-Secret</code> header to use it.",
"actionsIntro": "The Monitor manages this target through three actions on the Settings tab:",
"actionsItems": [
"<strong>Setup</strong> — runs automatically when you enable Notifications. Creates the entry in <code>/etc/pve/notifications.cfg</code> after backing up the current file.",
"<strong>Cleanup</strong> — removes the entry. The previous backup of the file is kept.",
"<strong>Read config</strong> — shows the current targets and matchers as PVE sees them. This is how you confirm the Monitor's entry is the one firing when PVE has multiple notification routes configured."
],
"clusterTitle": "Cluster nodes",
"clusterBody": "<code>/etc/pve/</code> is replicated across cluster members, so the webhook target is visible on every node. Each node, however, posts to its <em>own</em> <code>127.0.0.1:8008</code> — meaning the Monitor running on that node receives the events that PVE generated locally. Run the Monitor on every node you want to see in the Notifications history."
},
"catalogue": {
"heading": "Event catalogue",
"intro": "Around seventy event types are grouped into eleven UI categories. The Notifications panel renders one collapsible section per group with a toggle for every event inside it. Each event is on by default unless explicitly marked otherwise.",
"headerGroup": "Group",
"headerEvents": "Events",
"rows": [
{
"group": "VM / CT",
"events": "<code>vm_start</code>, <code>vm_start_warning</code>, <code>vm_stop</code>, <code>vm_shutdown</code>, <code>vm_fail</code>, <code>vm_restart</code>, plus the <code>ct_*</code> equivalents, <code>migration_start</code>, <code>migration_complete</code>, <code>migration_warning</code>, <code>migration_fail</code>, <code>replication_complete</code>, <code>replication_fail</code>."
},
{
"group": "Backups",
"events": "<code>backup_start</code>, <code>backup_complete</code>, <code>backup_warning</code>, <code>backup_fail</code>, <code>snapshot_complete</code>, <code>snapshot_fail</code>."
},
{
"group": "Resources",
"events": "<code>cpu_high</code>, <code>ram_high</code>, <code>temp_high</code>, <code>load_high</code>."
},
{
"group": "Storage",
"events": "<code>disk_space_low</code>, <code>disk_io_error</code>, <code>storage_unavailable</code>, <code>smart_test_complete</code>, <code>smart_test_failed</code>."
},
{
"group": "Network",
"events": "<code>network_down</code>, <code>network_latency</code>."
},
{
"group": "Security",
"events": "<code>auth_fail</code>, <code>ip_block</code>, <code>firewall_issue</code>, <code>user_permission_change</code>."
},
{
"group": "Cluster",
"events": "<code>split_brain</code>, <code>node_disconnect</code>, <code>node_reconnect</code>."
},
{
"group": "Services",
"events": "<code>system_startup</code>, <code>system_shutdown</code>, <code>system_reboot</code>, <code>system_problem</code>, <code>service_fail</code>, <code>oom_kill</code>, <code>system_mail</code>."
},
{
"group": "Health Monitor",
"events": "<code>new_error</code>, <code>error_resolved</code>, <code>error_escalated</code>, <code>health_degraded</code>, <code>health_persistent</code>, <code>health_issue_new</code>, <code>health_issue_resolved</code>."
},
{
"group": "Updates",
"events": "<code>update_summary</code>, <code>update_available</code>, <code>pve_update</code>, <code>update_complete</code>, <code>proxmenux_update</code>."
},
{
"group": "Hardware / GPU",
"events": "<code>gpu_mode_switch</code>, <code>gpu_passthrough_blocked</code>, <code>pci_passthrough_conflict</code>, <code>ai_model_migrated</code>."
}
],
"burstNote": "A handful of <code>burst_*</code> aggregation types (<code>burst_auth_fail</code>, <code>burst_ip_block</code>, <code>burst_disk_io</code>, etc.) exist only in the dispatcher — they replace bursts of individual events with a single summary message and are not exposed as toggles in the UI. They inherit the on/off state of their parent event type."
},
"history": {
"heading": "History",
"body1": "Every dispatch <em>attempt</em> the dispatcher actually performs is recorded in the <code>notification_history</code> SQLite table. Each row stores the timestamp (<code>sent_at</code>), channel, event type, severity, title, rendered message body, a <code>success</code> flag and — when the send failed — the error returned by the provider in <code>error_message</code>. Burst-aggregated events appear as a single row with the <code>burst_*</code> event type. Events suppressed by the cooldown stage are not logged: they never become a dispatch attempt.",
"body2": "The History tab inside Settings → Notifications shows the last 20 entries and has a single <em>Clear</em> button that wipes the table.",
"body3": "The same data is exposed at <code>GET /api/notifications/history</code> with optional <code>limit</code>, <code>offset</code>, <code>severity</code> and <code>channel</code> query parameters, and can be cleared with <code>DELETE /api/notifications/history</code>."
},
"api": {
"heading": "API endpoints",
"headerEndpoint": "Endpoint",
"headerMethod": "Method",
"headerUse": "Use",
"rows": [
{
"endpoint": "/api/notifications/settings",
"method": "GET / POST",
"use": "Read or write the full configuration (channels, per-event toggles, AI rewriter, Display Name)."
},
{
"endpoint": "/api/notifications/test",
"method": "POST",
"use": "Send a test notification to one channel: <code>'{'\"channel\":\"telegram\"'}'</code>."
},
{
"endpoint": "/api/notifications/test-ai",
"method": "POST",
"use": "Render and rewrite a sample event without dispatching it."
},
{
"endpoint": "/api/notifications/provider-models",
"method": "POST",
"use": "List available models for the selected AI provider."
},
{
"endpoint": "/api/notifications/send",
"method": "POST",
"use": "Emit an event from outside (custom integrations)."
},
{
"endpoint": "/api/notifications/history",
"method": "GET / DELETE",
"use": "Read history with filters; clear it."
},
{
"endpoint": "/api/notifications/webhook",
"method": "POST",
"use": "Receives Proxmox VE's own notifications. Loopback callers are rate-limited only; remote callers must additionally pass the <code>X-Webhook-Secret</code> header, <code>X-ProxMenux-Timestamp</code> freshness check, replay cache and optional IP allowlist."
},
{
"endpoint": "/api/notifications/proxmox/setup-webhook",
"method": "POST",
"use": "Register the Monitor as a target in <code>/etc/pve/notifications.cfg</code>."
},
{
"endpoint": "/api/notifications/proxmox/cleanup-webhook",
"method": "POST",
"use": "Remove the Monitor target from PVE's notification config."
},
{
"endpoint": "/api/notifications/proxmox/read-cfg",
"method": "GET",
"use": "Show the current PVE notification config as PVE sees it."
}
]
},
"whereNext": {
"heading": "Where to next",
"items": [
{
"label": "AI Assistant",
"href": "/docs/monitor/ai-assistant",
"tail": " — providers, models, prompt modes, languages, per-channel detail levels."
},
{
"label": "Health Monitor",
"href": "/docs/monitor/health-monitor",
"tail": " — the largest single producer of events, with its own per-category suppression durations."
},
{
"label": "Architecture",
"href": "/docs/monitor/architecture",
"tailRich": " — where the SQLite tables (<code>notification_last_sent</code>, <code>notification_history</code>) and the dispatch thread fit into the wider Monitor process."
},
{
"label": "Access & Authentication",
"href": "/docs/monitor/access-auth",
"tailRich": " — how API tokens are minted for scripts that call <code>/api/notifications/send</code>."
},
{
"label": "Dashboard → System Logs",
"href": "/docs/monitor/dashboard/system-logs",
"tail": " — the live view of the same journal that feeds the journal watcher."
}
]
}
}
@@ -0,0 +1,110 @@
{
"meta": {
"title": "Interfaces Backup & Restart | ProxMenux Documentation",
"description": "Manual snapshot, browse and restore /etc/network/interfaces backups stored under /var/backups/proxmenux/. Includes a network service restart with confirmation and a quick view of the live configuration.",
"ogTitle": "Interfaces Backup & Restart | ProxMenux Documentation",
"ogDescription": "Snapshot and restore Proxmox network configuration; restart the networking service with confirmation."
},
"header": {
"title": "Interfaces backup & restart",
"description": "Four utilities that revolve around /etc/network/interfaces: take a manual snapshot, view the live config, restore a previous backup with optional preview, and restart the networking service with explicit consent. Same backup directory used by the guided repair flows.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "Manages the same backup directory used by the guided repair flows (<code>/var/backups/proxmenux/</code>). Lets you take an extra snapshot before any manual change, browse all existing backups, and roll back to any of them — always with a fresh pre-restore backup taken automatically as a second safety net."
},
"shared": {
"heading": "The shared backup directory",
"intro": "Every backup taken anywhere in the Network menu lands in the same place:",
"outro": "Filenames are timestamped, sorted by date, and never overwritten. The directory is created on first use."
},
"show": {
"heading": "Show Network Config File",
"body": "Prints <code>/etc/network/interfaces</code> verbatim to the terminal. Read-only. Useful as a sanity check before taking a backup or after a restore — there is no separate \"diff with previous backup\" tool, so eyeballing the live file is the easiest way to confirm what you have."
},
"create": {
"heading": "Create Network Backup",
"body": "Copies the current <code>/etc/network/interfaces</code> into the backup directory with a fresh timestamp. That's it — no analysis, no prompts, just a snapshot.",
"whenTitle": "When to take a manual backup",
"whenBody": "Before editing <code>/etc/network/interfaces</code> by hand, before installing a package that may touch the network stack (e.g. NetworkManager, Open vSwitch), or before any hardware change. The guided repairs already snapshot automatically — this option is for the <em>manual</em> moments."
},
"restore": {
"heading": "Restore Network Backup",
"intro": "Lists every backup in <code>/var/backups/proxmenux/</code> sorted from newest to oldest, and walks through a guarded restore:",
"steps": [
{
"title": "1. Pick a backup",
"body": "A menu lists each backup by its timestamp. If no backups exist, the flow exits with a clear message.",
"tone": "blue"
},
{
"title": "2. Optional preview",
"body": "Offers to open the selected backup in a scrollable view before committing. Yes by default — do not skip it on a remote host.",
"tone": "blue"
},
{
"title": "3. Pre-restore backup",
"body": "Before overwriting <code>/etc/network/interfaces</code>, takes <strong>another</strong> backup of the current state. Restoring a backup is itself a destructive action, so the new pre-restore snapshot lets you go back if the chosen backup turns out to be the wrong one.",
"tone": "amber"
},
{
"title": "4. Apply the restore",
"body": "Copies the chosen backup over <code>/etc/network/interfaces</code>. The file change is on disk; the live kernel state still reflects the previous config.",
"tone": "amber"
},
{
"title": "5. Optional restart",
"body": "Asks whether to run <code>systemctl restart networking</code> now. Decline to defer the change to the next reboot.",
"tone": "emerald"
}
],
"autoBackupTitle": "A restore takes its own backup automatically",
"autoBackupBody": "Selecting <em>Restore Network Backup</em> always creates a fresh snapshot of the <em>current</em> config before overwriting it. If you restore to the wrong backup, the most recent file in <code>/var/backups/proxmenux/</code> is the state you came from."
},
"restart": {
"heading": "Restart Network Service",
"body": "Runs <code>systemctl restart networking</code> after a yes/no confirmation. Reports the result with <code>msg_ok</code> / <code>msg_error</code>. Most flows in this menu offer their own restart prompt at the end; this option is for restarting after a manual edit or after declining the in-flow restart earlier.",
"warnTitle": "Brief disconnection guaranteed; permanent disconnection possible",
"warnBody": "Restarting <code>networking</code> tears down and re-applies every interface declared in <code>/etc/network/interfaces</code>. SSH sessions hosted on those interfaces drop. If the new config is invalid, the network never comes back. Run this only when:",
"warnItems": [
"You have console / IPMI / iKVM access ready, <em>or</em>",
"You are physically next to the machine, <em>or</em>",
"You have just successfully rolled back to a known-good config and want to apply it."
]
},
"manualRollback": {
"heading": "Manual rollback from a console",
"intro": "If you cannot reach the menu (no SSH, dialog crashing, …) but can reach a console, rollback is two commands:",
"outro": "This is the <em>same</em> operation the menu performs, just typed by hand. If <code>networking</code> still fails to start, check <code>journalctl -u networking -b</code> for the underlying syntax / driver error."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noneTitle": "\"No backups found\" in Restore",
"noneBody": "The directory <code>/var/backups/proxmenux/</code> does not exist or contains no <code>interfaces_backup_*</code> files. Run <em>Create Network Backup</em> at least once, or run any guided repair (which auto-creates one). Confirm with <code>ls /var/backups/proxmenux/</code>.",
"unreachTitle": "Restart networking succeeds but the host is still unreachable",
"unreachBody": "Either the new config is wrong, or you restarted into a configuration that does not bind your management IP. Roll back from the console (see above). After rollback, use <bridgeLink>bridge analysis</bridgeLink> and <configLink>config analysis</configLink> to understand what was wrong before re-applying.",
"emptyTitle": "Restore preview shows an empty file",
"emptyBody": "The backup file is empty (0 bytes). This happens if a copy failed silently during a previous run. Pick an older backup, or re-run <em>Create Network Backup</em> right now if the live config is healthy."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis",
"tail": " — the most common reason a backup ends up here."
},
{
"label": "Config analysis & guided cleanup",
"href": "/docs/network/config-analysis",
"tailRich": " — also writes to <code>/var/backups/proxmenux/</code> automatically."
},
{
"label": "Diagnostics",
"href": "/docs/network/diagnostics",
"tail": " — verify the live state after a restore."
}
]
}
}
@@ -0,0 +1,132 @@
{
"meta": {
"title": "Bridge Analysis & Guided Repair | ProxMenux Documentation",
"description": "Detects vmbrX bridges with missing or invalid physical ports (typical after PCI re-enumeration), reports them with proposed shell commands, and offers a 5-step guided repair with mandatory backup.",
"ogTitle": "Bridge Analysis & Guided Repair | ProxMenux Documentation",
"ogDescription": "Audit and repair Proxmox bridge ports after hardware changes, with guided rollback-safe flow."
},
"header": {
"title": "Bridge analysis & guided repair",
"description": "Audits every vmbrX bridge declared in /etc/network/interfaces, verifies that its physical ports actually exist, and offers a step-by-step repair when they don't. The analysis is read-only; the repair is gated, previewed and backed up.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "Reads each bridge in <code>/etc/network/interfaces</code>, looks at its <code>bridge-ports</code> line and checks whether each declared port (e.g. <code>enp3s0</code>) actually exists on the host. If a port is missing, proposes a substitute and — with explicit consent — applies the change with a <strong>backup, preview, apply, verify</strong> flow."
},
"when": {
"heading": "When you need this",
"intro": "Linux assigns predictable interface names from PCI topology and slot order. Several events shuffle them and leave <code>/etc/network/interfaces</code> referring to names that no longer exist:",
"items": [
"Adding or removing a PCIe card (a NIC, a GPU, a HBA, an NVMe carrier).",
"Moving an existing card to a different PCIe slot.",
"BIOS / UEFI updates that re-enumerate PCI devices.",
"Migrating the boot disk to different hardware."
],
"outro": "After the next boot, the bridge tries to attach to a port that no longer exists, fails to come up, and the host loses its network. <link>Persistent interface names</link> prevents this from happening again — but if you are already locked out, this page is the recovery path."
},
"bigPicture": {
"heading": "The big picture",
"diagram1": {
"arrowLabel": "step 1",
"nodes": {
"sourceLabel": "/etc/network/interfaces",
"sourceDetail": "auto vmbr0\niface vmbr0 inet static\n bridge-ports enp3s0",
"bridgeLabel": "Analyze (read-only)",
"bridgeDetail": "ip link show enp3s0\n→ does not exist",
"targetLabel": "Report + suggestion",
"targetDetail": "❌ enp3s0: NOT FOUND\nReplace with: eno1\n(no changes yet)"
}
},
"diagram2": {
"arrowLabel": "apply with backup",
"nodes": {
"sourceLabel": "Guided repair",
"sourceDetail": "1. Backup\n2. Show current\n3. Preview changes\n4. Apply\n5. Verify",
"targetLabel": "/etc/network/interfaces (new)",
"targetDetail": "auto vmbr0\niface vmbr0 inet static\n bridge-ports eno1"
}
}
},
"step1": {
"heading": "Step 1: analysis (read-only)",
"intro": "Selecting <strong>Analyze Bridge Configuration</strong> aborts immediately if the host is not on the classic Debian/Proxmox stack. Otherwise it walks every bridge and reports:",
"items": [
"Bridge name, current status (UP / DOWN), assigned IP.",
"Each declared port and whether it currently exists (<code>ip link show &lt;port&gt;</code>).",
"For each invalid port: a proposed replacement (the first available physical interface) plus the exact <code>sed</code> command to apply it manually.",
"Bridges with no <code>bridge-ports</code> at all and orphan <code>auto</code> entries (no matching <code>iface</code> block)."
],
"readonlyTitle": "Read-only guarantee",
"readonlyBody": "Up to this point the script has not run a single modifying command. You can leave the analysis open, copy the suggested <code>sed</code> commands and apply them manually if you prefer — or accept the next prompt to enter the guided repair."
},
"step2": {
"heading": "Step 2: guided repair (5 steps)",
"intro": "Only entered if you accept the prompt at the end of the analysis. Each step shows what will happen and asks for confirmation before continuing.",
"steps": [
{
"title": "1. Safety backup",
"body": "Copies <code>/etc/network/interfaces</code> to <code>/var/backups/proxmenux/interfaces_backup_&lt;TIMESTAMP&gt;</code>. The exact backup path is shown before the copy and again after, with the rollback command.",
"tone": "blue"
},
{
"title": "2. Review current configuration",
"body": "Opens the live <code>/etc/network/interfaces</code> in a scrollable dialog so you can see exactly what is about to be changed.",
"tone": "blue"
},
{
"title": "3. Preview proposed changes",
"body": "Lists exactly which bridges will be touched and which port substitutions will happen. If the analysis decides nothing actually needs fixing (race condition: the port came back), the flow exits cleanly with <em>\"No changes needed.\"</em>",
"tone": "blue"
},
{
"title": "4. Apply changes",
"body": "For each affected bridge, runs <code>sed -i \"/iface $bridge/,/bridge-ports/ s/bridge-ports.*/bridge-ports $new_ports/\"</code> against <code>/etc/network/interfaces</code>. If a bridge had no valid replacement available, the substitution is skipped and reported in step 5.",
"tone": "amber"
},
{
"title": "5. Verification",
"body": "Re-reads the file and confirms each bridge's new port now exists. Prints the rollback command (<code>cp &lt;backup&gt; /etc/network/interfaces</code>). Finally offers a <strong>Restart networking</strong> prompt — accept only if you have console fallback.",
"tone": "emerald"
}
],
"restartTitle": "Restarting networking ≠ a free undo",
"restartBody": "The repair is written to disk regardless of whether you restart the service. <code>systemctl restart networking</code> applies the change <em>now</em>, which can drop your SSH session if the new port is wrong. If you decline the restart, the change still takes effect on the next reboot — confirm the new config first or roll back from the printed command."
},
"edits": {
"heading": "What gets edited (exactly)",
"body": "Only the <code>bridge-ports</code> line of each affected bridge. Other directives (<code>address</code>, <code>netmask</code>, <code>gateway</code>, <code>bridge-stp</code>, …) are left untouched. The script never creates new <code>iface</code> blocks and never removes existing ones in this flow — that is the job of <link>Config analysis &amp; cleanup</link>."
},
"troubleshoot": {
"heading": "Troubleshooting",
"unsupportedTitle": "Analysis aborts with \"Unsupported Network Stack\"",
"unsupportedBody": "The host runs netplan, systemd-networkd or NetworkManager. The tool only supports <code>/etc/network/interfaces</code>. Switch the host to the classic stack first, or edit the configuration with the manager's native tooling (e.g. <code>netplan apply</code>).",
"noSuggestTitle": "No suggestion is printed for an invalid port",
"noSuggestBody": "The host has zero free physical interfaces (everything is either already in another bridge or doesn't exist). The analysis falls back to suggesting <code>bridge-ports none</code> so the bridge can at least come up without a port. Add a NIC or migrate ports between bridges manually before re-running.",
"stillDownTitle": "The repair completes but the bridge is still DOWN",
"stillDownBody": "<code>sed</code> updated the file but <code>systemctl restart networking</code> was declined. Run it manually once the new config is verified, or reboot. If the restart was accepted and the bridge is still DOWN, run <code>ip link show</code> to confirm the new port exists, then check <code>journalctl -u networking</code> for the actual error (cable unplugged, link not negotiated, port already a member of another bridge).",
"lostSshTitle": "I lost SSH access right after restarting networking",
"lostSshIntro": "Use console / IPMI / iKVM to reach the host. Restore the backup:",
"lostSshOutro": "Then re-run the analysis from the console to figure out why the suggestion did not work (typically: the replacement port is not actually plugged in)."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Persistent interface names",
"href": "/docs/network/persistent-names",
"tail": " — pin names to MAC addresses so this scenario stops happening."
},
{
"label": "Config analysis & guided cleanup",
"href": "/docs/network/config-analysis",
"tailRich": " — for orphaned <code>iface</code> blocks (the other half of the same problem)."
},
{
"label": "Interfaces backup & restart",
"href": "/docs/network/backup-restore",
"tail": " — manual snapshots and the restore browser."
}
]
}
}
@@ -0,0 +1,122 @@
{
"meta": {
"title": "Config Analysis & Guided Cleanup | ProxMenux Documentation",
"description": "Detects iface blocks in /etc/network/interfaces that reference physical NICs no longer present on the host. Reports them and offers a 5-step guided removal with mandatory backup and per-block preview.",
"ogTitle": "Config Analysis & Guided Cleanup | ProxMenux Documentation",
"ogDescription": "Find and remove orphan interface blocks left behind by hardware changes, with full preview and rollback."
},
"header": {
"title": "Config analysis & guided cleanup",
"description": "Walks every iface block in /etc/network/interfaces and verifies that the underlying physical NIC still exists. Reports orphan blocks left behind by hardware changes and offers a guided removal with backup, preview and per-block confirmation.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "Identifies <code>iface</code> declarations whose backing NIC is no longer present on the host (typical after replacing or removing a network card). Then offers a guided cleanup that removes <em>only</em> the orphan blocks, with a backup, a per-section preview and an explicit final confirmation."
},
"differs": {
"heading": "How it differs from bridge analysis",
"headerAspect": "Aspect",
"headerBridge": "Bridge analysis",
"headerConfig": "Config analysis",
"rows": [
{
"aspect": "Looks at",
"bridge": "Bridges (<code>vmbrX</code>) and their <code>bridge-ports</code> line",
"config": "Every <code>iface</code> block (excluding loopback, bridges, bonds)"
},
{
"aspect": "Detects",
"bridge": "Bridges referencing a non-existent port",
"config": "Standalone interface blocks for NICs that don't exist"
},
{
"aspect": "Repair action",
"bridge": "Replaces the port name in <code>bridge-ports</code>",
"config": "Removes the entire <code>iface</code> block"
},
{
"aspect": "Excludes",
"bridge": "Nothing — every bridge is analyzed",
"config": "Bridges (<code>vmbrX</code>) and bonds (<code>bondX</code>) are always kept, since they are virtual and \"not existing\" would be normal during boot"
}
],
"outro": "In practice you often run both, in this order: <strong>config analysis</strong> first to remove orphans, then <link>bridge analysis</link> to re-point any bridge that was relying on the now-removed interface."
},
"step1": {
"heading": "Step 1: analysis (read-only)",
"intro": "Aborts immediately if the host is not on the classic stack. Otherwise lists every configured non-loopback interface and reports its status:",
"virtTitle": "Virtual interfaces are protected",
"virtBody": "Bridges (<code>vmbrX</code>) and bonds (<code>bondX</code>) are virtual constructs. They may legitimately not exist at the moment of inspection (e.g. a bridge with no ports yet), so the analysis never proposes removing them — only physical NICs."
},
"step2": {
"heading": "Step 2: guided cleanup (5 steps)",
"intro": "Only entered if you accept the prompt at the end of the analysis. Each step requires confirmation; cancelling at any point exits without writing.",
"steps": [
{
"title": "1. Safety backup",
"body": "Copies <code>/etc/network/interfaces</code> to <code>/var/backups/proxmenux/interfaces_backup_&lt;TIMESTAMP&gt;</code>. Path shown before and after.",
"tone": "blue"
},
{
"title": "2. Confirm the removal list",
"body": "Lists exactly which physical interface blocks will be removed. If, between analysis and cleanup, the NICs reappeared (e.g. you re-seated a card), the flow exits with <em>\"No cleanup needed.\"</em>",
"tone": "blue"
},
{
"title": "3. Preview the exact block(s)",
"body": "Opens a scrollable view of every <code>iface</code> block that would be deleted, verbatim from the file. This is the moment to spot e.g. an interesting <code>up</code> hook you want to preserve.",
"tone": "blue"
},
{
"title": "4. Apply removal",
"body": "For each orphan interface, runs <code>sed -i \"/^iface $iface/,/^$/d\" /etc/network/interfaces</code>. That deletes from the matching <code>iface</code> line up to the next blank line.",
"tone": "amber"
},
{
"title": "5. Verification",
"body": "Re-reads the file, lists what was removed, and re-checks the remaining interfaces. Prints the rollback command. Does <strong>not</strong> automatically restart networking — removing an unused block is safe to apply on the next reboot, and avoids touching the live state.",
"tone": "emerald"
}
],
"noRestartTitle": "Does not auto-restart networking",
"noRestartBody": "Unlike bridge repair, the cleanup flow does not offer to restart the service. Removing an unused interface block has no immediate effect on the running config, so a restart is unnecessary and would be a needless connectivity risk. The change takes effect on the next manual <code>systemctl restart networking</code> or at the next reboot."
},
"caveats": {
"heading": "Important caveats",
"boundaryTitle": "The block boundary is the first blank line",
"boundaryBody": "The <code>sed</code> pattern deletes from <code>iface &lt;name&gt;</code> down to the next empty line. If your <code>/etc/network/interfaces</code> has no blank line separating blocks (rare, but possible if hand-edited), the deletion may consume the next block too. This is why <strong>step 3 is mandatory</strong>: review the preview before confirming.",
"tandemTitle": "An orphan iface used by a bridge is detected here, not in bridge analysis",
"tandemBody": "If <code>vmbr0</code> declares <code>bridge-ports enp3s0</code> and <code>enp3s0</code> also has its own <code>iface enp3s0 inet manual</code> block, removing <code>enp3s0</code> here will leave <code>vmbr0</code> with a dangling reference. After the cleanup, run <link>bridge analysis</link> to repoint or remove the bridge port. The two flows are designed to be used in tandem."
},
"troubleshoot": {
"heading": "Troubleshooting",
"notFoundTitle": "The analysis shows my new NIC as \"NOT FOUND\"",
"notFoundBody": "The kernel sees the device under a different name than what is in the file. Run <code>ip link show</code> to get the actual name. This is exactly the case where <link>Persistent interface names</link> would prevent the issue going forward.",
"tooMuchTitle": "The cleanup removed too much (a block I wanted to keep)",
"tooMuchBody": "Restore from the backup printed in step 5:",
"tooMuchOutro": "Edit the file by hand to add a clear blank line between blocks before re-running the cleanup, or remove the problematic block manually.",
"bridgeBreakTitle": "A bridge stops working after the cleanup",
"bridgeBreakBody": "The bridge was relying on a port whose <code>iface</code> block was just removed. Run <link>bridge analysis</link> and the suggestion will point the bridge at an existing physical interface."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis",
"tail": " — the natural follow-up after a cleanup."
},
{
"label": "Persistent interface names",
"href": "/docs/network/persistent-names",
"tail": " — stops orphan blocks from accumulating after each hardware change."
},
{
"label": "Interfaces backup & restart",
"href": "/docs/network/backup-restore",
"tail": " — manual snapshots and the restore browser."
}
]
}
}
@@ -0,0 +1,94 @@
{
"meta": {
"title": "Diagnostics | ProxMenux Documentation",
"description": "Three read-only one-shot diagnostic checks: Show Routing Table, Test Connectivity and Advanced Diagnostics. Pure inspection — never writes to /etc/network/interfaces and never runs a modifying command (one explicit, opt-in exception for purging NetworkManager when detected).",
"ogTitle": "Diagnostics | ProxMenux Documentation",
"ogDescription": "Read-only network diagnostics for the Proxmox host: routing, reachability, advanced statistics."
},
"header": {
"title": "Diagnostics",
"description": "Three one-shot read-only checks that inspect the live network state: routing table, connectivity test and advanced statistics. None of them write to /etc/network/interfaces — safe to use at any time, including over SSH. For interactive live monitoring, see Live monitoring tools.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "Reports on routing, reachability and aggregate statistics <strong>without modifying anything</strong>. Use it to confirm the network is healthy or identify duplicate IPs. For continuous traffic observation see <monitoringLink>Live monitoring tools</monitoringLink>; for viewing the raw config file see <backupLink>Interfaces backup & restart</backupLink>."
},
"routing": {
"heading": "Show Routing Table",
"body": "Lists every route the kernel currently uses (<code>ip route show</code>) and highlights the default gateway. Useful for confirming that traffic to the internet leaves through the expected interface and that no leftover routes are taking precedence."
},
"connectivity": {
"heading": "Test Connectivity",
"intro": "Sends two ICMP probes to three targets in sequence and reports each one. Then runs an <code>nslookup google.com</code> to verify DNS resolution independently of ICMP.",
"headerTest": "Test",
"headerTarget": "Target",
"headerConfirms": "What it confirms",
"rows": [
{
"test": "Google DNS",
"target": "8.8.8.8",
"confirms": "External reachability via well-known anycast IP"
},
{
"test": "Cloudflare DNS",
"target": "1.1.1.1",
"confirms": "Independent second-opinion if Google blocks ICMP"
},
{
"test": "Gateway",
"target": "(default route)",
"confirms": "L2 / L3 connectivity to the local router"
},
{
"test": "DNS Resolution",
"target": "google.com",
"confirms": "DNS server is reachable and answering"
}
],
"readingTitle": "Reading the result",
"readingBody": "If the gateway test passes but the public DNS targets fail, you have local connectivity but no internet — check the gateway's upstream. If DNS resolution fails but pings to <code>8.8.8.8</code> succeed, the issue is the resolver, not the network: check <code>/etc/resolv.conf</code>."
},
"advanced": {
"heading": "Advanced Diagnostics",
"intro": "Aggregates network-wide statistics and runs a battery of common-issue checks. Reports active connection counts, listening ports, total interfaces and flags two anti-patterns explicitly:",
"items": [
"<strong>NetworkManager running on a Proxmox host.</strong> NetworkManager and Proxmox's <code>ifupdown</code> conflict — both try to manage interfaces, leading to bridges that flap or refuse to come up. If detected, the tool offers an interactive prompt to stop, disable and purge it (this is the <em>only</em> diagnostic that can modify the system, and only after explicit consent).",
"<strong>Duplicate IP addresses on different interfaces.</strong> Two interfaces holding the same IPv4 cause intermittent connectivity that's extremely hard to debug from inside the VM. Detected via <code>ip -4 addr show | sort | uniq -d</code>."
],
"nmTitle": "The NetworkManager prompt is the only modifying action here",
"nmBody": "Every other check in Advanced Diagnostics is read-only. NetworkManager removal is gated behind a yes/no dialog and runs <code>systemctl stop / disable</code> + <code>apt-get purge -y network-manager</code>. If you decline, nothing changes."
},
"troubleshoot": {
"heading": "Troubleshooting",
"gwTitle": "Test Connectivity reports the gateway as failed but the host has internet",
"gwBody": "Some routers do not respond to ICMP from their internal interface even when they happily forward traffic. Test with <code>traceroute 8.8.8.8</code> from a console: if the second hop is your ISP and the public DNS test passed, the gateway is fine despite the failed ping.",
"dupTitle": "Advanced Diagnostics keeps flagging duplicate IPs after I removed one",
"dupBody": "The check looks at the live kernel state, not the config file. Run <code>ip -4 addr show</code> to confirm; if the duplicate is still present, an interface is still holding it. Use <code>ip addr del &lt;IP&gt;/&lt;mask&gt; dev &lt;iface&gt;</code> to remove it from the live state, then edit <code>/etc/network/interfaces</code> if it is also persistent."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Live monitoring tools",
"href": "/docs/network/monitoring",
"tail": " — interactive iftop / iptraf-ng / iperf3 launchers."
},
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis",
"tail": " — when a vmbrX is missing its physical port."
},
{
"label": "Config analysis & guided cleanup",
"href": "/docs/network/config-analysis",
"tail": " — when an old NIC is still declared but no longer present."
},
{
"label": "Interfaces backup & restart",
"href": "/docs/network/backup-restore",
"tail": " — to snapshot the config before any change."
}
]
}
}
+107
View File
@@ -0,0 +1,107 @@
{
"meta": {
"title": "Proxmox Network Management — Bridges, Bonds, Diagnostics, Repair | ProxMenux",
"description": "Read-only diagnostics, analyze-then-suggest workflows and guided repairs for the Debian / Proxmox network stack (/etc/network/interfaces). Inspect bridges and bonds, run live monitoring tools, persist interface names, back up and safely restart networking — with mandatory backups and step-by-step previews.",
"ogTitle": "Proxmox Network Management — Bridges, Bonds, Diagnostics, Repair",
"ogDescription": "Diagnostics, analysis and guided repairs for the Proxmox network stack with mandatory backups and step-by-step previews.",
"twitterTitle": "Proxmox Network Management | ProxMenux",
"twitterDescription": "Bridges, bonds, diagnostics and guided repairs for the Proxmox network stack with mandatory backups."
},
"header": {
"title": "Network Management",
"description": "Read-only diagnostics, analyze-then-suggest reports and guided repairs for the classic Debian/Proxmox network stack. Every destructive flow takes a backup first and previews the exact changes before applying them.",
"section": "Network"
},
"intro": {
"title": "What this menu is for",
"body": "Inspect, diagnose and (when needed) repair the Proxmox host network configuration without losing remote access. The tools are designed around one principle: <strong>read first, propose, then apply only with explicit consent and a safety backup</strong>. There is no \"auto-fix everything\" button."
},
"openingMenu": {
"heading": "Opening the menu",
"intro": "From ProxMenux's main menu, select <strong>Network</strong>. You will see this:",
"imageAlt": "Network Management menu with diagnostics, monitoring, analysis, repair, persistent names and backup options"
},
"safety": {
"heading": "The safety model",
"body": "Editing network configuration on a remote Proxmox host is one of the easiest ways to lock yourself out. ProxMenux treats every action accordingly. The tools fall into three behavioural tiers — pick the card that matches your intent:"
},
"tiers": {
"readOnly": {
"title": "Read-only",
"body": "Pure inspection. Cannot modify the system under any circumstance.",
"items": [
"Routing table, connectivity tests, advanced statistics",
"Live traffic monitoring (iftop, iptraf-ng)",
"Bandwidth test (iperf3)"
]
},
"analyze": {
"title": "Analyze, then suggest",
"body": "Detects issues, prints a report with proposed shell commands, and stops. You decide whether to enter the guided repair afterwards.",
"items": [
"Bridge configuration analysis",
"Network configuration analysis"
]
},
"apply": {
"title": "Apply with backup",
"body": "Modifies the system. Always takes a timestamped backup of the affected file first and shows a preview before writing.",
"items": [
"Persistent interface names (.link files)",
"Manual backup, restore and service restart"
]
}
},
"classicTitle": "Classic stack only",
"classicBody": "Every analysis and repair function checks the active network manager before touching anything. If the host runs <strong>netplan</strong>, <strong>systemd-networkd</strong> or <strong>NetworkManager</strong>, the tool aborts immediately with a clear message — the menu only supports the classic Debian/Proxmox stack at <code>/etc/network/interfaces</code>. This is intentional: editing a netplan file with rules written for <code>ifupdown</code> would silently corrupt the configuration.",
"backups": {
"heading": "Where backups go",
"intro": "Every guided repair, restore or manual backup writes a timestamped copy of <code>/etc/network/interfaces</code> to <code>/var/backups/proxmenux/</code>:",
"rollbackIntro": "To roll back manually from a console:"
},
"readOnlySection": {
"heading": "Read-only inspection",
"body": "The starting point when something feels off. Pure inspection — never writes to <code>/etc/network/interfaces</code> and never runs a modifying command (with one explicit, opt-in exception for purging NetworkManager when detected). Safe to use over SSH at any time.",
"options": [
{
"title": "Diagnostics",
"description": "Three one-shot read-only checks: Show Routing Table, Test Connectivity and Advanced Diagnostics. Pure inspection — never writes to the system."
},
{
"title": "Live monitoring tools",
"description": "Three interactive launchers: iftop (real-time bandwidth per host pair), iptraf-ng (multi-mode traffic monitor) and iperf3 (bandwidth test, server / client mode)."
}
]
},
"analyzeSection": {
"heading": "Analyze, then suggest",
"body": "Used when an inspection (or a real outage) points at a configuration issue. Each tool walks the relevant part of <code>/etc/network/interfaces</code>, prints a detailed report with the exact shell command that would fix each finding, and <strong>stops</strong>. If you accept the optional guided repair afterwards, every change is backed up and previewed before being written.",
"options": [
{
"title": "Bridge analysis & guided repair",
"description": "Detects vmbrX bridges with missing or invalid ports (typical after PCI re-enumeration). Shows a report first; only repairs when you accept the 5-step guided flow."
},
{
"title": "Config analysis & guided cleanup",
"description": "Finds physical interfaces declared in /etc/network/interfaces that no longer exist (orphan configs left behind by hardware changes). Reports them and offers a guided removal."
}
]
},
"applySection": {
"heading": "Apply with backup",
"body": "Tools that write to disk by design. Each one takes a timestamped backup of the affected file before writing, and the destructive options (restore, restart) require an explicit yes/no confirmation. <em>Persistent interface names</em> takes effect at the next reboot, not immediately, so it is safe to schedule even on a remote host.",
"options": [
{
"title": "Persistent interface names",
"description": "Pins interface names (eno1, enp3s0, …) to MAC addresses via systemd .link files. Names survive PCI slot changes, kernel upgrades and adding / removing other NICs."
},
{
"title": "Interfaces backup & restart",
"description": "Manual snapshot of /etc/network/interfaces, browse and restore previous backups, view the live config, and restart the networking service when needed."
}
]
},
"consoleTitle": "Have console access ready",
"consoleSubTitle": "Before any repair on a remote host",
"consoleBody": "If you are connected over SSH and only have one path to the host, have a fallback before applying network changes: physical / IPMI / iKVM console, or another machine on the same LAN. The guided repairs are safe and always offer a roll-back command, but a misconfigured bridge or a dropped link can still leave you locked out until you can reach the console."
}
@@ -0,0 +1,136 @@
{
"meta": {
"title": "Live Monitoring Tools | ProxMenux Documentation",
"description": "Three interactive network monitoring launchers: iftop (real-time bandwidth per host pair), iptraf-ng (multi-mode traffic monitor) and iperf3 (bandwidth test, server / client mode). Each is installed on first use.",
"ogTitle": "Live Monitoring Tools | ProxMenux Documentation",
"ogDescription": "Interactive network monitoring and bandwidth testing for the Proxmox host: iftop, iptraf-ng, iperf3."
},
"header": {
"title": "Live monitoring tools",
"description": "Three interactive launchers for real-time network observation and bandwidth measurement: iftop, iptraf-ng and iperf3. Each tool is auto-installed from apt on first use, runs in the foreground, and is exited with the documented keystroke. Read-only against the host configuration — they only observe traffic.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "Three interactive monitoring tools, each behind its own menu entry. The first time you launch one, the package is installed silently via <code>apt-get</code>. Subsequent launches start instantly. None of these tools modify the host network configuration."
},
"when": {
"heading": "When to use which",
"headerQuestion": "Question",
"headerUse": "Use",
"rows": [
{
"question": "Who is saturating the link <em>right now</em>?",
"use": "iftop"
},
{
"question": "What protocol breakdown / packet sizes / TCP flows are flowing?",
"use": "iptraf-ng"
},
{
"question": "How much bandwidth is actually available between two hosts?",
"use": "iperf3"
}
]
},
"iftop": {
"heading": "Real-time network usage (iftop)",
"body": "Live bandwidth per host pair (source ↔ destination) — like <code>top</code> for traffic. Shows the heaviest flows at the top, with rolling 2/10/40-second averages. Best tool for the question <em>\"why is my uplink saturated?\"</em>.",
"exit": "<strong>Exit:</strong> press <kbd>q</kbd>. ProxMenux shows a reminder dialog before launching.",
"keysTitle": "Useful keys inside iftop",
"keysBody": "<kbd>n</kbd> toggle DNS lookup, <kbd>p</kbd> show port numbers, <kbd>P</kbd> pause display, <kbd>t</kbd> toggle line direction (sent / received / both), <kbd>1</kbd>/<kbd>2</kbd>/<kbd>3</kbd> sort by 2s / 10s / 40s average. <code>man iftop</code> for the full set."
},
"iptraf": {
"heading": "Network monitoring tool (iptraf-ng)",
"intro": "A menu-driven multi-mode traffic monitor. Where iftop answers <em>\"who\"</em>, iptraf-ng answers <em>\"what\"</em>: per-protocol byte/packet counts, TCP connection state tracking, packet size histograms and per-station LAN activity.",
"menuIntro": "On launch you get a five-option menu:",
"headerMode": "Mode",
"headerUseFor": "Use it for",
"rows": [
{
"mode": "IP traffic monitor",
"useFor": "Live TCP / UDP / ICMP / other-IP flow list with byte counters and connection state"
},
{
"mode": "General interface stats",
"useFor": "Aggregate IPv4 / IPv6 / TCP / UDP / ICMP / non-IP packet counts per NIC"
},
{
"mode": "Detailed interface stats",
"useFor": "Same as above but for one interface, with packet size and rate detail"
},
{
"mode": "Statistical breakdowns",
"useFor": "Packet size distribution histogram, by TCP / UDP port"
},
{
"mode": "LAN station monitor",
"useFor": "Per-MAC traffic stats for the local broadcast domain"
}
],
"exit": "<strong>Exit:</strong> press <kbd>x</kbd> from any view (or <kbd>Q</kbd> from the main menu). ProxMenux shows a reminder dialog before launching.",
"logTitle": "Logging captures to file",
"logBody": "Each mode offers to log captured stats to <code>/var/log/iptraf-ng/</code>. Useful if you need a record of a traffic spike — leave it running, log to file, review the file afterwards instead of trying to read the live screen."
},
"iperf3": {
"heading": "Bandwidth test (iperf3)",
"intro1": "Measures actual TCP throughput between two hosts. Unlike iftop / iptraf-ng (which observe existing traffic), iperf3 generates synthetic traffic to stress-test the link. Indispensable for answering questions like <em>\"is my 10 GbE actually doing 10 GbE?\"</em> or <em>\"is the bottleneck the NIC, the switch, or the storage?\"</em>.",
"intro2": "iperf3 is a <strong>two-host tool</strong>: one side runs as server (listens on TCP port 5201), the other runs as client (connects, sends data, prints the rate). The ProxMenux launcher asks which mode you want:",
"headerMode": "Mode",
"headerBehaviour": "Behaviour",
"headerCli": "Equivalent CLI",
"rows": [
{
"mode": "Server",
"behaviour": "Listens on TCP 5201 and prints results for each incoming test. Stops on Ctrl+C.",
"cli": "iperf3 -s"
},
{
"mode": "Client",
"behaviour": "Asks for the server IP / hostname, connects, runs a default 10-second test and prints the report.",
"cli": "iperf3 -c <target>"
}
],
"workflowIntro": "Typical workflow to test a 10 GbE link between two Proxmox hosts:",
"workflow": [
"On host A, open the Network menu → <em>Bandwidth test (iperf3)</em> → choose <strong>Server</strong>.",
"On host B, open the same menu entry → choose <strong>Client</strong> → enter host A's IP.",
"Wait 10 seconds. Compare the reported rate to the link's theoretical maximum."
],
"sample": "Sample client output:",
"flagsTitle": "Useful manual flags (run from a shell)",
"flagsBody": "<code>-t 60</code> longer test (60s instead of default 10s), <code>-P 4</code> 4 parallel streams (saturates faster), <code>-R</code> reverse direction (server → client), <code>-u -b 100M</code> UDP test at 100 Mbit/s (for jitter / packet loss measurements), <code>-p 5202</code> use a different port (multiple tests in parallel). <code>man iperf3</code> for the full set.",
"firewallTitle": "Open the firewall port on the server",
"firewallBody": "The server listens on TCP <strong>5201</strong> by default. If you run the server inside a Proxmox host with a strict firewall (datacenter or host level), allow inbound TCP 5201 from the client's IP for the duration of the test, then close it again. Same applies to <code>nftables</code> / <code>iptables</code> on bare hosts."
},
"install": {
"heading": "First launch installs the package",
"body": "All three launchers check for the binary and run <code>apt-get update -qq &amp;&amp; apt-get install -y &lt;pkg&gt;</code> if missing. The install is silent: the menu may appear frozen for 1030 seconds the first time. Subsequent launches start instantly."
},
"troubleshoot": {
"heading": "Troubleshooting",
"hangTitle": "Install hangs forever on first launch",
"hangBody": "The host has no internet or the apt repos are unreachable. Cancel with <kbd>Ctrl</kbd>+<kbd>C</kbd>, run <code>apt-get update</code> manually to see the actual error (DNS, repo signature, proxy …), then come back to the menu.",
"refusedTitle": "iperf3 client: \"unable to connect to server: Connection refused\"",
"refusedBody": "Either the server is not running, or its firewall blocks TCP 5201. Confirm on the server: <code>ss -tlnp | grep 5201</code> — should show iperf3 listening. If listening but client still fails, check the firewall path between the two hosts.",
"slowTitle": "iperf3 reports way less than the expected link speed",
"slowBody": "Common causes, in order of likelihood: (1) one of the hosts is bottlenecked on CPU — try <code>iperf3 -c &lt;target&gt; -P 4</code> to use multiple cores; (2) the path goes through a slower link (gigabit switch in the middle of two 10 GbE NICs); (3) MTU mismatch — check <code>ip link show</code> on both ends; (4) NIC offloading disabled — see the <em>Disable NIC Offloading</em> community script if you have an Intel e1000e card.",
"noTrafficTitle": "iftop / iptraf-ng show no traffic for a busy host",
"noTrafficBody": "Default capture is on the first detected interface. Specify the right one explicitly from the shell: <code>iftop -i vmbr0</code> or <code>iptraf-ng -i vmbr0</code>. The menu launcher uses the default; for non-default interfaces, run from a console."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Diagnostics",
"href": "/docs/network/diagnostics",
"tail": " — the read-only one-shot checks (routing, connectivity, advanced stats)."
},
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis",
"tail": " — when monitoring reveals an interface or bridge isn't doing what it should."
}
]
}
}
@@ -0,0 +1,130 @@
{
"meta": {
"title": "Persistent Interface Names | ProxMenux Documentation",
"description": "Pin Proxmox interface names (eno1, enp3s0, …) to MAC addresses via systemd .link files so names survive PCI re-enumeration, kernel upgrades and adding / removing other NICs.",
"ogTitle": "Persistent Interface Names | ProxMenux Documentation",
"ogDescription": "Stop Proxmox interface names from changing when you alter hardware. Uses systemd .link files keyed on MAC address."
},
"header": {
"title": "Persistent interface names",
"description": "Generates a systemd .link file per physical NIC that pins the kernel-assigned name to the card's MAC address. Once applied (after the next reboot), interface names stop drifting when you add, remove or move PCIe cards.",
"section": "Network"
},
"intro": {
"title": "What this does",
"body": "For every physical NIC on the host, writes a small file under <code>/etc/systemd/network/10-&lt;iface&gt;.link</code> that says: <em>\"the device with this MAC must always be called this name\"</em>. systemd-udevd applies the rule at every boot, before <code>ifupdown</code> reads <code>/etc/network/interfaces</code>."
},
"problem": {
"heading": "The problem this solves",
"intro": "Linux derives default interface names from PCI topology — <code>eno1</code> = onboard, <code>enp3s0</code> = the card in PCI bus 3, slot 0, etc. The naming scheme is deterministic <em>given the same hardware layout</em>. Change the layout and names shift:",
"items": [
"Add a GPU in front of an existing NIC → the NIC bus number can change → name changes.",
"Move a card to a different PCIe slot → name changes.",
"BIOS / UEFI update that re-enumerates devices → names can change.",
"Replace a faulty card with the same model in a different slot → name changes."
],
"outro": "After such a change, <code>/etc/network/interfaces</code> still references the <em>old</em> name; the bridge fails to come up; the host loses network. Setting up persistent names prevents this scenario from happening again."
},
"howWorks": {
"heading": "How it works",
"arrowLabel": "per NIC",
"nodes": {
"detectLabel": "Detect physical NICs",
"detectDetail": "ls /sys/class/net/\nfilter out vmbr / bond /\ndocker / veth / wireguard …",
"readLabel": "Read each MAC",
"readDetail": "cat /sys/class/net/\n '<'iface'>'/address",
"writeLabel": "Write .link file",
"writeDetail": "/etc/systemd/network/\n 10-'<'iface'>'.link"
},
"minimalIntro": "Each generated file is intentionally minimal:",
"minimalOutro": "At boot, systemd-udevd matches the device by MAC and assigns the requested name <em>before</em> any other component (ifupdown, kernel default naming) gets to it. The file prefix <code>10-</code> ensures these rules load early, ahead of the default <code>99-default.link</code>."
},
"scope": {
"heading": "What gets written, what gets skipped",
"headerType": "Type",
"headerBehaviour": "Behaviour",
"headerWhy": "Why",
"rows": [
{
"type": "Onboard / PCIe NIC",
"behaviour": "<code>.link</code> file written",
"why": "Backed by a real PCI device — the case the tool is for"
},
{
"type": "Wi-Fi (phy80211)",
"behaviour": "<code>.link</code> file written",
"why": "Has a real MAC and benefits from name stability"
},
{
"type": "Bridges (vmbrX)",
"behaviour": "Skipped",
"why": "Virtual; name comes from <code>/etc/network/interfaces</code>"
},
{
"type": "Bonds (bondX)",
"behaviour": "Skipped",
"why": "Virtual; bond name is set by ifupdown"
},
{
"type": "veth / docker0 / br-XXXX",
"behaviour": "Skipped",
"why": "Created on demand by Docker / LXC — not persistent hardware"
},
{
"type": "tap / fwpr / fwln",
"behaviour": "Skipped",
"why": "Created on demand by Proxmox per VM/CT"
},
{
"type": "WireGuard / Cilium / Tailscale",
"behaviour": "Skipped",
"why": "Software interfaces managed by their own daemons"
}
]
},
"safety": {
"heading": "Safety net: previous .link files are backed up",
"intro": "If <code>/etc/systemd/network/</code> already contains <code>.link</code> files (from a previous run or other tooling), they are copied to a timestamped backup directory before the new ones are generated:",
"outro": "To roll back: copy the files back from the backup directory and reboot.",
"rebootTitle": "Takes effect on next reboot, not immediately",
"rebootBody": "Changes to <code>.link</code> files only apply at boot, when udev re-enumerates devices. The tool reports <em>\"Changes will apply after reboot\"</em> for this reason. Renaming an interface live is risky and not attempted: an active <code>vmbr0</code> with members would have to be reconfigured atomically, which is why the operation is deferred to the next clean boot."
},
"afterReboot": {
"heading": "After the reboot",
"intro": "Once the names are pinned, the workflow for future hardware changes is simple:",
"items": [
"Power off, change hardware (add card, move slot, …), boot.",
"Each NIC keeps its previous name because its MAC matches a <code>.link</code> file.",
"If a NIC is replaced (different MAC), it gets a default kernel name (<code>enp&lt;bus&gt;s&lt;slot&gt;</code>); re-run this menu to add a <code>.link</code> entry for the new card's MAC."
]
},
"troubleshoot": {
"heading": "Troubleshooting",
"emptyTitle": "\"No physical interfaces found\" after running the tool",
"emptyBody": "The host has no PCI / phy80211-backed interfaces visible to the kernel. Confirm with <code>ls -l /sys/class/net/</code> — every entry should have either a <code>device</code> symlink (PCI) or a <code>phy80211</code> entry (Wi-Fi). If both are missing for what should be a real NIC, the driver is not loaded.",
"noChangeTitle": "After the reboot, names did not change as expected",
"noChangeBody": "Check that the file is present and well-formed: <code>cat /etc/systemd/network/10-&lt;iface&gt;.link</code>. Then check udev logs: <code>journalctl -u systemd-udevd -b | grep -i link</code>. A common cause is a stale <code>net.ifnames=0</code> kernel parameter that disables predictable naming entirely — remove it from <code>/etc/default/grub</code>, run <code>update-grub</code>, reboot.",
"undoTitle": "I want to undo persistent naming",
"undoBody": "Either delete the <code>.link</code> files (<code>rm /etc/systemd/network/10-*.link</code>) or restore from the backup directory generated on the previous run. Reboot to apply."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Bridge analysis & guided repair",
"href": "/docs/network/bridge-analysis",
"tailRich": " — the recovery path when names <em>have</em> already shifted."
},
{
"label": "Config analysis & guided cleanup",
"href": "/docs/network/config-analysis",
"tail": " — to remove orphan blocks left behind by name shifts."
},
{
"label": "Diagnostics",
"href": "/docs/network/diagnostics",
"tailRich": " — confirm the new names with <em>Show Routing Table</em> after reboot."
}
]
}
}
@@ -0,0 +1,172 @@
{
"meta": {
"title": "Automated Post-Install Script | ProxMenux Documentation",
"description": "The ProxMenux Automated post-install script applies a curated set of 13 safe, hardware-aware optimizations to a fresh Proxmox VE host with zero prompts. Every change is registered for later reversal via Uninstall Optimizations.",
"ogTitle": "Automated Post-Install Script | ProxMenux Documentation",
"ogDescription": "13 curated optimizations applied to a fresh Proxmox VE host with zero prompts. Hardware-aware (SSD/NVMe auto-detect) and fully reversible."
},
"header": {
"title": "Automated Post-Install Script",
"description": "One click, zero prompts — ProxMenux applies a curated set of 13 safe optimizations that almost every Proxmox host benefits from. Every change is registered in the tools JSON so you can undo any of them later from Uninstall Optimizations.",
"section": "Post-Install · Automated"
},
"intro": {
"title": "When to pick Automated",
"body": "Run this on a freshly installed Proxmox host when you want the sensible baseline without making decisions. The script is idempotent — running it twice is safe, it just re-applies the same configurations. Opt-in features (Fastfetch, IOMMU, Ceph repo, HA, AMD fixes…) are intentionally <strong>not</strong> part of this path; pick them from <link>Customizable</link> if you need them."
},
"applies": {
"heading": "What the script applies",
"intro": "The optimizations are applied in this exact order. The <em>Category</em> column links to the detailed documentation of each change in the Customizable reference.",
"headerNum": "#",
"headerTool": "Tool",
"headerWhat": "What it does",
"headerCategory": "Category"
},
"optimizations": [
{
"tool": "APT repositories + full upgrade",
"what": "Disables the enterprise pve-enterprise.sources and ceph.sources, writes a clean no-subscription source for the host's Debian codename, then runs apt update && apt full-upgrade -y (Proxmox's official upgrade command).",
"category": "Basic Settings",
"categorySlug": "basic-settings"
},
{
"tool": "Subscription banner removal",
"what": "Patches the web UI to hide the 'No valid subscription' banner. Asks for confirmation before applying; reversible from Uninstall Optimizations.",
"category": "Customization",
"categorySlug": "customization"
},
{
"tool": "Force IPv4",
"what": "Writes /etc/apt/apt.conf.d/99-force-ipv4 so apt uses IPv4 only — bypasses flaky IPv6 mirror setups.",
"category": "Network",
"categorySlug": "network"
},
{
"tool": "Skip language packages",
"what": "Writes /etc/apt/apt.conf.d/99-disable-translations to stop downloading locale-specific packages. Faster, lighter apt updates.",
"category": "Basic Settings",
"categorySlug": "basic-settings"
},
{
"tool": "Increase system limits",
"what": "Raises inotify watches, nofile/nproc limits, kernel keyring limits and fs.file-max across sysctl.d, limits.d, pam and systemd — high enough for container-heavy hosts.",
"category": "System",
"categorySlug": "system"
},
{
"tool": "Memory tuning",
"what": "Sets vm.swappiness=10, balanced dirty ratios, vm.overcommit_memory=1, vm.max_map_count=262144 and compaction proactiveness when supported.",
"category": "System",
"categorySlug": "system"
},
{
"tool": "Kernel panic behaviour",
"what": "Configures the host to reboot 10 seconds after a panic / oops / hardlockup instead of freezing indefinitely.",
"category": "System",
"categorySlug": "system"
},
{
"tool": "Network stack tuning",
"what": "TCP buffer sizing, IPv4 hardening (redirects off, rp_filter=2, martian log off), local port range 1024-65535, TCP MTU probing, RFC 1337, plus a oneshot systemd unit to normalise virtual firewall bridges.",
"category": "Network",
"categorySlug": "network"
},
{
"tool": "Bashrc customisation (root)",
"what": "Colored PS1, common aliases (l/la/ll/ls/grep), timestamped history and bash-completion sourcing, all inside a PMX_CORE_BASHRC fenced block so it is easy to remove.",
"category": "Customization",
"categorySlug": "customization"
},
{
"tool": "Log2RAM (SSD-aware, auto)",
"what": "Detects whether the root disk is SSD / NVMe and installs Log2RAM from upstream git. Sizes the ramdisk by host RAM (128M / 256M / 512M), schedules periodic sync and a 95 % threshold auto-sync. Adjusts journald limits to fit in the ramdisk.",
"category": "Storage",
"categorySlug": "storage"
},
{
"tool": "ZFS autotrim (SSD-only)",
"what": "Enables zpool autotrim=on on every ZFS pool whose vdevs are all SSD/NVMe with TRIM support (checks /sys/block/<dev>/queue/rotational and discard_granularity). Pools backed by HDDs are skipped automatically. Only pools actually changed by ProxMenux are recorded for uninstall — pools you set autotrim on manually are left alone.",
"category": "Storage",
"categorySlug": "storage"
},
{
"tool": "Journald size limits",
"what": "Forces persistent storage, caps SystemMaxUse=64M / RuntimeMaxUse=60M, sets compression, info-level logging (required for the Monitor). Skipped automatically when Log2RAM is active (it does its own adjustment).",
"category": "System",
"categorySlug": "system"
},
{
"tool": "Logrotate tuning",
"what": "Daily rotation with size cap 10M, 7 rotations, compression and copytruncate — Log2RAM-friendly.",
"category": "System",
"categorySlug": "system"
},
{
"tool": "Persistent interface names",
"what": "Writes /etc/systemd/network/10-*.link files matching each physical NIC by MAC so eth0 / enp… names stay stable across reboots and new NIC additions.",
"category": "Network",
"categorySlug": "network"
}
],
"hardwareTitle": "Hardware-aware defaults",
"hardwareBody": "The script reads the host hardware before applying settings. Log2RAM is only installed on SSD / NVMe root disks by default (it prompts if detection says otherwise). Log2RAM ramdisk size is picked from total RAM (<code>≤ 8 GB → 128M</code>, <code>≤ 16 GB → 256M</code>, <code>'>' 16 GB → 512M</code>). The journald limits are matched to the ramdisk size when Log2RAM is active, to avoid filling it.",
"upgrade": {
"heading": "Update and upgrade system",
"intro": "The very first step of the Automated bundle is the Proxmox upgrade. Proxmox's own upgrade guidance for a running host (within the same major version) is to run:",
"after": "That single line is the official command on any current Proxmox release. The Automated script runs <strong>exactly</strong> that, and wraps it with the repo hygiene and post-upgrade cleanup the official upgrade guide also recommends — same steps as the standalone <link>Proxmox System Update</link> utility:",
"items": [
"Disables the enterprise <code>pve-enterprise.sources</code> / <code>ceph.sources</code>, removes legacy repo files, writes a clean no-subscription source for the host's codename.",
"Runs the upgrade non-interactively with <code>DEBIAN_FRONTEND=noninteractive</code> and <code>--force-confdef --force-confold</code> — config files you customised stay yours when upstream also changed them.",
"Installs essential Proxmox packages if missing (<code>zfsutils-linux</code>, <code>proxmox-backup-restore-image</code>, <code>chrony</code>).",
"LVM metadata sanity check, <code>apt-get autoremove -y</code> + <code>apt-get autoclean -y</code>, and a reboot prompt only if the kernel actually changed."
],
"sameTitle": "Same updater, two entry points",
"sameBody": "The Automated bundle and the standalone <link>Proxmox System Update</link> utility share the same underlying scripts (<code>update-pve8.sh</code> / <code>update-pve9_2.sh</code>). Use the utility on its own when you only want to upgrade the host without applying the rest of the optimizations."
},
"endResult": {
"heading": "Expected end result",
"body": "When the script finishes, you will see a success message with the per-step output and a reboot prompt (some kernel settings require a restart to take effect). Declining the reboot is safe; the settings apply at the next boot.",
"imageAlt": "Automated post-install script — final terminal output showing each optimization applied successfully"
},
"notDoes": {
"heading": "What this script does NOT do",
"items": [
"Timezone auto-detection (commented out upstream; use Customizable if you want it).",
"Disable portmapper / rpcbind (see <secLink>Security</secLink>).",
"Enable IOMMU / VFIO (see <virtLink>Virtualization</virtLink>).",
"Install Fastfetch / Figurine / Ceph repo / HA / AMD CPU fixes (see <optLink>Optional</optLink>).",
"Install pigz or apply ZFS ARC tuning (see <perfLink>Performance</perfLink> / <storLink>Storage</storLink>)."
]
},
"xshokTitle": "xshok-proxmox detection",
"xshokBody": "If the host has previously run the <code>xshok-proxmox</code> script, ProxMenux detects the marker file and warns you before continuing. Some tweaks can overlap. The companion script is deprecated — if you decide to continue anyway, review <link>the overview</link> for context.",
"revert": {
"heading": "Reverting",
"body": "Every tool in the table above registers itself in <code>/usr/local/share/proxmenux/installed_tools.json</code>. Open <link>Uninstall Optimizations</link> to pick individual items to revert. Backups of modified config files are placed next to the originals with a <code>.bak</code> suffix."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — pick exactly what you want from the same catalog."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — revert any subset of what was applied here."
},
{
"label": "Useful System Commands",
"href": "/docs/help-info/system-commands",
"tail": " — verify the changes (uptime, free, journalctl, etc.)."
},
{
"label": "Post-Install overview",
"href": "/docs/post-install",
"tail": "."
}
]
}
}
@@ -0,0 +1,240 @@
{
"meta": {
"title": "Post-Install: Basic Settings | ProxMenux Documentation",
"description": "Foundational post-install options: switch to free Proxmox repositories and upgrade, auto-detect timezone and enable NTP, skip APT language downloads, and pick from 25 common system utilities to install."
},
"header": {
"title": "Post-Install: Basic Settings",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Four foundational options you typically want on any fresh Proxmox host: switch to the free community repositories and run a full system upgrade, auto-configure the timezone and NTP sync, strip APT language downloads to save bandwidth and disk, and pick from a list of 25 common system utilities."
},
"upgrade": {
"heading": "Update and upgrade system",
"intro": "Reconfigures APT to use the free <em>pve-no-subscription</em> repository (instead of the enterprise repo that requires a subscription) and runs a full system upgrade. The exact steps depend on the Proxmox VE major version: ProxMenux detects it and dispatches to the right script.",
"headerVersion": "PVE version",
"headerScript": "Dispatcher script",
"headerCodename": "Debian codename",
"rows": [
{
"version": "9.x",
"script": "update-pve9_2.sh",
"codename": "trixie"
},
{
"version": "8.x",
"script": "update-pve8.sh",
"codename": "bookworm"
}
],
"officialTitle": "The official Proxmox recommendation",
"officialBody": "Proxmox's own upgrade guidance is to run, in this exact order:",
"officialOutro": "That single line is all you need on any current Proxmox release. The challenge isn't the command itself — it's making sure the repositories on the host are sane <em>before</em> running it.",
"doesTitle": "What the ProxMenux option does — verified against the script",
"doesIntro": "The ProxMenux update wraps the exact apt commands above and adds a number of pre/post steps you would otherwise have to remember by hand. Every item below is what the dispatcher script actually does (see <link>Proxmox System Update</link> for the full breakdown):",
"doesItems": [
"<strong>Repository hygiene first.</strong> Disables the enterprise <code>pve-enterprise.sources</code> / <code>ceph.sources</code>, removes legacy repo files left over from previous PVE versions, and writes a clean <code>proxmox.sources</code> pointing at the free <em>pve-no-subscription</em> channel (matching the host's Debian codename: trixie for PVE 9, bookworm for PVE 8).",
"<strong>Debian repos rewritten</strong> with main / updates / security, including <code>non-free-firmware</code>, so the firmware warning during upgrade goes away.",
"<strong>Runs the official upgrade.</strong> <code>apt-get update</code> followed by <code>apt full-upgrade -y</code> (PVE 9) or <code>apt dist-upgrade -y</code> (PVE 8), both launched non-interactively with <code>--force-confdef --force-confold</code> so any configuration files you customised stay yours.",
"<strong>Installs essential packages</strong> if they are missing: <code>zfsutils-linux</code>, <code>proxmox-backup-restore-image</code>, <code>chrony</code>.",
"<strong>LVM metadata sanity check.</strong> Looks for VMs with disk passthrough that may have scribbled stale physical-volume headers onto raw disks; warns if anything is off (no automatic fix).",
"<strong>Cleans up afterwards:</strong> <code>apt-get autoremove -y</code> + <code>apt-get autoclean -y</code>, then prompts for a reboot if the kernel was updated or <code>/var/run/reboot-required</code> is present."
],
"shortTitle": "In short",
"shortBody": "The option runs the exact <code>apt update && apt full-upgrade -y</code> Proxmox recommends, wraps it with the repo hygiene and post-upgrade cleanup that the official guide also tells you to do, and prompts for the reboot at the end. See <link>Proxmox System Update</link> — the same updater is also available as a standalone utility in the main menu, with the full process diagram.",
"subTitle": "Don't apply to a subscribed host",
"subBody": "If you actually have a Proxmox subscription and want to keep using the enterprise repositories, skip this option. Re-running it would disable the enterprise repo and route you to the community channel. You can restore enterprise repos from the Uninstall menu if you change your mind later.",
"safetyTitle": "Post-update safety check",
"safetyBody": "After the upgrade, the script checks for disks with stale PV (Physical Volume) metadata — an edge case that can happen when a VM with disk passthrough scribbles LVM headers onto a raw disk. If anything suspicious is found you'll see a warning suggesting <code>pvs</code> to inspect. No action is taken automatically."
},
"time": {
"heading": "Synchronize time automatically",
"intro": "Detects the server's public IP via <code>dig myip.opendns.com @resolver1.opendns.com</code>, then queries <code>ipapi.co/'{'ip'}'/timezone</code> to look up the matching IANA timezone, and applies it with <code>timedatectl set-timezone</code>. Finally enables NTP with <code>timedatectl set-ntp true</code>.",
"depTitle": "Depends on two external services",
"depBody": "The lookup relies on OpenDNS and <code>ipapi.co</code> being reachable, and on their responses being correct. If you run Proxmox behind a VPN or on a VLAN that egresses from a different region, the auto-detected timezone may be wrong. In that case skip this option and set the timezone by hand:",
"revertTitle": "Reversible from the Uninstall menu",
"revertBody": "<link>Uninstall Optimizations</link> resets the timezone to UTC (a safe default). It does not disable NTP — your clock keeps syncing, just anchored to UTC until you set a new timezone manually."
},
"languages": {
"heading": "Skip downloading additional languages",
"intro": "On every <code>apt update</code>, Debian by default pulls translation files for every locale it ships — a lot of traffic and disk space for something you'll rarely see. This option tells APT to only fetch the main metadata. Before disabling, ProxMenux <strong>makes sure the host's own locale is actually generated</strong> (reads <code>/etc/default/locale</code> or <code>/etc/environment</code>, appends to <code>/etc/locale.gen</code> if missing, and runs <code>locale-gen</code>). So you don't lose your shell locale as a side effect.",
"writtenTitle": "What gets written",
"revertTitle": "Reversible from the Uninstall menu",
"revertBody": "Deleting <code>/etc/apt/apt.conf.d/99-disable-translations</code> (either manually or from the Uninstall menu) restores the default behaviour and APT downloads language files again."
},
"utilities": {
"heading": "Install common system utilities",
"intro": "Opens a checklist with <strong>25 curated utilities</strong> organised into groups. Pick the ones you want, confirm, and ProxMenux installs each via <code>apt</code>, verifying the package worked and showing a summary at the end.",
"imageAlt": "Checklist dialog showing the list of ProxMenux system utilities with space to select and enter to confirm",
"reuseTitle": "Same list is reused elsewhere",
"reuseBody": "The 25-utility catalogue lives in a single source of truth (<code>PROXMENUX_UTILS</code> in <code>scripts/global/utils-install-functions.sh</code>). The <em>Utilities and Tools → System Utilities</em> menu on the main ProxMenux menu exposes the same list, so you can come back later and install more without re-running post-install.",
"listTitle": "What's in the list",
"groups": [
{
"group": "System monitors",
"items": [
{
"pkg": "htop",
"desc": "Interactive process viewer"
},
{
"pkg": "btop",
"desc": "Modern resource monitor (CPU, RAM, disks, net, processes)"
},
{
"pkg": "s-tui",
"desc": "Terminal-based CPU stress & monitoring UI"
},
{
"pkg": "iftop",
"desc": "Live per-connection bandwidth usage"
},
{
"pkg": "iotop",
"desc": "Per-process disk I/O"
},
{
"pkg": "iptraf-ng",
"desc": "Interactive IP LAN monitor"
}
]
},
{
"group": "Network",
"items": [
{
"pkg": "iperf3",
"desc": "Measure maximum achievable bandwidth between hosts"
},
{
"pkg": "net-tools",
"desc": "Legacy tools (ifconfig, netstat, route). Still handy for quick checks."
},
{
"pkg": "ipset",
"desc": "Manage large IP sets in the kernel — useful with iptables/nftables rules."
}
]
},
{
"group": "Download and archive",
"items": [
{
"pkg": "axel",
"desc": "Lightweight parallel download accelerator"
},
{
"pkg": "aria2",
"desc": "Multi-source / multi-protocol downloader (HTTP, FTP, BitTorrent, Metalink)"
},
{
"pkg": "unzip",
"desc": "Extract ZIP archives"
},
{
"pkg": "zip",
"desc": "Create ZIP archives"
},
{
"pkg": "cabextract",
"desc": "Extract Microsoft CAB archives (handy when working with Windows ISOs)"
},
{
"pkg": "wimtools",
"desc": "Manipulate Windows WIM images (extract, split, mount, apply)"
},
{
"pkg": "genisoimage",
"desc": "Build ISO 9660 images from a directory tree"
}
]
},
{
"group": "Text and files",
"items": [
{
"pkg": "dos2unix",
"desc": "Convert CRLF (Windows) to LF (Unix) line endings"
},
{
"pkg": "grc",
"desc": "Generic colouriser — wraps ping, traceroute, dig, tail, etc. with syntax highlighting"
},
{
"pkg": "plocate",
"desc": "Fast file search (indexed). Run `updatedb` after install to build the index."
}
]
},
{
"group": "Remote and sessions",
"items": [
{
"pkg": "sshpass",
"desc": "Non-interactive SSH password auth — useful for scripts, not for daily use"
},
{
"pkg": "tmux",
"desc": "Terminal multiplexer — detach sessions, split panes, survive disconnects"
}
]
},
{
"group": "Hardware and low-level",
"items": [
{
"pkg": "msr-tools",
"desc": "Read/write CPU model-specific registers (rdmsr, wrmsr)"
},
{
"pkg": "intel-gpu-tools",
"desc": "Intel GPU diagnostic utilities including `intel_gpu_top`"
}
]
},
{
"group": "Virtualization",
"items": [
{
"pkg": "libguestfs-tools",
"desc": "Inspect and modify VM disk images (virt-ls, virt-cat, guestmount…)"
},
{
"pkg": "chntpw",
"desc": "Edit Windows SAM — useful for password recovery on Windows VMs you inherit"
}
]
}
],
"actionTitle": "A few of them in action",
"noBulkTitle": "No bulk uninstall for utilities",
"noBulkBody": "The Uninstall Optimizations menu does <strong>not</strong> track which utilities you installed — only whether the \"apt languages\", \"time sync\" and \"apt upgrade\" options were applied. To remove a specific utility later, uninstall it by hand:"
},
"related": {
"heading": "Related",
"items": [
{
"label": "Proxmox System Update",
"href": "/docs/utils/system-update",
"tail": " — re-runs the apt update + dist-upgrade cycle on demand."
},
{
"label": "System Utilities Installer",
"href": "/docs/utils/system-utils",
"tail": " — install (or re-install) utilities individually after post-install."
},
{
"label": "Updates and Packages commands",
"href": "/docs/help-info/update-commands",
"tail": " — apt reference."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,106 @@
{
"meta": {
"title": "Customizable Post-Install Script | ProxMenux Documentation",
"description": "Cherry-pick exactly which optimizations to apply to a Proxmox VE host with ProxMenux. 10 categories, ~30 individual tools, checklist UI. Includes everything the Automated script does, plus opt-in features (IOMMU, Fastfetch, Figurine, Ceph, HA, AMD fixes…).",
"ogTitle": "Customizable Post-Install Script | ProxMenux Documentation",
"ogDescription": "10 categories, ~30 individual optimizations. Pick exactly what you want on a Proxmox VE host. Fully reversible."
},
"header": {
"title": "Customizable Post-Install Script",
"description": "Cherry-pick exactly which optimizations to apply to a Proxmox VE host. ProxMenux groups ~30 individual tools into 10 categories, each with its own checklist dialog. Same engine as Automated, but with full control over what gets applied.",
"section": "Post-Install · Customizable"
},
"intro": {
"title": "When to pick Customizable",
"body": "Choose this path when you already know which tweaks you want on the host — or which you definitely do not want. The script presents a checklist per category so you can pre-select, deselect or mix-and-match optimizations. Every item can be applied again later (it is idempotent) or reverted from <link>Uninstall Optimizations</link>."
},
"compare": {
"heading": "How it compares to Automated",
"body": "Customizable is a superset of the <link>Automated script</link>. It covers the same 13 baseline optimizations plus a long list of opt-in ones that Automated intentionally skips — things that are useful only on specific hardware (AMD fixes), specific hosting (OVH RTM), or specific workloads (IOMMU/VFIO, Ceph repo, High Availability, Fastfetch, Figurine, ZFS ARC tuning, pigz, ZFS auto-snapshot, vzdump speed limits, Open vSwitch, TCP BBR…)."
},
"categoriesSection": {
"heading": "The 10 categories",
"body": "The Customizable script groups optimizations into 10 categories. Each category has its own checklist dialog and its own documentation page — open one of the cards below for the per-option rationale, defaults and verification steps."
},
"categories": [
{
"name": "Basic Settings",
"description": "Repositories, system upgrade, timezone, locale, common utilities."
},
{
"name": "System",
"description": "Journald, logrotate, kernel limits, memory tuning, kernel panic, fast reboots."
},
{
"name": "Virtualization",
"description": "Guest agent auto-install, IOMMU/VFIO enablement for PCI passthrough."
},
{
"name": "Network",
"description": "APT over IPv4, network sysctl tuning, Open vSwitch, TCP BBR, persistent interface names."
},
{
"name": "Storage",
"description": "ZFS ARC sizing, ZFS auto-snapshot, vzdump backup speed limits."
},
{
"name": "Security",
"description": "Disable portmapper/rpcbind to reduce the attack surface."
},
{
"name": "Customization",
"description": "Bashrc colors & aliases, MOTD banner, subscription-notice removal."
},
{
"name": "Monitoring",
"description": "OVH Real-Time Monitoring (only on detected OVH servers)."
},
{
"name": "Performance",
"description": "Parallel gzip (pigz) for faster compression in backups and transfers."
},
{
"name": "Optional",
"description": "AMD CPU fixes, Fastfetch, Figurine, Ceph repo, High Availability, Log2RAM."
}
],
"mixTip": {
"title": "Mix Automated and Customizable",
"body": "A common pattern: run <strong>Automated</strong> first to lock in the sensible baseline, then open <strong>Customizable</strong> and pick only the opt-in tools you care about (for example, IOMMU on a host that will do GPU passthrough). Changes are tracked independently; the Uninstall menu shows everything you have applied regardless of which path added it."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Automated Post-Install",
"href": "/docs/post-install/automated",
"tail": " — sane defaults applied with zero prompts."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — back any selection out cleanly."
},
{
"label": "Basic Settings",
"href": "/docs/post-install/basic-settings",
"tail": " — repos, time, language, utilities."
},
{
"label": "Virtualization",
"href": "/docs/post-install/virtualization",
"tail": " — IOMMU + VFIO for passthrough."
},
{
"label": "Security",
"href": "/docs/post-install/security",
"tailRich": " · <storageLink>Storage</storageLink> · <networkLink>Network</networkLink> · <customLink>Customization</customLink> — other categories."
},
{
"label": "Post-Install overview",
"href": "/docs/post-install",
"tail": "."
}
]
}
}
@@ -0,0 +1,74 @@
{
"meta": {
"title": "Post-Install: Customization | ProxMenux Documentation",
"description": "Customization options in the ProxMenux Customizable post-install script: a colored bash prompt with useful aliases, a ProxMenux banner in the MOTD, and the option to remove the Proxmox subscription nag from the web interface."
},
"header": {
"title": "Post-Install: Customization",
"description": "Cosmetic and quality-of-life tweaks for the Proxmox host. None of them change functional behaviour — they just make the shell nicer to use and hide the subscription nag in the web UI. All three are tracked and reversible from the Uninstall menu.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Three small, independent options: a <strong>colored bash prompt + aliases</strong> for the root shell, a one-line <strong>MOTD banner</strong> visible on SSH login, and removal of the <strong>\"No valid subscription\" popup</strong> that Proxmox shows on every login to the web UI."
},
"bashrc": {
"heading": "Customize bashrc",
"intro": "Injects a curated block into <code>/root/.bashrc</code> with a colored prompt, timestamped history, standard <code>ls</code> / <code>grep</code> aliases, and a <code>source</code> for bash completion. Makes working over SSH noticeably more pleasant and makes it obvious which host you're on when you have many tabs open.",
"writesTitle": "What ProxMenux adds to .bashrc",
"writesOutro": "The block is delimited by the <code>PMX_CORE_BASHRC</code> markers. Running the script again replaces the previous block instead of duplicating it. The original <code>.bashrc</code> is backed up once to <code>/root/.bashrc.bak</code>, and a <code>source /root/.bashrc</code> line is appended to <code>/root/.bash_profile</code> so the prompt also applies on login shells (e.g. after <code>su -</code>).",
"rootTitle": "Applies to root only",
"rootBody": "The customization targets the root account's shell. Other users you create on the host keep their own defaults. If you administer Proxmox exclusively over the web UI and never use the shell, this option is pure aesthetics and you can skip it."
},
"motd": {
"heading": "Set up custom MOTD banner",
"intro": "Prepends <em>\"This system is optimised by: ProxMenux\"</em> to <code>/etc/motd</code>, the message shown after a successful SSH login (above the shell prompt, before any <code>update-motd</code> scripts run). Harmless and purely informational — useful as a quick visual confirmation that ProxMenux has been applied on this host.",
"writesTitle": "What ProxMenux writes",
"writesOutro": "Original <code>/etc/motd</code> is backed up to <code>/etc/motd.bak</code> on first apply. The operation is idempotent: if the marker line is already present, nothing is added."
},
"banner": {
"heading": "Remove subscription banner",
"intro": "Removes the <em>\"You do not have a valid subscription for this server\"</em> modal that pops up every time someone logs into the Proxmox web UI without an enterprise subscription. The patch is version-aware: different Proxmox major versions have different UI bundles, so ProxMenux dispatches to the right script.",
"versionTitle": "Version-aware dispatch",
"versionItems": [
"<strong>PVE 9.x</strong> → runs <code>remove-banner-pve-v3.sh</code> (patches both the desktop <code>proxmoxlib.js</code> and the new Yew-based mobile UI).",
"<strong>PVE 8.x</strong> → runs <code>remove-banner-pve8.sh</code> (desktop-only)."
],
"versionOutro": "Before patching, ProxMenux backs up the original JS/template files to <code>/usr/local/share/proxmenux/backups/</code> with a timestamp. The Uninstall flow uses those backups to restore the original files, and falls back to reinstalling the Proxmox UI packages if the backup is missing or corrupt.",
"breakTitle": "Can break after Proxmox updates",
"breakBody": "Proxmox regularly ships UI updates that overwrite <code>proxmoxlib.js</code>. When that happens, the banner comes back. You can re-apply this option after every Proxmox update to re-patch the file, or just accept the nag until you reapply. ProxMenux also installs an APT hook that auto-re-patches on package upgrades — see <link>Uninstall Optimizations</link> for how that hook is reversed.",
"legalTitle": "Legal note (always worth repeating)",
"legalBody": "This option only hides the UI nag. It does <strong>not</strong> grant you enterprise support, access to the enterprise repository, or any rights to ship Proxmox commercially without a subscription. If you run Proxmox in a revenue-generating environment, buy a subscription — it supports the project and gets you the stable enterprise channel."
},
"verify": {
"heading": "Verification",
"intro": "After applying all three:",
"reversibleTitle": "All three are reversible",
"reversibleBody": "<link>Uninstall Optimizations</link> restores <code>/root/.bashrc</code> and <code>/etc/motd</code> from their <code>.bak</code> backups, and either restores the patched UI files from the backup directory or reinstalls <code>pve-manager</code>, <code>proxmox-widget-toolkit</code>, <code>libjs-extjs</code> and <code>libpve-http-server-perl</code> with <code>--force-confnew</code> to bring the web UI back to vanilla."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Optional",
"href": "/docs/post-install/optional",
"tail": " — Fastfetch and Figurine (other visual customizations)."
},
{
"label": "Show Version Information",
"href": "/docs/settings/show-version-information",
"tail": " — confirms the customizations are tracked as installed."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — revert bashrc, motd, subscription nag."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,106 @@
{
"meta": {
"title": "Proxmox VE Post-Install Script — Automated and Customizable | ProxMenux",
"description": "Overview of the ProxMenux Post-Install scripts for Proxmox VE. Run the Automated script for sane defaults with zero prompts, the Customizable script to pick exactly what you want across 10 categories (system, virtualization, network, storage, security, performance, optional), or fully reverse any change with the Uninstall Optimizations option.",
"ogTitle": "Proxmox VE Post-Install Script — Automated and Customizable",
"ogDescription": "Apply common Proxmox VE post-install optimizations across 10 categories — automated or à la carte, with reversible options.",
"twitterTitle": "Proxmox VE Post-Install Script | ProxMenux",
"twitterDescription": "Automated and customizable post-install optimizations for Proxmox VE — with reversible options."
},
"header": {
"title": "Post-Install Scripts",
"description": "Configure a fresh Proxmox VE host with ProxMenux's post-install optimizations. Three paths: run everything automatically, cherry-pick what you want, or reverse any change. All changes are tracked.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this menu is for",
"body": "Right after installing Proxmox VE, there are dozens of small changes that make the host faster and easier to maintain — free repositories, sane journald limits, sensible TCP buffers, SSD-friendly log storage, bashrc niceties, and more. ProxMenux automates all of them, tracks what it changed, and lets you revert."
},
"openingMenu": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, select <strong>Settings post-install Proxmox</strong>. You will see this:",
"imageAlt": "Post-Installation Scripts menu with 3 ProxMenux options (Automated / Customizable / Uninstall) followed by the Community Scripts section"
},
"threeWays": {
"heading": "Three ways to apply optimizations",
"body": "The three ProxMenux entries share the same underlying code and the same registry of installed tools — they just give you different levels of control. Pick the one that matches how much you want to decide."
},
"routes": [
{
"title": "Automated",
"description": "A curated set of 13 safe, always-useful optimizations applied in sequence with zero prompts. Good default for most users.",
"bullets": [
"Free repos + system upgrade",
"Memory, kernel, network tuning",
"Log2RAM (auto-detected on SSD/NVMe)",
"Journald + logrotate size limits",
"Persistent interface names"
]
},
{
"title": "Customizable",
"description": "~30 individual optimizations across 10 categories. You pick exactly which ones to apply. Same engine as Automated, but with full control.",
"bullets": [
"Checklist UI per category",
"Includes everything Automated does, plus opt-in items (IOMMU, Fastfetch, Figurine, Ceph, HA, AMD fixes…)",
"Run as many times as you want — changes are idempotent"
]
},
{
"title": "Apply Available Updates",
"description": "When a post-install optimization (Log2Ram, Memory Settings, Logrotate…) gets a newer version on disk than what is registered on the host, this entry surfaces only the ones that moved. Re-runs the corresponding function and refreshes the registry — touches nothing else.",
"bullets": [
"Per-optimization opt-in (only what changed)",
"Same picker available from the Monitor dashboard",
"Single grouped notification when new updates land"
]
},
{
"title": "Uninstall Optimizations",
"description": "Every change made by either path is tracked in a JSON registry, and every optimization has a reverse function. Pick what to revert, and the host goes back.",
"bullets": [
"Detects previously applied optimizations automatically",
"Reversal restores original configs from backup files",
"Reboot prompt if needed (VFIO, persistent names, etc.)"
]
}
],
"whichTitle": "Which one should you pick?",
"whichBody": "If this is a fresh Proxmox install and you want the sensible baseline with no decisions: <autoLink><strong>Automated</strong></autoLink>. If you already know which tweaks you want (or which you definitely don't want): <customLink><strong>Customizable</strong></customLink>. If something you already applied has a newer version on disk and you want to lift only that: <updatesLink><strong>Apply Available Updates</strong></updatesLink>. If you applied something earlier and want to back it out cleanly: <uninstallLink><strong>Uninstall Optimizations</strong></uninstallLink>. You can mix them — apply Automated first, then open Customizable to add opt-ins like Fastfetch or IOMMU, and revert any individual item later.",
"mixing": {
"heading": "Mixing with other post-install scripts",
"stackTitle": "Don't stack multiple post-install scripts",
"stackBody": "Running several post-install scripts on the same host can cause duplicated configuration files, conflicting sysctl entries, or worse — broken networking after reboot. If you already applied the <strong>Helper-Scripts Post Install</strong>, some ProxMenux optimizations may overlap with what it already configured. Stick to one post-install tool per host.",
"xshokTitle": "xshok-proxmox: deprecated",
"xshokBody": "Earlier versions of ProxMenux referenced <a>xshok-proxmox</a> as a companion post-install tool. That project is now deprecated and no longer offered from ProxMenux. If a previous run of xshok-proxmox left markers on the host, ProxMenux still detects them and will warn you — but it is not something you should install alongside ProxMenux today."
},
"community": {
"heading": "Community scripts",
"body": "The menu also exposes two third-party scripts from the <a>community-scripts</a> project: <em>Proxmox VE Post Install</em> and <em>Proxmox VE Microcode</em>. These are wrappers that <code>wget | bash</code> the original authors' scripts. They are not maintained by ProxMenux. See <link>External Repositories</link> for details and trust considerations before running them."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Proxmox System Update",
"href": "/docs/utils/system-update",
"tail": " — keeps the host up to date once it's been post-installed."
},
{
"label": "Security",
"href": "/docs/security",
"tail": " — Fail2Ban + Lynis on top of the post-install hardening."
},
{
"label": "Show Version Information",
"href": "/docs/settings/show-version-information",
"tail": " — see which post-install components are tracked as installed."
},
{
"label": "Updates and Packages commands",
"href": "/docs/help-info/update-commands",
"tail": " — reference for apt / pveupgrade."
}
]
}
}
@@ -0,0 +1,58 @@
{
"meta": {
"title": "Post-Install: Monitoring | ProxMenux Documentation",
"description": "Monitoring options in the ProxMenux Customizable post-install script. Currently a single option: install OVH Real-Time Monitoring (RTM), which only activates if the host is detected as an OVH server."
},
"header": {
"title": "Post-Install: Monitoring",
"description": "Monitoring options inside the Customizable post-install script. This category is small and provider-specific — it installs the OVH Real-Time Monitoring agent on dedicated OVH servers and does nothing anywhere else.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "Narrow scope on purpose",
"body": "Post-install monitoring is limited to <strong>one provider-specific agent</strong>. General-purpose monitoring (Prometheus, Grafana, node_exporter) is out of scope here because those require architectural decisions (separate host or not, data retention, alerting targets) that don't fit a one-click post-install step. ProxMenux Monitor itself, bundled with ProxMenux, fills most of that role without needing any external agent."
},
"ovh": {
"heading": "Install OVH Real-Time Monitoring (RTM)",
"intro": "If your Proxmox host is a dedicated server rented from <a>OVHcloud</a>, you can enable RTM to expose hardware telemetry (CPU temperature, PSU status, disk SMART, RAID controller state, etc.) to the OVH control panel. This is the same agent OVH uses for their own \"Server Monitoring\" feature.",
"decisionsTitle": "How ProxMenux decides",
"decisionsItems": [
"Gets the host's public IP via <code>curl ipinfo.io/ip</code>.",
"Looks up the owning ISP with a <code>whois</code> query to <code>v4.whois.cymru.com</code>.",
"If the result mentions OVH, fetches <code>last-public-ovh-infra-yak.snap.mirrors.ovh.net/yak/archives/apply.sh</code> and pipes it to <code>bash</code> with the RTM v2 puppet manifest.",
"If the result does <em>not</em> mention OVH, nothing is installed. The option is a no-op."
],
"remoteTitle": "Remote script piped to bash",
"remoteBody": "The installation runs <code>wget -qO - https://…apply.sh | bash</code>. If the OVH mirror is ever compromised, the script executes as root on your host. Before enabling this option, decide whether you trust OVH's mirror chain more than the monitoring you gain. For most home-lab or non-OVH users this option should simply stay off.",
"noOpTitle": "Only enable if the host is actually at OVH",
"noOpBody": "The option is a no-op on non-OVH servers, so ticking it on a home-lab Proxmox doesn't break anything. But there is a cosmetic bug today: even on non-OVH servers the script prints <em>\"Server belongs to OVH\"</em> at the end, which can be misleading. See the troubleshooting note below.",
"runsTitle": "What ProxMenux runs",
"verifyTitle": "Verification",
"verifyBody": "On a real OVH host, after a reboot you should see the <a>RTM dashboard</a> in your OVH Manager populated with live data for the host. On the Proxmox side, the RTM collector is a systemd service — check it directly:",
"troubleTitle": "Troubleshooting",
"spuriousTitle": "\"Server belongs to OVH\" but I'm not on OVH",
"spuriousBody": "This is a known cosmetic quirk in the current script: the success message fires outside the OVH-detected conditional, so it prints on every run. If the RTM install did <em>not</em> actually happen (check <code>systemctl status ovh-rtm</code> — it will not exist), the message is spurious and can be ignored. Nothing was installed on your host.",
"revertTitle": "Not reversible from the Uninstall menu",
"revertBody": "There is no dedicated uninstall entry for RTM. On a real OVH host, remove the packages manually with <code>apt purge ovh-*</code> and delete any puppet manifests under <code>/etc/puppet/</code> that RTM installed. On a non-OVH host, nothing was ever installed, so there's nothing to revert."
},
"related": {
"heading": "Related",
"items": [
{
"label": "ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — local web dashboard for the host (works on any provider, not just OVH)."
},
{
"label": "Useful System Commands",
"href": "/docs/help-info/system-commands",
"tail": " — local-host monitoring reference."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,126 @@
{
"meta": {
"title": "Post-Install: Network | ProxMenux Documentation",
"description": "Network-related optimizations in the ProxMenux Customizable post-install script: force APT over IPv4, apply a curated sysctl tuning profile, install Open vSwitch, enable TCP BBR + Fast Open, and pin interface names to their MAC addresses."
},
"header": {
"title": "Post-Install: Network",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Five independent network options. Two are small (<strong>APT over IPv4</strong>, <strong>Open vSwitch install</strong>), two tune TCP behaviour (<strong>network sysctl profile</strong>, <strong>BBR + Fast Open</strong>), and one fixes a common operational headache — <strong>pinning interface names</strong> so a new NIC or a BIOS update doesn't rename <code>enp3s0</code> to <code>enp4s0</code> and break your bridges."
},
"ipv4": {
"heading": "Force APT to use IPv4",
"intro": "Writes <code>Acquire::ForceIPv4 \"true\";</code> to <code>/etc/apt/apt.conf.d/99-force-ipv4</code>. APT then refuses to use IPv6 for package downloads, even if the host has IPv6 connectivity.",
"tipTitle": "Who benefits",
"tipBody": "Useful when your IPv6 path is flaky, slower than IPv4, or the Debian/Proxmox mirror occasionally breaks over IPv6 (it happens). Harmless on hosts without IPv6. On a healthy dual-stack network, it's just a guarantee of predictable behaviour — apt won't surprise you with an IPv6 timeout."
},
"sysctl": {
"heading": "Apply network optimizations",
"intro": "Writes a curated sysctl profile to <code>/etc/sysctl.d/99-network.conf</code> covering core socket buffers, ICMP hardening, basic spoof protection, and TCP buffer sizes that make sense on a hypervisor with lots of concurrent flows.",
"tunedTitle": "What gets tuned",
"headerArea": "Area",
"headerSettings": "Key settings",
"rows": [
{
"area": "Core socket buffers",
"settings": "<code>netdev_max_backlog=8192</code>, <code>rmem_max=16M</code>, <code>wmem_max=16M</code>, <code>somaxconn=8192</code>"
},
{
"area": "ICMP hardening",
"settings": "<code>icmp_echo_ignore_broadcasts=1</code>, <code>icmp_ignore_bogus_error_responses=1</code>"
},
{
"area": "Routing safety",
"settings": "<code>accept_redirects=0</code>, <code>accept_source_route=0</code>, <code>secure_redirects=0</code>, <code>send_redirects=0</code>"
},
{
"area": "Reverse path filter",
"settings": "<code>rp_filter=2</code> (loose mode, see note below)"
},
{
"area": "TCP",
"settings": "<code>tcp_mtu_probing=1</code>, <code>tcp_rfc1337=1</code>, <code>tcp_sack=1</code>, <code>tcp_rmem=8K/87K/16M</code>, <code>tcp_wmem=8K/64K/16M</code>"
},
{
"area": "Ports",
"settings": "<code>ip_local_port_range=1024 65535</code> (ephemeral port pool)"
},
{
"area": "Unix sockets",
"settings": "<code>net.unix.max_dgram_qlen=4096</code>"
}
],
"sourceOutro": "It also adds <code>source /etc/network/interfaces.d/*</code> to <code>/etc/network/interfaces</code> if not already present — standard practice so you can drop modular interface snippets without editing the main file.",
"rpFilterTitle": "Why rp_filter=2 (loose) instead of 1 (strict)",
"rpFilterBody": "Strict reverse-path filtering drops packets whose source would be routed out a <em>different</em> interface. That's the right default on a client machine, but breaks badly on a Proxmox host where VM traffic often arrives on a bridge and leaves on an uplink with asymmetric routes. <code>rp_filter=2</code> (loose) only drops packets with truly unroutable sources. It's a pragmatic trade-off — slight reduction in local-IP-spoof detection in exchange for not breaking your VM network."
},
"ovs": {
"heading": "Install Open vSwitch",
"intro": "Installs <code>openvswitch-switch</code> + <code>openvswitch-common</code>. These packages add OVS as a bridge implementation alternative to the standard Linux bridges that Proxmox uses by default. The install alone doesn't change any networking — existing <code>vmbrX</code> bridges keep working. OVS becomes available in the Proxmox UI when you <em>create</em> a new bridge and pick it from the type dropdown.",
"tipTitle": "When OVS makes sense",
"tipBody": "Consider OVS if you need <strong>VLAN trunking with non-contiguous VLAN IDs</strong>, <strong>LACP with LLDP on specific modes</strong>, <strong>fine-grained flow programming</strong> (OpenFlow), or interoperation with SDN controllers. For a home lab with a couple of VLANs and a single LACP uplink, standard Linux bridges + <code>vmbrX.VID</code> are simpler and perfectly fine.",
"revertTitle": "Not reversible from the Uninstall menu",
"revertBody": "Installing OVS is not tracked in Uninstall Optimizations. If you decide you don't want it, remove it manually — but only after migrating any bridges back to Linux bridges first:"
},
"bbr": {
"heading": "Enable TCP BBR + TCP Fast Open",
"intro": "Writes two sysctl files and reloads them. BBR replaces the default CUBIC congestion control with Google's bandwidth-based algorithm, which handles long-fat pipes and lossy links much better. TCP Fast Open (TFO) eliminates a round trip on repeat TCP connections by piggy-backing data on the SYN.",
"verifyTitle": "Verification",
"impactTitle": "Impact is workload-dependent",
"impactBody": "BBR shines on high-latency or lossy links (cross-continent replication, VPN tunnels, mobile clients). On a LAN between two machines on the same switch, the difference is often within noise. TFO helps short, repeated HTTP connections the most.",
"revertTitle": "Not reversible from the Uninstall menu",
"revertBody": "BBR/TFO aren't tracked. To revert, remove the two sysctl files and reload:"
},
"names": {
"heading": "Interface Names (persistent)",
"intro": "Iterates over every physical NIC the host has (skipping loopback, Docker veths, bridges, TAP devices, bonds, Cilium, ZeroTier, WireGuard) and writes a systemd <code>.link</code> file binding the current interface name to the current MAC address. The kernel's naming logic can then no longer rename that NIC — the MAC wins.",
"whyTitle": "Why this matters",
"whyItems": [
"Adding or removing PCIe devices can shift the bus numbering, turning <code>enp3s0</code> into <code>enp4s0</code>. If your <code>/etc/network/interfaces</code> references the old name, the bridge vanishes on reboot.",
"BIOS / firmware updates sometimes change how devices enumerate, with the same effect.",
"LXC containers with <code>hotplug</code> NICs and bonded links can race on boot and end up named inconsistently. Pinning fixes that."
],
"writtenTitle": "What gets written",
"writtenIntro": "One file per physical NIC, at <code>/etc/systemd/network/10-&lt;iface&gt;.link</code>:",
"writtenOutro": "Any pre-existing <code>.link</code> files in that directory are copied to <code>/etc/systemd/network/backup-&lt;timestamp&gt;/</code> before touching anything.",
"pveTitle": "PVE 9 vs PVE 8",
"pveBody": "On Proxmox VE 9 (<code>systemd-networkd</code> native), the script reloads udev rules after writing the <code>.link</code> files so new hotplug NICs pick up the correct name without a reboot. On PVE 8 (<code>ifupdown2</code>), interface naming is resolved at boot anyway — a reboot is required for the changes to take effect. The script sets the reboot flag either way so Customizable prompts you.",
"reviewTitle": "Review existing /etc/network/interfaces first",
"reviewBody": "If your host has legacy configuration in <code>/etc/network/interfaces</code> that references NIC names generated by the kernel's default scheme, pinning <em>today's</em> names is exactly what you want. But if you've already manually customised the config around specific names, double-check the pinning matches what the interfaces file expects before rebooting.",
"revertTitle": "Reversible from the Uninstall menu",
"revertBody": "<link>Uninstall Optimizations</link> deletes every <code>.link</code> file from <code>/etc/systemd/network/</code>, restoring the kernel's default naming on next reboot. The timestamped backup of the original files stays behind in case you need to restore specific ones manually."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Network Management",
"href": "/docs/network",
"tail": " — diagnostics, bridge analysis, guided repairs."
},
{
"label": "Persistent interface names",
"href": "/docs/network/persistent-names",
"tail": " — same idea exposed as its own menu later (use either, not both)."
},
{
"label": "Network commands reference",
"href": "/docs/help-info/network-commands",
"tail": " — ip, ss, ethtool, sysctl."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — revert any of these network changes."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,143 @@
{
"meta": {
"title": "ProxMenux Post-Install: Optional Settings",
"description": "Guide to Optional Settings in the ProxMenux post-install script for additional Proxmox VE features and optimizations.",
"ogTitle": "ProxMenux Post-Install: Optional Settings",
"ogDescription": "Guide to Optional Settings in the ProxMenux post-install script for additional Proxmox VE features and optimizations.",
"ogImageAlt": "ProxMenux Post-Install Optional Settings"
},
"title": "Optional Settings",
"intro": "The <strong>Optional Settings</strong> category provides additional features and optimizations that you can choose to apply to your Proxmox VE installation. These settings are not essential but can enhance your system's capabilities in specific scenarios.",
"available": "Available Optional Features",
"ceph": {
"title": "Add Latest Ceph Support",
"intro": "This option installs the latest Ceph storage system support for Proxmox VE. Ceph is a distributed storage system that provides high performance, reliability, and scalability.",
"doesIntro": "What it does:",
"doesItems": [
"Adds the Ceph repository to your system",
"Updates package lists",
"Installs Ceph packages using the 'pveceph install' command",
"Verifies the installation"
],
"howUse": "How to use: After installation, you can configure and manage Ceph storage using the Proxmox VE web interface or command-line tools.",
"automates": "This adjustment automates the following commands:"
},
"amd": {
"title": "Apply AMD CPU Fixes",
"intro": "This option applies specific fixes for AMD EPYC and Ryzen CPUs to improve stability and compatibility.",
"doesIntro": "What it does:",
"doesItems": [
"Detects if an AMD EPYC or Ryzen CPU is present",
"Applies kernel parameter 'idle=nomwait' to prevent random crashes",
"Configures KVM to ignore certain MSRs (Model Specific Registers) for better Windows guest compatibility",
"Installs the latest Proxmox VE kernel"
],
"howUse": "How to use: These fixes are applied automatically and require a system reboot to take effect.",
"automates": "This adjustment automates the following commands:"
},
"ha": {
"title": "Enable High Availability Services",
"intro": "This option enables High Availability (HA) services in Proxmox VE, allowing for automatic failover of VMs and containers in case of node failure.",
"doesIntro": "What it does:",
"doesItems": [
"Enables and starts the pve-ha-lrm (Local Resource Manager) service",
"Enables and starts the pve-ha-crm (Cluster Resource Manager) service",
"Enables and starts the corosync service for cluster communication"
],
"howUse": "How to use: After enabling these services, you can configure HA groups and resources in the Proxmox VE web interface.",
"automates": "This adjustment automates the following commands:"
},
"testing": {
"title": "Enable Proxmox Testing Repository",
"intro": "This option enables the Proxmox testing repository, allowing access to the latest, potentially unstable versions of Proxmox VE packages.",
"doesIntro": "What it does:",
"doesItems": [
"Adds the Proxmox testing repository to the system's package sources",
"Creates a new file in /etc/apt/sources.list.d/ for the testing repository",
"Updates the package lists to include packages from the new repository"
],
"howUse": "How to use: After enabling this repository, you can update and upgrade your system to get the latest testing versions of Proxmox VE packages. Use with caution as these versions may be unstable.",
"manualIntro": "To manually add the Proxmox testing repository, you can use these commands:",
"noteLabel": "Note:",
"noteBody": "$(lsb_release -cs) automatically detects your Proxmox VE version codename (e.g., bullseye).",
"warnLabel": "Warning:",
"warnBody": "Enabling the testing repository may lead to system instability. It's recommended for testing environments only."
},
"fastfetch": {
"title": "Install and Configure Fastfetch",
"intro": "This option silently installs and configures Fastfetch, a system information tool that displays system specs and a custom logo at login.",
"doesLabel": "What it does:",
"doesItems": [
"Silently downloads and installs the latest version of Fastfetch",
"Allows you to choose a custom logo (<strong>ProxMenux, Proxmox, Helper-Scripts, Home-Labs-Club, Proxmology</strong>, or a custom one)",
"Configures Fastfetch to display <em>\"System optimised by ProxMenux\"</em>",
"Sets up Fastfetch to run automatically at console login"
],
"importantLabel": "Important:",
"importantBody": "If you connect to Proxmox via SSH, you should select the <strong>Proxmox</strong> logo or create a custom one using <code>jp2a</code> or <code>img2txt</code>. The other logos are generated using <code>chafa</code> and may not display correctly in a standard SSH session.",
"customLabel": "Custom Logos:",
"customBody1": "To use a custom logo, place your ASCII art text file in: <code>/usr/local/share/fastfetch/logos/</code>",
"customBody2": "You can create custom logos using tools like <code>chafa</code>, <code>jp2a</code>, or <code>img2txt</code>.",
"customBody3": "For best results:",
"customItems": [
"Keep the logo height to 35 lines or less to maintain proportions and fit in the terminal",
"Use <code>chafa</code> for color logos (may not display correctly in SSH sessions)",
"Use <code>jp2a</code> or <code>img2txt</code> for SSH-compatible logos"
],
"examplesLabel": "Example Logos:",
"logos": [
{
"name": "ProxMenux",
"alt": "ProxMenux Logo",
"src": "https://macrimi.github.io/ProxMenux/fastfetch/proxmenux.png"
},
{
"name": "Proxmox",
"alt": "Proxmox Logo",
"src": "https://macrimi.github.io/ProxMenux/fastfetch/proxmox.png"
},
{
"name": "JC Channel",
"alt": "JC Channel Logo",
"src": "/fastfetch/jc-channel.png"
},
{
"name": "Helper-Scripts",
"alt": "Helper-Scripts Logo",
"src": "https://macrimi.github.io/ProxMenux/fastfetch/helper-scripts.png"
},
{
"name": "Home-Labs-Club",
"alt": "Home-Labs-Club Logo",
"src": "https://macrimi.github.io/ProxMenux/fastfetch/home-labs-club.png"
},
{
"name": "Proxmology",
"alt": "Proxmology Logo",
"src": "https://macrimi.github.io/ProxMenux/fastfetch/proxmology.png"
}
],
"automates": "This adjustment automates the following commands:"
},
"figurine": {
"title": "Install and Configure Figurine",
"intro": "This option installs and configures Figurine, a tool that creates stylish ASCII text banners for your terminal, displaying your hostname in a visually appealing 3D format.",
"doesLabel": "What it does:",
"doesItems": [
"Downloads and installs Figurine v2.0.0 from GitHub",
"Creates a welcome message that displays your hostname in 3D ASCII art when you log in",
"Automatically removes any previous Figurine installation if present",
"Sets up the welcome message to run automatically at login"
],
"practicalLabel": "Practical Use:",
"practicalBody": "When managing multiple Proxmox nodes in a cluster, Figurine provides an immediate visual indication of which node you're currently logged into. This helps prevent accidental commands on the wrong node and improves your workflow when managing multiple servers.",
"exampleLabel": "Example Output:",
"imageAlt": "Figurine Example Output",
"automates": "This adjustment automates the following process:",
"outro": "After installation, you'll see your hostname displayed in 3D ASCII art each time you log in, making it immediately clear which Proxmox node you're working on."
},
"autoApplication": {
"title": "Automatic Application",
"body": "These optional features are applied only when specifically selected during the post-install process. Each feature can be individually chosen based on your specific needs and preferences."
}
}
@@ -0,0 +1,60 @@
{
"meta": {
"title": "Post-Install: Performance | ProxMenux Documentation",
"description": "Performance options in the ProxMenux Customizable post-install script. Replaces single-threaded gzip with pigz (parallel gzip) for faster backups and compression on multi-core hosts."
},
"header": {
"title": "Post-Install: Performance",
"description": "Performance options inside the Customizable post-install script. Currently this category contains a single optimization: replacing gzip with pigz so backups and compression use every CPU core instead of one.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "The only performance option here rewires the system's gzip to a parallel implementation. Other performance-related tweaks (memory tuning, I/O scheduling, ZFS ARC sizing, kernel limits) live under their own categories (<em>System</em>, <em>Storage</em>) because they affect different subsystems."
},
"pigz": {
"heading": "Use pigz for faster gzip compression",
"intro": "Standard <code>gzip</code> compresses data using a <strong>single CPU core</strong>. On modern Proxmox hosts with 8, 16 or 32 cores, that is a huge bottleneck during <code>vzdump</code> VM/CT backups, log rotation, and anything else that pipes through <code>gzip</code>. <a>pigz</a> is a drop-in parallel replacement: same gzip-compatible output, but it spreads the work across every core.",
"doesTitle": "What ProxMenux does",
"doesIntro": "Four steps, all idempotent:",
"doesItems": [
"Sets <code>pigz: 1</code> in <code>/etc/vzdump.conf</code> so Proxmox's backup tool uses pigz natively.",
"Installs the <code>pigz</code> apt package if not already present.",
"Writes a wrapper script at <code>/bin/pigzwrapper</code> that forwards every argument to <code>/usr/bin/pigz</code>.",
"Moves the original <code>/bin/gzip</code> aside to <code>/bin/gzip.original</code> and replaces <code>/bin/gzip</code> with the wrapper. From now on, <em>anything</em> that calls <code>gzip</code> — logrotate, <code>tar czf</code>, scripts, vzdump — uses pigz transparently."
],
"replacesTitle": "This replaces a system binary",
"replacesBody": "Replacing <code>/bin/gzip</code> with a wrapper is unusual. It is safe (the wrapper produces gzip-compatible output), but worth knowing: scripts that hardcode paths, run inside restrictive chroots, or verify binary hashes may behave differently. The original binary is preserved as <code>/bin/gzip.original</code> so you can always swap it back.",
"revertTitle": "Not reversible from the Uninstall menu",
"revertBody": "This optimization is applied by Customizable, but <strong>does not currently have a matching entry in the Uninstall Optimizations menu</strong>. To revert it by hand, restore the original gzip and clear the wrapper:",
"verifyTitle": "Verification",
"verifyBody": "After applying, <code>gzip --version</code> should mention pigz. A quick benchmark also shows the speed difference on a multi-core host:",
"whenTitle": "When this matters most",
"whenBody": "The impact scales with <strong>how many cores the host has</strong> and <strong>how often you run backups</strong>. On a 2-core home-lab box with one daily vzdump, the benefit is marginal. On a 16-core production host backing up a dozen VMs every night, pigz can cut the backup window to a fraction of what single-threaded gzip takes."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Backup and Restore commands",
"href": "/docs/help-info/backup-commands",
"tailRich": " — vzdump CLI reference, including <code>--pigz</code> threads option."
},
{
"label": "Storage",
"href": "/docs/post-install/storage",
"tail": " — vzdump speed limits and ZFS ARC tuning."
},
{
"label": "System",
"href": "/docs/post-install/system",
"tail": " — file-descriptor and memory tuning."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,57 @@
{
"meta": {
"title": "Post-Install: Security | ProxMenux Documentation",
"description": "Security options available in the ProxMenux Customizable post-install script. Currently a single option: disable the portmapper/rpcbind service to reduce the host's attack surface."
},
"header": {
"title": "Post-Install: Security",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Post-install security is limited to <strong>host hardening that is safe to apply unattended</strong> — things that disable services almost nobody needs and that can be undone from the Uninstall menu. Active security tooling (Fail2Ban for intrusion prevention, Lynis for auditing) lives under the dedicated <em>Security</em> entry on ProxMenux's main menu, not here in post-install."
},
"rpcbind": {
"heading": "Disable portmapper / rpcbind",
"intro": "<code>rpcbind</code> (formerly <code>portmap</code>) is a service that maps RPC program numbers to network ports. It is a dependency for NFS and some legacy RPC-based tools. On a typical Proxmox host that is not acting as an NFS server, <strong>nothing uses it</strong> — and leaving it enabled keeps port <code>111/tcp</code> listening on every interface.",
"whyTitle": "Why it's worth disabling",
"whyItems": [
"Reduces the host attack surface — one less listening service to worry about.",
"Historically abused as a reflection/amplification vector in DDoS attacks. Disabling <code>rpcbind</code> removes that amplification factor for your host.",
"Removes the noise it generates in logs and <code>netstat</code> / <code>ss</code> output, making real activity easier to spot."
],
"nfsTitle": "Don't disable this if you use NFS",
"nfsBody": "NFS server <strong>and</strong> NFS client rely on <code>rpcbind</code> to negotiate the ports used by <code>mountd</code>, <code>statd</code>, <code>lockd</code>, etc. If your Proxmox host either <em>exports</em> NFS shares to other machines or <em>mounts</em> NFS shares from a NAS, do not apply this option. Mounts will fail with <code>mount.nfs: rpc.statd is not running</code> or similar.",
"runsTitle": "What ProxMenux runs",
"runsOutro": "The package stays installed (so you or another tool can re-enable it later). The service unit is disabled so the service does not come back on reboot.",
"verifyTitle": "Verification",
"verifyBody": "After applying, confirm <code>rpcbind</code> is off and nothing is listening on port 111:",
"reversibleTitle": "Reversible from the Uninstall menu",
"reversibleBody": "This change is tracked. Open <link>Uninstall Optimizations</link> and pick <em>RPC Disable</em> to restore it. Nothing is purged from the system — just re-enable the service and it starts again."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Security menu",
"href": "/docs/security",
"tail": " — heavier hitters: Fail2Ban (intrusion prevention) and Lynis (audit)."
},
{
"label": "Lynis",
"href": "/docs/security/lynis",
"tail": " — audit the host to find more hardening opportunities."
},
{
"label": "Useful System Commands",
"href": "/docs/help-info/system-commands",
"tail": " — service status, journalctl, lynis audit reference."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,158 @@
{
"meta": {
"title": "Post-Install: Storage | ProxMenux Documentation",
"description": "Storage optimizations in the ProxMenux Customizable post-install script: ZFS ARC sizing based on host RAM, zfs-auto-snapshot for periodic snapshots, and vzdump backup speed limits removal."
},
"header": {
"title": "Post-Install: Storage",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Three storage-related optimizations: tune the <strong>ZFS ARC</strong> cache size to a sensible fraction of host RAM, install and schedule <strong>ZFS auto-snapshots</strong>, and remove throttles from <strong>vzdump</strong> so backups run at full speed. All three are independent — pick the ones that match your setup."
},
"notTrackedTitle": "None of these are in the Uninstall menu",
"notTrackedBody": "Unlike most post-install optimizations, the three Storage options are <strong>not currently tracked</strong> in the Uninstall Optimizations flow. If you apply them and later want to revert, you'll have to do it by hand. The manual rollback commands are shown below each section.",
"arc": {
"heading": "Optimize ZFS ARC size",
"intro": "The <strong>Adaptive Replacement Cache (ARC)</strong> is ZFS's in-memory read cache. Without explicit tuning, ZFS happily grabs up to half the host RAM for itself, which is excessive on a Proxmox host that also needs memory for VMs and LXCs. This option caps ARC to a sane fraction of total RAM based on the size of the machine.",
"sizingTitle": "Sizing rules",
"headerRam": "Host RAM",
"headerMin": "ARC min",
"headerMax": "ARC max",
"rows": [
{
"ram": "≤ 16 GB",
"min": "512 MB",
"max": "512 MB"
},
{
"ram": "17 32 GB",
"min": "1 GB",
"max": "1 GB"
},
{
"ram": "> 32 GB",
"min": "RAM / 16",
"max": "RAM / 8"
}
],
"after": "On a 64 GB host, that means 4 GB min / 8 GB max for ARC. The config is written to <code>/etc/modprobe.d/99-zfsarc.conf</code> and enables a few extra ZFS tunables (L2ARC prefetch on, L2ARC write max at 500 MB, longer TXG timeout).",
"rebootTitle": "Requires a reboot to take effect",
"rebootBody": "ARC settings are read when the <code>zfs</code> kernel module loads. They do <strong>not</strong> apply on a live system — you'll need to reboot the host for the cap to kick in. The script sets the \"reboot required\" flag automatically.",
"safeTitle": "Safe on non-ZFS hosts",
"safeBody": "The function checks for the <code>zfs</code> command before touching anything. On ext4 / LVM-only Proxmox hosts, ticking this option is a no-op — nothing gets written.",
"verifyTitle": "Verification and manual rollback"
},
"autoSnap": {
"heading": "Install ZFS auto-snapshot",
"intro": "Installs the <a>zfs-auto-snapshot</a> package and rewrites its cron schedules so snapshots are taken automatically at several intervals. A great no-effort safety net on top of your regular vzdump backups.",
"cadenceTitle": "Snapshot cadence ProxMenux configures",
"headerLabel": "Label",
"headerRuns": "Runs",
"headerKept": "Snapshots kept",
"rows": [
{
"label": "frequent",
"runs": "every 15 min",
"kept": "4"
},
{
"label": "hourly",
"runs": "every hour",
"kept": "1"
},
{
"label": "daily",
"runs": "once a day",
"kept": "1"
},
{
"label": "weekly",
"runs": "once a week",
"kept": "1"
},
{
"label": "monthly",
"runs": "once a month",
"kept": "1"
}
],
"conservativeTitle": "Conservative keep counts",
"conservativeBody": "ProxMenux ships with conservative retention (just 4 frequent + 1 of each longer interval) so ZFS snapshot storage doesn't balloon. If you want longer retention, edit the numbers in <code>/etc/cron.d/zfs-auto-snapshot</code>, <code>/etc/cron.hourly/zfs-auto-snapshot</code>, etc. after the script runs.",
"onlyZfsTitle": "Only useful on ZFS pools",
"onlyZfsBody": "Installing the package on an ext4-only host is harmless but pointless — there are no ZFS datasets for it to snapshot. Skip this option if you don't use ZFS.",
"verifyTitle": "Verification and manual rollback"
},
"autotrim": {
"heading": "Enable ZFS autotrim (SSD/NVMe pools)",
"intro": "Enables the <code>autotrim</code> property on every ZFS pool that is backed exclusively by SSDs or NVMe drives with TRIM support. Pools that include a single HDD vdev are skipped automatically — TRIM on rotational drives is meaningless and ZFS will refuse it. Pools that were already set to <code>autotrim=on</code> are left as they are.",
"trimTitle": "What TRIM does, and why it matters on ZFS",
"trimBody1": "SSDs / NVMe drives manage internal storage in fixed-size erase blocks that are much larger than the logical sectors the filesystem talks to. When a filesystem deletes a file, the drive doesn't know — it still thinks those sectors are in use, so its internal garbage collector keeps shuffling stale data around to free new erase blocks. <strong>TRIM</strong> is the standard command the OS uses to tell the drive \"these sectors are now free, you can erase them ahead of time\".",
"trimBody2": "Without TRIM, SSD performance degrades over time as the drive runs out of pre-erased blocks and has to do erase-on-write, and write amplification increases — both shortening the drive's useful life. With TRIM enabled, the drive can keep a healthy pool of empty blocks ready to write into.",
"trimBody3": "On ZFS, <code>autotrim=on</code> is the modern equivalent of the periodic <code>zpool trim &lt;pool&gt;</code> command — instead of having to remember to run a trim manually (or schedule one), the pool issues TRIM commands automatically and continuously as blocks become free. It's low-overhead and the recommended setting for SSD-backed pools.",
"practicalTitle": "Why is this practical to enable?",
"practicalItems": [
"<strong>Sustained write performance.</strong> SSDs that never see TRIM commands slow down measurably over months. Autotrim keeps the controller's job easier.",
"<strong>Drive longevity.</strong> Lower write amplification means fewer total NAND writes for the same amount of data — measurable in years of useful life for the disk.",
"<strong>No scheduled cron job to remember.</strong> Unlike a periodic <code>zpool trim</code>, autotrim is fire-and-forget — the pool handles it on its own."
],
"whenTitle": "When is this necessary?",
"whenIntro1": "<strong>You should enable it</strong> on any ZFS pool whose vdevs are all SSD or NVMe with TRIM support — the typical Proxmox install on consumer or enterprise SSDs.",
"whenIntro2": "<strong>The script skips it automatically</strong> on:",
"whenSkipItems": [
"Pools containing any HDD (rotational) vdev — TRIM is meaningless there.",
"Drives without <code>discard_granularity</code> exposed in sysfs — usually old SSDs without TRIM, or pass-through paths where the OS can't see the underlying device.",
"Pools where ZFS itself reports the property unsupported (rare; very old pools).",
"Pools already set to <code>autotrim=on</code> (no-op)."
],
"whenIntro3": "<strong>Not relevant on ext4-only hosts</strong> — there's nothing for ZFS to trim. The function exits with a friendly message in that case.",
"recordedTitle": "Why only the pools ProxMenux changed are recorded",
"recordedBody": "The function only writes a pool to its internal state file (<code>/usr/local/share/proxmenux/zfs_autotrim_pools</code>) when it actively flipped that pool from <code>off</code> to <code>on</code>. Pools you had on autotrim before running the script are left out of the list, so a future Uninstall doesn't turn off settings you configured yourself — only ProxMenux's own changes are reverted.",
"manualTitle": "Manual equivalent (run on your server)",
"manualIntro": "The full sequence the script runs against each pool is replicable by hand. This is what you would type if you wanted to do the same thing on a single pool without ProxMenux:",
"verifyTitle": "Verification and manual rollback",
"oneShotTitle": "Need a one-shot trim instead of continuous?",
"oneShotBody": "Some operators prefer a manual trim during off-peak hours rather than continuous trim activity. Disable autotrim and schedule a cron job that runs <code>zpool trim &lt;pool&gt;</code> — same end goal, different cadence."
},
"vzdump": {
"heading": "Increase vzdump backup speed",
"intro": "By default, Proxmox vzdump throttles backups to protect running VMs/CTs from IO starvation. On many setups that throttle is more conservative than needed. This option removes the bandwidth cap and lowers the I/O priority so vzdump can saturate the storage path during backup windows.",
"changedTitle": "What gets changed in /etc/vzdump.conf",
"noBackupTitle": "No backup of vzdump.conf",
"noBackupBody": "The script <strong>edits <code>/etc/vzdump.conf</code> in place</strong> without creating a <code>.bak</code> first. If you had custom values there (bwlimit, ionice, compress, pigz, tmpdir, exclude-path, etc.), the changes to <em>those two lines</em> are made with <code>sed</code> — surrounding config is preserved — but there's no \"undo\" snapshot. Make a manual backup if your config is non-trivial: <code>cp /etc/vzdump.conf /etc/vzdump.conf.pre-proxmenux</code>.",
"skipTitle": "When to skip this",
"skipBody": "On a host with slow local storage and VMs that are latency-sensitive, removing the bandwidth cap can cause noticeable slowdowns during backups. If you've previously set a specific <code>bwlimit</code> for that reason, keep it — skip this option.",
"verifyTitle": "Verification and manual rollback"
},
"related": {
"heading": "Related",
"items": [
{
"label": "ZFS Management commands",
"href": "/docs/help-info/zfs-commands",
"tail": " — zpool / zfs reference for ARC, snapshots, scrub."
},
{
"label": "Storage and Disks commands",
"href": "/docs/help-info/storage-commands",
"tail": " — generic block-device and Proxmox storage reference."
},
{
"label": "Backup and Restore commands",
"href": "/docs/help-info/backup-commands",
"tail": " — vzdump CLI reference (now without the legacy bwlimit / ionice caps)."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — revert ARC / vzdump changes."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,133 @@
{
"meta": {
"title": "Post-Install: System | ProxMenux Documentation",
"description": "System-level optimizations in the ProxMenux Customizable post-install script: journald and logrotate size limits, higher kernel and file-descriptor limits, balanced memory tuning, kexec for quick reboots, and kernel panic recovery."
},
"header": {
"title": "Post-Install: System",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Six independent, system-level optimizations. They tune <strong>journald</strong> and <strong>logrotate</strong> to stop logs from filling the disk, raise <strong>kernel and file-descriptor limits</strong> so applications with many open files don't hit ceilings, <strong>balance memory</strong> for a virtualization host, add <strong>kexec</strong> for \"reboots without the BIOS\", and configure <strong>automatic recovery</strong> on kernel panic. All six are tracked and reversible from the Uninstall menu."
},
"journald": {
"heading": "Optimize journald",
"intro": "Rewrites <code>/etc/systemd/journald.conf</code> with sane defaults so the systemd journal can't slowly eat your root partition, then restarts <code>systemd-journald</code> and vacuums existing logs.",
"keyTitle": "Key values",
"keyItems": [
"<code>Storage=persistent</code> — keep logs on disk across reboots.",
"<code>SystemMaxUse=64M</code> / <code>RuntimeMaxUse=60M</code> — hard caps on journal disk/memory usage.",
"<code>Compress=yes</code>, <code>Seal=no</code> — compress logs, skip forward-secure sealing (saves CPU).",
"<code>MaxLevelStore=info</code> — store info and above (required for ProxMenux Monitor's log viewer and for Fail2Ban to detect SSH/Proxmox auth failures from the journal).",
"Rate-limits: <code>1000 events / 30 s</code> to prevent log flooding.",
"<code>ForwardToSyslog=no</code>, <code>ForwardToWall=no</code> — don't duplicate messages to syslog or broadcast to consoles."
],
"tipTitle": "Why MaxLevelStore=info matters",
"tipBody": "Using a stricter level like <code>warning</code> makes ProxMenux Monitor's log viewer show nearly identical entries across all date ranges (because most activity is info-level), and it prevents Fail2Ban from seeing failed logins. If you want less log volume, rely on the <code>SystemMaxUse</code> cap and <code>RateLimitBurst</code> instead of lowering the stored level."
},
"logrotate": {
"heading": "Optimize logrotate",
"intro": "Rewrites <code>/etc/logrotate.conf</code> with a tighter policy suitable for a host that's also part of an SSD-protecting Log2RAM setup: daily rotation, 7-day retention, 10 MB size trigger, compression, and <code>copytruncate</code> so active services keep writing without reopening their log files. Original <code>logrotate.conf</code> is backed up to <code>.bak</code> on first apply.",
"tipTitle": "Log2RAM-friendly",
"tipBody": "The <code>size 10M</code> trigger means logs rotate on size <em>or</em> daily, whichever comes first. Combined with Log2RAM's RAM-backed <code>/var/log</code>, this keeps the working set small so flushes to disk stay cheap."
},
"limits": {
"heading": "Increase various system limits",
"intro": "Raises a bunch of kernel, systemd and PAM limits that default to values too low for a host running many VMs, containers and networked services.",
"headerFile": "File",
"headerSets": "What it sets",
"rows": [
{
"file": "/etc/sysctl.d/99-maxwatches.conf",
"sets": "<code>fs.inotify.max_user_watches / max_user_instances / max_queued_events = 1048576</code>"
},
{
"file": "/etc/sysctl.d/99-maxkeys.conf",
"sets": "<code>kernel.keys.maxkeys / root_maxkeys = 1000000</code>"
},
{
"file": "/etc/sysctl.d/99-swap.conf",
"sets": "<code>vm.swappiness = 10</code>, <code>vm.vfs_cache_pressure = 100</code>"
},
{
"file": "/etc/sysctl.d/99-fs.conf",
"sets": "<code>fs.nr_open / file-max = 2097152</code>, <code>fs.aio-max-nr = 1048576</code>"
},
{
"file": "/etc/security/limits.d/99-limits.conf",
"sets": "<code>nofile</code> and <code>nproc</code> to 1,048,576 (unlimited for root)"
},
{
"file": "/etc/systemd/system.conf + user.conf",
"sets": "<code>DefaultLimitNOFILE=1048576</code> for systemd services"
},
{
"file": "/etc/pam.d/common-session + runuser-l",
"sets": "<code>session required pam_limits.so</code> so the above apply to login shells"
},
{
"file": "/root/.profile",
"sets": "<code>ulimit -n 1048576</code> for the root shell"
}
],
"tipTitle": "Why inotify matters",
"tipBody": "Applications like Docker, Syncthing, Node.js watchers, Plex's library scanner and many more hit <code>max_user_watches</code> quickly. Default on Debian is 8192 — a single running Plex can exhaust it. 1M is generous and costs ~1 KB of RAM per watch, which is negligible."
},
"memory": {
"heading": "Optimize memory settings",
"intro": "Writes a balanced sysctl profile to <code>/etc/sysctl.d/99-memory.conf</code>. Designed for a hypervisor host — prefers keeping VM working sets in RAM and frees pages proactively so allocation bursts don't stall.",
"warnTitle": "swappiness=10 on memory-tight hosts",
"warnBody": "On a host with 16 GB RAM running many VMs, lowering swappiness can push the kernel to OOM-kill processes instead of swapping. If you're routinely seeing OOM events, raise swappiness back to 3060 in <code>/etc/sysctl.d/99-memory.conf</code> after the script runs."
},
"kexec": {
"heading": "Enable fast reboots (kexec)",
"intro": "Installs <code>kexec-tools</code> and wires it up so you can reboot the host straight into a new kernel <em>without going through BIOS/UEFI firmware</em>. On big servers where POST takes 45 90 seconds, this turns a reboot from a coffee break into a few seconds of downtime.",
"installsTitle": "What ProxMenux installs",
"installsItems": [
"Package <code>kexec-tools</code> (with debconf pre-answered so apt doesn't prompt during install).",
"Systemd unit <code>/etc/systemd/system/kexec-pve.service</code> — loads the Proxmox kernel and initrd into memory at boot, reusing the current cmdline.",
"An alias in <code>/root/.bash_profile</code>: <code>reboot-quick</code> → <code>systemctl kexec</code>."
],
"usageIntro": "Usage after the next reboot (or manual <code>systemctl start kexec-pve</code>):",
"warnTitle": "When not to use kexec",
"warnBody": "kexec skips firmware-level init. If you rely on BIOS/UEFI to reset hardware state — for example, a GPU doing passthrough that only resets cleanly on full POST, or a troublesome HBA firmware — kexec reboots may leave those devices in a half-initialized state. Use a normal <code>reboot</code> after kernel upgrades or when you need BIOS/UEFI changes to take effect. <code>reboot-quick</code> is for everyday restarts."
},
"panic": {
"heading": "Enable restart on kernel panic",
"intro": "Makes the kernel <strong>auto-reboot</strong> instead of sitting forever on a panic screen. Critical on headless/remote Proxmox hosts where a hung kernel means all your VMs are down until you can power-cycle the box.",
"tipTitle": "Pair this with remote console access",
"tipBody": "Auto-reboot is a recovery mechanism, not a debug tool. If you want to <em>investigate</em> a panic rather than just come back up, use <link>the kexec option</link> above with the kernel kdump support (not configured by ProxMenux) or capture a serial console to another host before enabling auto-reboot."
},
"verify": {
"heading": "Verification",
"intro": "After applying the System optimizations:",
"tipTitle": "Fully reversible",
"tipBody": "All six options are tracked in <code>installed_tools.json</code>, so they appear in <link>Uninstall Optimizations</link> if you want to back any of them out. Reverts restore the sysctl files' defaults, drop the systemd unit and alias for kexec, and reset journald/logrotate to stock Debian configs."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Useful System Commands",
"href": "/docs/help-info/system-commands",
"tail": " — verify the changes (free -h, journalctl, ulimit -a)."
},
{
"label": "Performance",
"href": "/docs/post-install/performance",
"tail": " — additional system-level tuning (pigz)."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — revert any of these changes."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
@@ -0,0 +1,210 @@
{
"meta": {
"title": "Uninstall Optimizations | ProxMenux Documentation",
"description": "Reverse any post-install optimization applied by ProxMenux. Every change is tracked in a JSON registry, and every tool has a dedicated uninstaller that restores the original configuration."
},
"header": {
"title": "Uninstall Optimizations",
"description": "Reverse any change made by the Automated or Customizable post-install scripts. ProxMenux keeps a registry of every optimization it applied and has a dedicated reversal function for each one — pick which to revert, and the host goes back.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "Why this exists",
"body": "Every tweak the post-install scripts apply is <strong>tracked</strong> in a JSON registry at <code>/usr/local/share/proxmenux/installed_tools.json</code>. That registry is what powers the uninstall flow — it shows you the list of optimizations currently applied, and a reversal function that restores the original state for each one (from backup files where possible, or by reinstalling the affected packages)."
},
"openMenu": {
"heading": "How to open it",
"body": "From ProxMenux's main menu, <strong>Settings post-install Proxmox → Uninstall optimizations</strong>. You will see a checklist of <em>currently applied</em> optimizations — items you have not applied don't show up.",
"imageAlt": "Uninstall Optimizations checklist showing items currently applied on the host, with checkboxes to select which to revert"
},
"howWorks": {
"heading": "How the reversal works",
"steps": [
{
"title": "Registry and auto-detection",
"body1": "On first run, ProxMenux walks the host looking for fingerprint files (e.g. <code>/etc/sysctl.d/99-memory.conf</code>, <code>/etc/apt/apt.conf.d/99-force-ipv4</code>, <code>haveged</code> package installed, Log2RAM service active…). Anything found is added to the registry as reversible, even if it was applied by an older ProxMenux version that predates the registry.",
"body2": "This migration only runs once. After that, every apply/revert updates the registry directly."
},
{
"title": "Pick what to revert",
"body1": "The checklist shows a human-readable label per item (e.g. <em>Memory Settings Optimization</em>, <em>IOMMU/VFIO PCI Passthrough</em>, <em>Log2RAM (SSD Protection)</em>). Tick the ones you want to reverse. Nothing you don't tick will be touched."
},
{
"title": "Reversal runs",
"body1": "For each selected item, ProxMenux calls its matching uninstall function. Most reversals follow one of three patterns:",
"items": [
"<strong>Backup-based</strong> — restore a <code>.bak</code> captured at apply time (bashrc, logrotate.conf, journald.conf, GRUB/kernel cmdline).",
"<strong>Delete-the-config</strong> — remove ProxMenux's <code>/etc/sysctl.d/99-*.conf</code>, <code>/etc/apt/apt.conf.d/99-*</code>, or systemd unit, then reload.",
"<strong>Package reinstall</strong> — for UI changes like the subscription banner, reinstall the upstream packages with <code>--force-confnew</code> to restore shipped configuration."
],
"body2": "Each reversal logs its progress. Items that require a reboot (VFIO, persistent interface names) set a flag that triggers the reboot prompt at the end."
},
{
"title": "Reboot if needed",
"body1": "If any reversed item modified kernel parameters, kernel modules, or network naming, you'll be offered a reboot. Otherwise the changes are live immediately."
}
]
},
"reversible": {
"heading": "What is reversible",
"intro": "Every optimization the post-install scripts apply has a matching uninstaller. Grouped here by area:",
"groups": [
{
"title": "Repositories & APT",
"items": [
{
"tool": "Subscription Banner Removal",
"restores": "Reinstalls pve-manager, proxmox-widget-toolkit, libjs-extjs and libpve-http-server-perl with force-confnew to restore the original UI files. Also clears cached .js / .gz copies."
},
{
"tool": "APT Language Skip",
"restores": "Removes /etc/apt/apt.conf.d/99-disable-translations. APT will download language packages again."
},
{
"tool": "APT IPv4 Force",
"restores": "Removes /etc/apt/apt.conf.d/99-force-ipv4."
}
]
},
{
"title": "Kernel, memory and system limits",
"items": [
{
"tool": "Memory Settings",
"restores": "Removes /etc/sysctl.d/99-memory.conf and reloads sysctl."
},
{
"tool": "Kernel Panic Configuration",
"restores": "Removes /etc/sysctl.d/99-kernelpanic.conf."
},
{
"tool": "System Limits Increase",
"restores": "Removes /etc/sysctl.d/99-maxwatches.conf, 99-maxkeys.conf, 99-swap.conf, 99-fs.conf and /etc/security/limits.d/99-limits.conf. Reverts PAM limits and systemd DefaultLimitNOFILE."
}
]
},
{
"title": "Networking",
"items": [
{
"tool": "Network Optimizations",
"restores": "Removes /etc/sysctl.d/99-network.conf and the proxmenux-fwbr-tune.service unit. Reloads sysctl and systemd."
},
{
"tool": "Persistent Interface Names",
"restores": "Removes every .link file from /etc/systemd/network/. Interface names return to systemd's default behaviour on next reboot."
}
]
},
{
"title": "Logging",
"items": [
{
"tool": "Journald Optimization",
"restores": "Rewrites /etc/systemd/journald.conf with vanilla defaults and restarts systemd-journald."
},
{
"tool": "Logrotate Optimization",
"restores": "Restores /etc/logrotate.conf from the .bak file captured before the change."
},
{
"tool": "Log2RAM",
"restores": "Stops and disables the service and timer. Purges cron jobs, systemd units, binaries, config files and the /var/log.hdd directory. Also uninstalls the apt package if it was installed that way."
},
{
"tool": "ZFS autotrim",
"restores": "Reads /usr/local/share/proxmenux/zfs_autotrim_pools (the list of pools ProxMenux actually changed) and runs zpool set autotrim=off on each one. Pools you set autotrim on manually before ProxMenux ran are not touched."
}
]
},
{
"title": "Shell & appearance",
"items": [
{
"tool": "Bashrc Customization",
"restores": "Restores /root/.bashrc from the .bak backup. If no backup exists, removes the PMX_CORE_BASHRC block by markers."
},
{
"tool": "Fastfetch",
"restores": "Removes the binary, config directory, update-motd hook and the bashrc block. Purges the apt package if installed."
},
{
"tool": "Figurine",
"restores": "Removes the binary, profile.d entry and the alias block in bashrc/profile."
}
]
},
{
"title": "Hardware & virtualization",
"items": [
{
"tool": "IOMMU / VFIO",
"restores": "Removes vfio modules from /etc/modules, the nouveau / radeon / nvidia blacklist entries, and intel_iommu=on / amd_iommu=on / iommu=pt / pcie_acs_override parameters from /etc/kernel/cmdline (ZFS) or GRUB. Rebuilds initramfs."
},
{
"tool": "AMD CPU fixes (Ryzen/EPYC)",
"restores": "Removes idle=nomwait from kernel cmdline (ZFS) or GRUB, and the ignore_msrs / report_ignored_msrs options from /etc/modprobe.d/kvm.conf."
}
]
},
{
"title": "Services & extras",
"items": [
{
"tool": "Time Synchronization",
"restores": "Sets timezone back to UTC (safe default) via timedatectl."
},
{
"tool": "Entropy Generation (haveged)",
"restores": "Stops, disables and purges the haveged package."
},
{
"tool": "kexec (fast reboots)",
"restores": "Disables kexec-pve.service, removes the unit file and the reboot-quick alias, purges kexec-tools."
}
]
}
]
},
"edge": {
"heading": "Edge cases and caveats",
"packageTitle": "Package reinstall touches live Proxmox packages",
"packageBody": "Reverting <strong>Subscription Banner Removal</strong> reinstalls <code>pve-manager</code>, <code>proxmox-widget-toolkit</code>, <code>libjs-extjs</code> and <code>libpve-http-server-perl</code> with <code>--force-confnew</code>. This is generally safe but does touch the running web UI — refresh your browser afterwards, and expect a few seconds of reconnection. Don't run this in the middle of a migration or clone operation.",
"rebootTitle": "Persistent names and VFIO need a reboot",
"rebootBody": "Removing the <code>.link</code> files (<em>Persistent Interface Names</em>) and reverting <em>IOMMU/VFIO</em> do not affect the running system — they only matter after a reboot. ProxMenux sets the reboot flag automatically for these.",
"perItemTitle": "You can revert one thing and keep the rest",
"perItemBody": "The uninstaller operates per-item. If you only want to remove Log2RAM but keep the network tuning and bashrc changes, tick only <em>Log2RAM</em>. Nothing else is touched, and the registry is updated accordingly."
},
"inspect": {
"heading": "Inspecting the registry manually",
"intro": "If you want to see what's tracked without opening the menu:",
"outro": "Each <code>\"tool\": true</code> entry corresponds to something ProxMenux applied and can reverse. Removing an entry manually is not recommended — always use the menu, which also runs the reversal function instead of just forgetting the change.",
"reinstallTitle": "Reinstall after uninstall",
"reinstallBody": "Reverting an optimization doesn't prevent you from re-applying it later. Open <link>the Post-Install menu</link> again and run either Automated or Customizable — the registry will track the new state."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Automated Post-Install",
"href": "/docs/post-install/automated",
"tail": " — re-apply the sane-defaults baseline."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — pick a different subset."
},
{
"label": "Uninstall ProxMenux",
"href": "/docs/settings/uninstall-proxmenux",
"tail": " — different operation: removes ProxMenux itself, not its applied optimizations."
},
{
"label": "Post-Install overview",
"href": "/docs/post-install",
"tail": "."
}
]
}
}
@@ -0,0 +1,106 @@
{
"meta": {
"title": "Apply Available Updates — Post-Install Optimizations | ProxMenux Documentation",
"description": "How ProxMenux detects when a post-install optimization (Log2Ram, Memory Settings, System Limits, Logrotate, Network tuning…) has been updated upstream, and how to apply the new version — from the Post-Install menu or from the Monitor dashboard."
},
"header": {
"title": "Apply Available Updates",
"description": "When a post-install optimization (Log2Ram, Memory Settings, System Limits, Logrotate…) gets a newer version on disk than the one currently registered on the host, ProxMenux surfaces it as an available update. You can apply it from the Post-Install menu (Scripts side) or from the Monitor dashboard — both paths re-run the same post-install function and refresh the registry.",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this is",
"body": "ProxMenux post-install optimizations are versioned. Each script in the repository carries a version number (e.g. <code>Log2ram SSD Protection v1.2</code>), and the host keeps a registry of which optimizations are active and at which version in <code>/usr/local/share/proxmenux/installed_tools.json</code>. When a new ProxMenux release ships an updated version of any optimization, ProxMenux detects the mismatch and offers to re-apply just that one — without re-running the whole post-install."
},
"why": {
"heading": "Why this exists",
"body": "Post-install optimizations occasionally get improvements — a better sysctl tuning, a stricter Logrotate limit, a new Log2RAM size heuristic, a fix for an edge case reported by a tester. Without an update path the operator had only two options: manually re-run the post-install script (which re-applies <em>every</em> optimization) or skip the improvement entirely. Apply Available Updates is the middle ground: a per-optimization, opt-in re-run that lifts only the versions that actually moved."
},
"detection": {
"heading": "How updates are detected",
"steps": [
{
"title": "Versioned scripts on disk",
"body": "Every post-install function declares its version inside the script (<code>scripts/post_install/auto_post_install.sh</code> and <code>scripts/post_install/customizable_post_install.sh</code>). A scanner extracts these versions from the source on disk."
},
{
"title": "Versioned registry on the host",
"body": "When the operator applied each optimization, the corresponding <code>register_tool</code> call wrote the active version into <code>/usr/local/share/proxmenux/installed_tools.json</code>. That file is the source of truth for \"what is active on this host right now\"."
},
{
"title": "Monitor compares both sides",
"body": "On startup and every 24h, the Monitor compares disk versions against registry versions. Any mismatch produces an entry in <code>/usr/local/share/proxmenux/updates_available.json</code>. That file drives both the Post-Install menu entry and the Monitor dashboard card."
},
{
"title": "One notification per new version",
"body": "When at least one optimization has a pending update, the Monitor emits a single grouped notification — for example <em>\"4 ProxMenux optimization update(s) available\"</em> — with one line per tool in the same <code>name (vX → vY)</code> format used for Proxmox package updates. The notification is anti-cascade so it does not repeat day after day for the same set; only a new version (or a fresh tool entering the list) re-triggers it."
}
]
},
"pathA": {
"heading": "Path A — From the Post-Install menu",
"intro": "From ProxMenux's main menu, open <strong>Settings post-install Proxmox</strong>. When there are pending updates, a new entry <strong>Apply available updates (N)</strong> appears right above <em>Uninstall optimizations</em>. The number reflects how many optimizations have a newer version on disk than what the host currently has registered. When everything is up to date the entry simply does not appear, so the menu stays clean.",
"menuAlt": "Post-Install Scripts menu showing the conditional 'Apply available updates (N)' entry positioned just above 'Uninstall optimizations', with the count badge indicating how many optimizations have a newer version on disk",
"menuCaption": "The <em>Apply available updates (N)</em> entry only renders when at least one optimization has a pending update — it hides when the host is current.",
"checklistBody": "Selecting the entry opens a checklist with every pending update, each row formatted as <code>name (vX → vY)</code>. All rows are pre-checked by default; uncheck any you don't want to apply this round.",
"checklistAlt": "Apply Available Updates checklist dialog with one row per pending optimization, each labelled with the optimization name and the version transition (current → available). All rows pre-checked.",
"checklistCaption": "Per-optimization opt-in: pick exactly which versions to lift. The same engine that powers Automated and Customizable post-install runs in the background to re-apply each function and refresh its registry version."
},
"pathB": {
"heading": "Path B — From the Monitor dashboard",
"intro": "The same updates appear in the Monitor under <link>Settings → ProxMenux Optimizations</link>. When pending updates are detected the card shows an \"Updates available\" banner with the count and an <strong>Apply</strong> action that opens the same per-optimization picker.",
"imageAlt": "ProxMenux Optimizations card on the Monitor dashboard with an Updates available banner at the top showing the count of pending updates and an Apply button that opens the per-optimization picker",
"imageCaption": "The Optimizations card in the Monitor — when at least one optimization has a newer version on disk, the banner surfaces it without requiring shell access."
},
"applying": {
"heading": "What happens when you apply",
"steps": [
{
"title": "Re-runs the post-install function",
"body": "The picked optimization's function is re-executed against the host. Because every post-install function is <strong>idempotent</strong>, re-running it doesn't duplicate config — it overwrites the previous version with the new one (sysctl files, drop-ins, service units, etc.)."
},
{
"title": "Refreshes the registry",
"body": "The <code>register_tool</code> call inside the function writes the new version into <code>installed_tools.json</code>. The next scan no longer sees a mismatch and the update entry disappears from both the menu and the Monitor card."
},
{
"title": "No reboot unless the function says so",
"body": "Most updates take effect immediately. Updates that touch kernel modules, persistent interface names, or VFIO show the same reboot prompt as a fresh install would."
}
]
},
"differs": {
"heading": "How it differs from the other paths",
"headerPath": "Path",
"headerScope": "Scope",
"headerWhen": "When it makes sense",
"rows": [
{
"pathLabel": "Automated",
"pathHref": "/docs/post-install/automated",
"scope": "Re-applies <em>every</em> optimization in the bundle.",
"when": "Fresh host, or full re-baseline of a fully-managed node."
},
{
"pathLabel": "Customizable",
"pathHref": "/docs/post-install/customizable",
"scope": "Pick from the full catalogue.",
"when": "Cherry-pick which optimizations are active on the host."
},
{
"pathLabel": "Apply available updates",
"pathHref": null,
"scope": "Only the optimizations whose version bumped on disk.",
"when": "Keep already-installed optimizations current without touching the rest."
},
{
"pathLabel": "Uninstall optimizations",
"pathHref": "/docs/post-install/uninstall",
"scope": "Reverse the optimization and remove its registry entry.",
"when": "Roll back a specific change."
}
]
},
"notifTitle": "Notification gate",
"notifBody": "The notification that announces pending updates is the <em>ProxMenux optimization updates available</em> event. It is enabled by default on every channel, can be muted per-channel from <link>Settings → Notifications</link>, and is anti-cascade — it fires once per distinct set of pending updates, not on every 24h scan."
}
@@ -0,0 +1,116 @@
{
"meta": {
"title": "Post-Install: Virtualization | ProxMenux Documentation",
"description": "Virtualization options in the ProxMenux Customizable post-install script: auto-install the right guest agent if Proxmox runs inside a VM, and enable IOMMU / VFIO so you can pass PCI devices (GPUs, NICs, HBAs) through to your own VMs."
},
"header": {
"title": "Post-Install: Virtualization",
"section": "Settings post-install Proxmox"
},
"intro": {
"title": "What this category covers",
"body": "Two independent options. <strong>Install relevant guest agent</strong> is a safety net for when Proxmox itself runs nested inside another hypervisor. <strong>Enable VFIO IOMMU support</strong> is the one most users care about: it flips on the kernel features you need to pass a GPU, HBA or NIC straight into a VM with near-native performance."
},
"guestAgent": {
"heading": "Install relevant guest agent",
"intro": "Detects the virtualization environment the Proxmox host is running on (using <code>systemd-detect-virt</code> and <code>dmidecode</code>) and installs the matching guest-tools package so the outer hypervisor can communicate with Proxmox cleanly (graceful shutdown, clock sync, IP reporting, etc.).",
"headerDetected": "Detected host",
"headerPackage": "Package installed",
"rows": [
{
"detected": "QEMU / KVM",
"package": "qemu-guest-agent"
},
{
"detected": "VMware (ESXi, Workstation)",
"package": "open-vm-tools"
},
{
"detected": "VirtualBox",
"package": "virtualbox-guest-utils"
},
{
"detected": "Bare metal (none)",
"package": "— no-op, nothing installed"
}
],
"skipTitle": "Skip this on bare-metal Proxmox",
"skipBody": "If Proxmox runs directly on hardware (the common case), ticking this option is a no-op — the detector returns <code>none</code> and the script exits without changes. The option only matters for the minority of setups that run Proxmox <em>as a guest</em> for testing or labs."
},
"vfio": {
"heading": "Enable VFIO IOMMU support",
"intro": "Turns on IOMMU on the host and loads the kernel modules that make PCI passthrough possible (<code>vfio</code>, <code>vfio_iommu_type1</code>, <code>vfio_pci</code>). With this enabled, you can bind a physical device to a VM and the guest gets direct, near-bare-metal access to it.",
"whoTitle": "Who needs this",
"whoItems": [
"You want to pass a GPU to a Windows gaming VM or a macOS VM.",
"You have a dedicated 10G NIC for a firewall/router VM (OPNsense, pfSense).",
"You want to pass an HBA directly to a TrueNAS/Unraid VM for ZFS on bare disks.",
"You're planning to use <em>Coral TPU</em>, a capture card, or an SDR dongle in a VM."
],
"whoOutro": "If none of those apply, you can safely skip this option. For passthrough to an <strong>LXC</strong> (not a VM), IOMMU is <em>not</em> required.",
"doesTitle": "What ProxMenux does",
"doesIntro": "The function is boot-loader aware: it detects whether Proxmox is on ZFS (systemd-boot) or LVM/ext4 (GRUB) and writes to the right file. It's also idempotent — if the parameters are already present, nothing is added.",
"headerBoot": "Boot type",
"headerFile": "File touched",
"headerPost": "Post-update step",
"bootRows": [
{
"boot": "systemd-boot (ZFS)",
"file": "/etc/kernel/cmdline",
"post": "proxmox-boot-tool refresh"
},
{
"boot": "GRUB (LVM/ext4)",
"file": "/etc/default/grub",
"post": "update-grub"
}
],
"kernelIntro": "Kernel parameters added:",
"modulesIntro": "Kernel modules added to <code>/etc/modules</code>:",
"blacklistIntro": "Conflicting drivers blacklisted in <code>/etc/modprobe.d/blacklist.conf</code>:",
"blacklistTitle": "Blacklisting GPU drivers conflicts with host-side GPU usage",
"blacklistBody": "The blacklist ensures the host kernel never binds <em>any</em> GPU driver, so VFIO can claim the GPU cleanly. This is exactly what you want for passthrough to a VM — but it's the <strong>opposite</strong> of what you need to <link>install NVIDIA drivers on the host</link> (for LXC transcoding, for example). Pick one path per GPU:",
"pathItems": [
"<strong>GPU → VM:</strong> enable VFIO/IOMMU here, leave the GPU drivers blacklisted.",
"<strong>GPU → LXC (or host):</strong> skip this option, use the NVIDIA host install, do not blacklist nvidia/nouveau.",
"<strong>Two GPUs:</strong> one can go to a VM and the other to an LXC, but you'll need finer-grained configuration (bind only one card to <code>vfio-pci</code> by PCI ID). Default blacklist is too broad for this case — edit <code>blacklist.conf</code> afterwards."
],
"acsTitle": "About pcie_acs_override — know what you're enabling",
"acsBody": "<code>pcie_acs_override=downstream,multifunction</code> relaxes the PCIe Access Control Services check. It lets the kernel split apart IOMMU groups that the firmware reports as monolithic, which is sometimes the only way to pass through one device of a group without dragging the rest. The trade-off is <strong>reduced isolation between devices</strong>: a malicious or compromised VM with passthrough has a larger attack surface via DMA. Fine for a home lab; think twice before enabling on a host that runs untrusted workloads. If you don't need it, remove that token from <code>/etc/kernel/cmdline</code> or <code>/etc/default/grub</code> after the script runs and re-run the boot-loader update step.",
"rebootTitle": "Reboot required",
"rebootBody": "IOMMU, VFIO modules, and the blacklist only take effect after a reboot + initramfs regeneration. The script triggers <code>update-initramfs -u -k all</code> and the boot-loader refresh, and sets the \"reboot required\" flag so Customizable prompts you at the end.",
"verifyTitle": "Verification after reboot",
"revertTitle": "Reversible from the Uninstall menu",
"revertBody": "<link>Uninstall Optimizations</link> reverts all the changes: strips the IOMMU tokens from <code>/etc/kernel/cmdline</code> or GRUB, removes the VFIO modules from <code>/etc/modules</code>, removes the driver blacklist entries, and rebuilds initramfs. A reboot is required to actually apply the reversion."
},
"related": {
"heading": "Related",
"items": [
{
"label": "Add GPU to VM (Passthrough)",
"href": "/docs/hardware/gpu-vm-passthrough",
"tail": " — natural next step once IOMMU + VFIO are enabled."
},
{
"label": "Add Controller or NVMe to VM",
"href": "/docs/disk-manager/add-controller-nvme-vm",
"tail": " — same passthrough infrastructure for storage controllers."
},
{
"label": "GPU Passthrough commands",
"href": "/docs/help-info/gpu-commands",
"tail": " — IOMMU verification reference."
},
{
"label": "Uninstall Optimizations",
"href": "/docs/post-install/uninstall",
"tail": " — back IOMMU / VFIO out cleanly."
},
{
"label": "Customizable Post-Install",
"href": "/docs/post-install/customizable",
"tail": " — back to the parent menu."
}
]
}
}
+152
View File
@@ -0,0 +1,152 @@
{
"meta": {
"title": "Fail2Ban | ProxMenux Documentation",
"description": "Install Fail2Ban with three jails tuned for Proxmox (SSH aggressive, Proxmox UI 8006, ProxMenux Monitor 8008). Includes the journald MaxLevelStore fix, custom log services for reliability, auto-detected nftables/iptables backend and SSH MaxAuthTries hardening.",
"ogTitle": "Fail2Ban | ProxMenux Documentation",
"ogDescription": "Brute-force protection for SSH and Proxmox web UIs, with Proxmox-specific journald and backend fixes."
},
"header": {
"title": "Fail2Ban",
"description": "Installs Fail2Ban with a Proxmox-specific configuration: three jails (SSH aggressive, Proxmox UI on port 8006, ProxMenux Monitor on port 8008 + reverse proxy), a journald log-level fix so SSH auth events are actually stored, two journal-to-file logger services that work around a known Fail2Ban systemd-backend issue, auto-detected firewall backend and SSH MaxAuthTries hardening.",
"section": "Security"
},
"intro": {
"title": "What this does",
"body": "Installs Fail2Ban from the Debian repos and writes a complete Proxmox-tuned configuration that protects three attack surfaces (SSH, Proxmox UI, ProxMenux Monitor) out of the box. Detects an existing install and offers a manage menu (reinstall / remove) instead of re-running the installer."
},
"firstLaunch": {
"heading": "First-launch dialog",
"body": "On a host without Fail2Ban, the script shows a confirmation dialog summarising everything it's about to install and configure. Cancel exits without changes; confirm starts the install flow.",
"imageAlt": "Fail2Ban install confirmation dialog listing the three jails, journald fix and SSH hardening"
},
"jails": {
"heading": "The three jails",
"headerJail": "Jail",
"headerProtects": "Protects",
"headerRetries": "Retries / Window",
"headerBan": "Ban time",
"rows": [
{
"jail": "[sshd]",
"protects": "SSH (aggressive mode — covers ddos, mode, normal)",
"retries": "2 / 60 min",
"ban": "9 hours"
},
{
"jail": "[proxmox]",
"protects": "Proxmox web UI (port 8006)",
"retries": "3 / 10 min",
"ban": "1 hour"
},
{
"jail": "[proxmenux]",
"protects": "ProxMenux Monitor (port 8008 + http/https reverse proxy)",
"retries": "3 / 10 min",
"ban": "1 hour"
}
],
"outro": "Global defaults from <code>jail.local</code>: <code>ignoreip = 127.0.0.1/8 ::1</code>, <code>ignoreself = true</code>,<code> bantime = 86400</code> (24h fallback for jails that don't override it), <code>maxretry = 2</code>, <code>findtime = 1800</code>."
},
"journald": {
"heading": "Why the journald fix matters",
"intro": "Proxmox ships <code>/etc/systemd/journald.conf</code> with <codeNw>MaxLevelStore=warning</codeNw>. journald drops every log message <em>below</em> warning before storing it. SSH and PAM emit auth failures at <em>info</em> / <em>notice</em> levels, so:",
"diagram": {
"sshLabel": "SSH / PAM",
"sshDetail": "auth failure\n(info / notice level)",
"journaldLabel": "journald",
"journaldDetail": "MaxLevelStore=warning\n→ event silently dropped",
"fail2banLabel": "Fail2Ban",
"fail2banDetail": "sees nothing\n→ never bans anything",
"arrowLabel": "default Proxmox"
},
"afterDiagram": "The installer detects this and writes a drop-in at <codeXs>/etc/systemd/journald.conf.d/proxmenux-loglevel.conf</codeXs> raising both <code>MaxLevelStore</code> and <code>MaxLevelSyslog</code> to <code>info</code>:",
"code": "[Journal]\nMaxLevelStore=info\nMaxLevelSyslog=info",
"outro": "Then restarts <code>systemd-journald</code>. The drop-in is removed on uninstall, restoring the original Proxmox default."
},
"loggers": {
"heading": "Why two custom logger services",
"intro1": "Fail2Ban can read directly from the systemd journal (<code>backend = systemd</code>), but on Proxmox this backend has known reliability issues with <code>pvedaemon</code> worker processes (auth events appear in the journal but Fail2Ban doesn't always pick them up) and intermittently with <code>sshd</code>.",
"intro2": "The workaround: ProxMenux creates two tiny systemd services that <code>journalctl -f</code> the relevant units and append every line to a file. Fail2Ban then reads those files with the rock-solid <code>backend = auto</code> (file mode):",
"headerService": "Service",
"headerSource": "Source unit",
"headerOutput": "Output file",
"rows": [
{
"service": "proxmox-auth-logger.service",
"source": "pvedaemon.service",
"output": "/var/log/proxmox-auth.log"
},
{
"service": "ssh-auth-logger.service",
"source": "ssh.service",
"output": "/var/log/ssh-auth.log"
}
],
"outro": "Both services are declared <code>PartOf=fail2ban.service</code> so they restart with Fail2Ban and stop with it. Mode 640 owned by <code>root:adm</code> on the log files. The third log used by the <code>[proxmenux]</code> jail (<code>/var/log/proxmenux-auth.log</code>) is written directly by the ProxMenux Monitor Flask app — no logger service needed for that one."
},
"backend": {
"heading": "Firewall backend auto-detection",
"intro": "The installer probes the host: if <code>nft list ruleset</code> works, it picks <code>nftables</code> as the ban action. Otherwise it falls back to <code>iptables-multiport</code> / <code>iptables-allports</code>. The choice is written into <code>jail.local</code>:",
"code": "# nftables host\nbanaction = nftables\nbanaction_allports = nftables[type=allports]\n\n# iptables host (fallback)\nbanaction = iptables-multiport\nbanaction_allports = iptables-allports"
},
"hardening": {
"heading": "SSH hardening: MaxAuthTries",
"intro": "Lynis control <strong>SSH-7408</strong> recommends <code>MaxAuthTries 3</code> in <code>sshd_config</code>. With Fail2Ban's <code>maxretry = 2</code> on the SSH jail, a malicious client never reaches three attempts anyway — but the explicit setting satisfies the audit and adds defence in depth (e.g. if Fail2Ban is stopped for maintenance).",
"installerIntro": "The installer:",
"items": [
"Reads the current <code>MaxAuthTries</code> value (or defaults to 6 if absent).",
"Saves it to <code>/usr/local/share/proxmenux/sshd_maxauthtries_backup</code>.",
"Edits <code>sshd_config</code> in-place — replaces existing line, uncomments commented line, or appends.",
"Reloads <code>sshd</code> (reload, not restart, to keep existing sessions alive)."
],
"outro": "On uninstall, the saved original value is restored and <code>sshd</code> is reloaded again."
},
"manage": {
"heading": "Manage an existing install",
"intro": "If Fail2Ban is already installed when you open the menu, the script detects it and shows a manage menu instead of re-running the installer:",
"headerAction": "Action",
"headerWhat": "What it does",
"rows": [
{
"action": "Reinstall",
"what": "Re-runs the full installer — rewrites all jails with the current ProxMenux defaults. Use this after a ProxMenux update bumps the recommended values."
},
{
"action": "Remove",
"what": "Stops fail2ban and the two logger services, purges the apt package, removes all jail / filter files, deletes the journald drop-in (restoring the Proxmox default), and restores the original SSH MaxAuthTries."
}
]
},
"verify": {
"heading": "Verify it's working",
"intro": "After installation, useful commands from the host:",
"code": "# Service status and version\nsystemctl status fail2ban\nfail2ban-client --version\n\n# All active jails\nfail2ban-client status\n\n# Detail on one jail\nfail2ban-client status sshd\nfail2ban-client status proxmox\nfail2ban-client status proxmenux\n\n# Currently banned IPs in a jail\nfail2ban-client status sshd | grep \"Banned IP\"\n\n# Manually unban an IP (use this if you ban yourself)\nfail2ban-client unban 192.0.2.10\n\n# Tail the auth logs Fail2Ban watches\ntail -f /var/log/ssh-auth.log\ntail -f /var/log/proxmox-auth.log\ntail -f /var/log/fail2ban.log"
},
"troubleshoot": {
"heading": "Troubleshooting",
"neverBansTitle": "Fail2Ban runs but never bans anything",
"neverBansBody": "Check the auth log files actually receive entries: <code>tail -f /var/log/ssh-auth.log</code> and try a wrong-password SSH attempt from a different machine. If the log stays empty, the logger service is not running: <code>systemctl status ssh-auth-logger.service</code>. If it's active but the log is empty, check that the journald drop-in took effect: <code>journalctl --dump-catalog | head</code> — events at <em>info</em> level should be visible.",
"monitorEmptyTitle": "ProxMenux Monitor jail has no entries even after failed logins",
"monitorEmptyBody": "The <code>[proxmenux]</code> jail reads <code>/var/log/proxmenux-auth.log</code>, which is written by the ProxMenux Monitor Flask app — not by a journald logger. If you don't run the Monitor, the file stays empty and the jail never fires. That's expected; the jail config is harmless. If you do run the Monitor and the log is empty, check the Flask logging config.",
"selfBanTitle": "I banned myself",
"selfBanIntro": "From a console / IPMI / iKVM (or another whitelisted IP):",
"selfBanCode": "fail2ban-client unban '<'YOUR_IP'>'\n\n# To prevent it next time, edit /etc/fail2ban/jail.local and add your IP:\nignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 203.0.113.42\n\n# Then reload\nfail2ban-client reload",
"aptFailTitle": "apt-get fails: ''Unable to locate package fail2ban''",
"aptFailBody": "The host is missing the Debian repos (common on barebones Proxmox installs). The installer detects this and writes <code>/etc/apt/sources.list.d/debian.sources</code> with the right codename (<code>bookworm</code> / <code>trixie</code>) before retrying. If it still fails, check <code>/etc/os-release</code> for <code>VERSION_CODENAME</code> and confirm the repo URL is reachable.",
"lockoutTitle": "SSH locks me out after install",
"lockoutBody": "The installer sets <code>MaxAuthTries=3</code>. If your password manager / agent retries multiple keys, you may exceed that on a single connection attempt. Limit the keys offered: <code>ssh -o IdentitiesOnly=yes -i ~/.ssh/specific_key user@host</code>. Or temporarily raise <code>MaxAuthTries</code> in <code>sshd_config</code> while you debug."
},
"files": {
"heading": "Files written",
"code": "/etc/fail2ban/jail.local # global defaults + [sshd]\n/etc/fail2ban/jail.d/proxmox.conf # [proxmox]\n/etc/fail2ban/jail.d/proxmenux.conf # [proxmenux]\n/etc/fail2ban/filter.d/proxmox.conf # auth-failure regex for pvedaemon\n/etc/fail2ban/filter.d/proxmenux.conf # auth-failure regex for Monitor\n/etc/systemd/system/proxmox-auth-logger.service # journal → file (pvedaemon)\n/etc/systemd/system/ssh-auth-logger.service # journal → file (sshd)\n/etc/systemd/journald.conf.d/proxmenux-loglevel.conf # MaxLevelStore=info\n/etc/ssh/sshd_config # MaxAuthTries=3 (in-place edit)\n/var/log/proxmox-auth.log # written by logger service\n/var/log/ssh-auth.log # written by logger service\n/var/log/proxmenux-auth.log # written by Monitor Flask app\n/usr/local/share/proxmenux/sshd_maxauthtries_backup # for restore on uninstall"
},
"related": {
"heading": "Related",
"monitorLabel": "ProxMenux Monitor → Security tab",
"monitorTail": " — same install reachable from the dashboard, plus live jail status, banned IPs and per-jail retry / ban-time tuning from the browser.",
"lynisLabel": "Lynis",
"lynisTail": " — run a security audit before/after to confirm the SSH-7408 control is satisfied.",
"securityLabel": "Security overview",
"securityTail": " — back to the section overview."
}
}
+70
View File
@@ -0,0 +1,70 @@
{
"meta": {
"title": "Proxmox Security — Fail2Ban, Lynis Hardening Audit | ProxMenux",
"description": "Two installable security tools for Proxmox VE: Fail2Ban (intrusion prevention for SSH, the Proxmox web UI and the ProxMenux Monitor) and Lynis (security audit and hardening scanner installed from upstream GitHub).",
"ogTitle": "Proxmox Security — Fail2Ban, Lynis Hardening Audit",
"ogDescription": "Fail2Ban and Lynis for Proxmox VE — intrusion prevention plus a hardening audit installed and managed by ProxMenux.",
"twitterTitle": "Proxmox Security | ProxMenux",
"twitterDescription": "Fail2Ban and Lynis for Proxmox VE — intrusion prevention and hardening audit."
},
"header": {
"title": "Security",
"description": "Two complementary security tools for Proxmox VE: an active defence (Fail2Ban — bans IPs that attack SSH or the web UIs) and an offline audit (Lynis — scans the system for hardening gaps and gives a 0100 score). Both are installed and managed through their own dedicated menu, with detection of an existing install before any action.",
"section": "Security"
},
"intro": {
"title": "Active defence vs. offline audit",
"body": "These two tools answer different questions. <strong>Fail2Ban</strong> answers <em>\"is something attacking us right now?\"</em> by watching auth logs and banning offending IPs. <strong>Lynis</strong> answers <em>\"how hardened is this host?\"</em> by running a one-shot audit and printing concrete recommendations. Use both together: Lynis tells you what to fix, Fail2Ban handles the live abuse."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, select <strong>Security</strong>. You will see this:",
"imageAlt": "Security menu with Fail2Ban and Lynis options"
},
"pick": {
"heading": "Pick your tool",
"body": "The two security tools are independent — install either one, both, or neither. Each card below jumps to the section that explains the tool in detail."
},
"cards": {
"fail2ban": {
"title": "Fail2Ban",
"body": "Active intrusion prevention. Watches SSH and web UI auth logs and bans IPs after repeated failures.",
"bullets": [
"Three jails: SSH, Proxmox UI (8006), ProxMenux Monitor (8008)",
"Fixes Proxmox journald defaults that block auth logs",
"Auto-detects nftables / iptables",
"SSH hardening: MaxAuthTries=3 (Lynis recommendation)"
]
},
"lynis": {
"title": "Lynis",
"body": "Offline security auditor. Scans the host and prints a hardening score plus concrete remediation hints.",
"bullets": [
"Installed from upstream CISOfy GitHub (always latest)",
"Hardening score 0100 + list of warnings and suggestions",
"Run-audit and update actions in-menu",
"Read-only by design — never changes the system"
]
}
},
"workflowTip": {
"title": "Workflow that uses both",
"body": "Run a Lynis audit first to see your starting score and the top recommendations. Apply the fixes you want. Then install Fail2Ban — it implements one of Lynis's most common recommendations (SSH brute-force protection) automatically, and adjusts <code>MaxAuthTries</code> in <code>sshd_config</code> to satisfy the SSH-7408 control. Re-run Lynis afterwards to confirm the score improved."
},
"fail2banSection": {
"heading": "Fail2Ban",
"body": "ProxMenux installs Fail2Ban with a configuration tuned for Proxmox specifically. Beyond the standard SSH jail, it adds protection for the Proxmox web UI and the ProxMenux Monitor, and works around two Proxmox-specific quirks: a journald default that drops auth events, and the systemd-backend issue that prevents Fail2Ban from reading certain journal sources reliably. The detail page covers the full install flow, the three jails, the journald fix, the SSH hardening change and the troubleshooting cheatsheet.",
"optionTitle": "Fail2Ban — install & manage",
"optionDescription": "Three pre-configured jails (sshd aggressive, Proxmox UI port 8006, ProxMenux Monitor port 8008 + reverse proxy), auto-detected nftables/iptables backend, journald fix and SSH MaxAuthTries hardening."
},
"lynisSection": {
"heading": "Lynis",
"body": "ProxMenux clones Lynis from <code>github.com/CISOfy/lynis</code> into <code>/opt/lynis</code> and exposes it as <code>/usr/local/bin/lynis</code>. The Debian package is intentionally avoided because it lags several major versions behind upstream. The detail page covers the install / audit / update / uninstall flow, how to read the report, and how to act on the findings.",
"optionTitle": "Lynis — install, audit & manage",
"optionDescription": "Installs the latest Lynis from the official CISOfy GitHub repo (not the older Debian package), runs system audits with hardening score, and updates via git pull."
},
"componentStatus": {
"heading": "Component status",
"body": "Both installers register their state in <code>/usr/local/share/proxmenux/components_status.json</code> under the <code>security</code> category. ProxMenux uses this file to decide whether to show the install or the manage menu on subsequent runs, and the same data feeds the dashboards in the ProxMenux Monitor when present."
}
}
+170
View File
@@ -0,0 +1,170 @@
{
"meta": {
"title": "Lynis | ProxMenux Documentation",
"description": "Install Lynis from the official CISOfy GitHub repository (always latest), run a system audit with hardening score 0100, update via git pull. Read-only by design — never modifies the system.",
"ogTitle": "Lynis | ProxMenux Documentation",
"ogDescription": "Install and run the Lynis security auditor on Proxmox VE. Upstream GitHub install, audit, update."
},
"header": {
"title": "Lynis",
"description": "Clones the latest Lynis from the official CISOfy GitHub repository, exposes it as /usr/local/bin/lynis and offers run-audit / update / reinstall / uninstall actions from the menu. Read-only auditor by design — never modifies the system, only reports.",
"section": "Security"
},
"intro": {
"title": "What this does",
"body": "Installs Lynis (the open-source security auditor by CISOfy) from upstream GitHub into <code>/opt/lynis</code> and creates a wrapper at <code>/usr/local/bin/lynis</code> so it's in your <code>PATH</code>. Detects an existing install on launch and shows a manage menu (audit / update / reinstall / remove) instead."
},
"manageMenu": {
"heading": "Manage menu (after install)",
"intro": "Once Lynis is installed, every subsequent invocation opens the management menu instead of re-running the installer. From here you launch an audit, update via git pull, reinstall or uninstall:",
"imageAlt": "Lynis management menu with audit, update, reinstall and remove options"
},
"whyUpstream": {
"heading": "Why upstream GitHub, not apt",
"intro": "Debian ships Lynis through apt, but the package typically lags several major versions behind upstream. Newer controls, fixes for new attack vectors and refined recommendations only land in the GitHub repo. Lynis itself is a self-contained shell script — no compilation, no dependencies beyond <code>git</code> for the install — so cloning the repo is the canonical install method recommended by CISOfy themselves.",
"headerSource": "Source",
"headerPath": "Install path",
"headerUpdate": "Update method",
"headerFresh": "Version freshness",
"rows": [
{
"sourceRich": "<strong>ProxMenux (this script)</strong>",
"path": "/opt/lynis/",
"update": "git pull (in-menu)",
"fresh": "Latest upstream"
},
{
"sourceRich": "<strong>Debian apt</strong>",
"path": "/usr/bin/lynis",
"update": "apt upgrade",
"fresh": "Often months / years behind"
}
]
},
"install": {
"heading": "How the install works",
"node1Label": "github.com/CISOfy/lynis",
"node1Detail": "git clone\n(install git first if missing)",
"node2Label": "/opt/lynis/",
"node2Detail": "full repo\nincluding ./lynis script",
"node3Label": "/usr/local/bin/lynis",
"node3Detail": "wrapper:\ncd /opt/lynis && ./lynis $@",
"outro": "The wrapper is mandatory — Lynis insists on being run from its own directory because it loads relative paths for plugins and profile data. The wrapper hides that detail so <code>lynis audit system</code> just works from anywhere."
},
"detection": {
"heading": "Detection paths",
"intro": "Before showing the menu, the script checks three locations to decide if Lynis is already present:",
"items": [
"<code>/usr/local/bin/lynis</code> — wrapper installed by ProxMenux",
"<code>/opt/lynis/lynis</code> — direct path (in case the wrapper got removed)",
"<code>/usr/bin/lynis</code> — apt-installed version, if the user installed it that way previously"
],
"outro": "If any of these is found, the manage menu opens. The script <strong>does not</strong> uninstall an apt-installed Lynis — only the one it manages itself (<code>/opt/lynis</code> + the wrapper)."
},
"audit": {
"heading": "Run an audit",
"intro": "From the manage menu, choose <strong>Run security audit now</strong>. This is equivalent to executing:",
"code": "lynis audit system --no-colors",
"outro": "The audit takes 30 seconds to a few minutes depending on host size. Output streams directly to the terminal — there is no spinner. Lynis prints sections for each control category, marking each test as <ok>[ OK ]</ok>, <warn>[ WARNING ]</warn> or <sugg>[ SUGGESTION ]</sugg>. The summary at the end has the headline numbers:",
"summary": "================================================================================\n\n Lynis security scan details:\n\n Hardening index : 76 [############ ]\n Tests performed : 247\n Plugins enabled : 0\n\n Components:\n - Firewall [V]\n - Malware scanner [X]\n\n Lynis modules:\n - Compliance status [?]\n - Security audit [V]\n - Vulnerability scan [V]\n\n================================================================================"
},
"report": {
"heading": "Reading the report",
"intro": "The two important sections are <strong>Warnings</strong> (things you should fix soon) and <strong>Suggestions</strong> (recommendations to improve hardening). Each item carries a control ID like <code>SSH-7408</code> — useful when searching the Lynis docs for the rationale and the fix.",
"headerMarker": "Marker",
"headerMeaning": "Meaning",
"headerAction": "Action",
"rows": [
{
"markerRich": "<strong>OK</strong>",
"meaning": "Test passed",
"action": "Nothing"
},
{
"markerRich": "<strong>WARNING</strong>",
"meaning": "Real issue, fix recommended",
"action": "Read the control description, plan a fix"
},
{
"markerRich": "<strong>SUGGESTION</strong>",
"meaning": "Hardening improvement available",
"action": "Apply if it fits your threat model"
}
],
"outro": "Full report and machine-readable data are written to <code>/var/log/lynis.log</code> and <code>/var/log/lynis-report.dat</code> by Lynis itself."
},
"pairFail2ban": {
"title": "Pair with Fail2Ban",
"body": "SSH-7408 (MaxAuthTries) is one of the most common warnings. Installing <link>Fail2Ban</link> from ProxMenux clears it automatically because the installer sets <code>MaxAuthTries=3</code> as part of its SSH hardening step. Run Lynis again afterwards to confirm the warning is gone."
},
"update": {
"heading": "Update Lynis",
"body": "From the manage menu, <strong>Update Lynis to latest version</strong> runs <code>git pull --quiet</code> inside <code>/opt/lynis</code>. If the directory exists but isn't a Git checkout (e.g. someone copied the files in manually), the script falls back to a full reinstall."
},
"reinstall": {
"heading": "Reinstall / uninstall",
"headerAction": "Action",
"headerWhat": "What it does",
"rows": [
{
"actionRich": "<strong>Reinstall</strong>",
"whatRich": "Removes <code>/opt/lynis</code>, re-clones from GitHub, recreates the wrapper. Use this if the local checkout is corrupted."
},
{
"actionRich": "<strong>Remove</strong>",
"whatRich": "Deletes <code>/opt/lynis</code> and <code>/usr/local/bin/lynis</code>. Logs at <code>/var/log/lynis*</code> are kept (they're audit history). An apt-installed Lynis at <code>/usr/bin/lynis</code> is left untouched."
}
]
},
"cli": {
"heading": "Useful CLI options",
"intro": "Once installed, Lynis can be invoked directly from a shell with extra options not exposed by the menu:",
"code": "lynis show version # version + build date\nlynis show commands # list every available command\nlynis show details TEST-ID # explain a specific control\nlynis audit system --quick # skip slow tests (e.g. malware scan)\nlynis audit system --pentest # treat host as untrusted (more aggressive)\nlynis update info # check if a newer Lynis is available\n\n# Filter the report log for just the warnings\ngrep \"Warning\" /var/log/lynis.log\n\n# Same, for suggestions only\ngrep \"Suggestion\" /var/log/lynis.log"
},
"troubleshoot": {
"heading": "Troubleshooting",
"cloneTitle": "git clone fails during install",
"cloneBody": "The host needs network access and DNS to reach <code>github.com</code>. From a console: <code>curl -sI https://github.com</code> and <code>git ls-remote https://github.com/CISOfy/lynis.git</code> will reveal the actual error (DNS, TLS, proxy, repo URL). If a proxy is required, set <code>https_proxy</code> in the environment before re-running the menu.",
"notFoundTitle": "lynis: command not found after install",
"notFoundIntro": "The wrapper at <code>/usr/local/bin/lynis</code> was either not created or got removed. Quickest fix: reinstall from the menu. Manual fix:",
"notFoundCode": "cat > /usr/local/bin/lynis <<'EOF'\n#!/bin/bash\ncd /opt/lynis && ./lynis \"$@\"\nEOF\nchmod +x /usr/local/bin/lynis",
"sshTitle": "Audit prints \"Warning: Test SSH-7408 — MaxAuthTries set incorrectly\"",
"sshIntro": "The SSH daemon allows too many auth attempts per connection. Either install <link>Fail2Ban</link> from ProxMenux (which sets <code>MaxAuthTries=3</code> automatically) or edit <code>/etc/ssh/sshd_config</code> by hand:",
"sshCode": "sed -i 's/^#?MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config\nsystemctl reload sshd",
"scoreTitle": "Score went down after a Proxmox upgrade",
"scoreBody": "Run <code>lynis update info</code> first — a Lynis update may have added new controls that flag existing config. Update Lynis from the menu, re-audit, and address the new findings."
},
"files": {
"heading": "Files written",
"code": "/opt/lynis/ # full Lynis git checkout\n/usr/local/bin/lynis # wrapper script (cd + exec)\n/var/log/lynis.log # human-readable audit log (Lynis itself)\n/var/log/lynis-report.dat # machine-readable report (Lynis itself)"
},
"sample": {
"heading": "Sample report",
"intro": "ProxMenux Monitor packages each Lynis run into a multi-page PDF available from the <link>Security tab</link> in the dashboard. The first page is the executive summary — hardening score, system info, security posture overview. Subsequent pages list every warning with explanation and every suggestion ranked by impact, plus the package inventory used during the audit.",
"imageAlt": "First page of the Lynis Security Audit Report PDF — executive summary with Hardening Index 71/100, system information block, and security posture overview with firewall, malware scanner and installed packages count",
"captionPrefix": "First page of a sample report. The full PDF (",
"captionLink": "sample",
"captionSuffix": ") continues with detailed warnings, suggestions and the installed-packages list.",
"cli": "On the CLI side the same data is in <code>/var/log/lynis-report.dat</code> (machine-readable flat file) and <code>/var/log/lynis.log</code> (the human-readable run log). The PDF is generated on demand by ProxMenux Monitor — running <code>lynis</code> from the command line does not produce one."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/monitor/dashboard/security",
"label": "ProxMenux Monitor → Security tab",
"tail": " — run the audit, browse historical reports and download the PDF straight from the dashboard."
},
{
"href": "/docs/security/fail2ban",
"label": "Fail2Ban",
"tailRich": " — implements the SSH brute-force protection that Lynis recommends."
},
{
"href": "/docs/security",
"label": "Security overview",
"tail": " — back to the section overview."
}
]
}
}
@@ -0,0 +1,169 @@
{
"meta": {
"title": "HTTPS for ProxMenux Monitor — Proxmox host certificate or custom paths | ProxMenux",
"description": "Serve the ProxMenux Monitor over HTTPS using either the Proxmox host certificate (auto-detected, including the Let's Encrypt cert uploaded via the Proxmox ACME tab) or a custom certificate at any path on disk.",
"ogTitle": "HTTPS for ProxMenux Monitor — Proxmox host or custom certificate",
"ogDescription": "Enable HTTPS on port 8008 with the Proxmox host certificate or any custom .pem / .key pair."
},
"header": {
"title": "HTTPS for ProxMenux Monitor",
"description": "Turn HTTPS on for the Monitor (port 8008) using either the Proxmox host certificate the Monitor auto-detects, or a custom certificate located anywhere on disk. The Proxmox option transparently picks the ACME-uploaded certificate when present, so a Let's Encrypt cert managed by the Proxmox UI is reused without an extra renewal job.",
"section": "Security"
},
"intro": {
"title": "What this page covers",
"body": "How to switch the Monitor from HTTP to HTTPS in the Settings → Security panel, what each certificate source actually points at on disk, how the Proxmox option behaves when the host has a Let's Encrypt cert, and how to set custom paths if you manage certs outside Proxmox."
},
"wheresetting": {
"heading": "Where the setting lives",
"body": "Open the Monitor and go to <strong>Settings → Security → HTTPS / SSL</strong>. The panel shows the current state (HTTP or HTTPS), and on a host without HTTPS yet it lists the certificate sources the Monitor was able to detect.",
"imageAlt": "Settings → Security → HTTPS / SSL panel in the Monitor showing the HTTPS-off state, the auto-detected Proxmox certificate (subject, issuer, expiry) and the Use Custom Certificate option",
"caption": "Settings → Security → HTTPS / SSL panel before activation. The Monitor surfaces the cert Proxmox itself is using and offers it as a one-click source."
},
"twoways": {
"heading": "Two ways to enable HTTPS",
"proxmox": {
"title": "Use Proxmox certificate",
"summary": "One click. The Monitor reuses the certificate Proxmox VE itself serves on port 8006.",
"items": [
"Auto-detected — no path to type",
"Picks the ACME-uploaded cert if present, falls back to the self-signed default",
"Renewal happens through Proxmox; the Monitor follows automatically on next start"
]
},
"custom": {
"title": "Use custom certificate",
"summaryRich": "Point the Monitor at a <code>.pem</code> / <code>.key</code> pair anywhere on disk.",
"items": [
"Absolute paths only (the Monitor process must be able to read both)",
"Useful when certs come from <code>certbot</code>, <code>acme.sh</code> or a wildcard",
"You own the renewal — restart the Monitor service after the file changes"
]
}
},
"proxmoxCert": {
"heading": "Proxmox certificate — what it actually points at",
"intro": "Proxmox VE keeps two certificate pairs in <code>/etc/pve/local/</code>:",
"table": {
"headers": {
"file": "File",
"origin": "Origin",
"when": "When the Monitor uses it"
},
"rows": [
{
"fileRich": "<code>pveproxy-ssl.pem</code><br /><code>pveproxy-ssl.key</code>",
"originRich": "Custom certificate uploaded via the Proxmox UI — including the Let's Encrypt certificate issued under <em>Datacenter → Node → Certificates → ACME</em>.",
"when": "Preferred whenever both files exist. The Monitor will follow the cert Proxmox itself is serving."
},
{
"fileRich": "<code>pve-ssl.pem</code><br /><code>pve-ssl.key</code>",
"originRich": "Self-signed certificate generated at install time by the Proxmox PKI.",
"whenRich": "Fallback when no <code>pveproxy-ssl.pem</code> is present."
}
]
},
"callout": {
"title": "Same priority as Proxmox itself",
"bodyRich": "<code>pveproxy</code> uses the same selection rule, so picking the Proxmox option in the Monitor always serves the cert the Proxmox web UI is already serving on port 8006. No copying, no separate renewal pipeline."
}
},
"letsencrypt": {
"heading": "Getting a Let's Encrypt certificate via Proxmox ACME",
"intro": "Proxmox VE ships its own ACME client. Clicking <em>\"Order Certificate Now\"</em> writes the result to <code>/etc/pve/local/pveproxy-ssl.pem</code>, which is exactly what the Monitor reads. The five-step recipe below is the same procedure as the <extlink1>official Proxmox guide</extlink1> — distilled to the commands you actually need to run.",
"prereqs": {
"title": "Prerequisites",
"items": [
"The node has a real DNS name (not just an IP) pointing at it.",
"<strong>Either</strong> port 80 reachable from the public internet (HTTP-01 challenge, simplest), <strong>or</strong> a DNS provider with API credentials (DNS-01 challenge — works behind NAT, supports wildcards).",
"An email address for the ACME account."
]
},
"step1": {
"heading": "Step 1 — Register the ACME account",
"introRich": "Replace the email with yours. The account name <code>default</code> is just a label — you can use any string.",
"code": "pvenode acme account register default you@example.com",
"afterRich": "Proxmox prompts you to accept the Let's Encrypt terms of service. After that the account is persisted under <code>/etc/pve/priv/acme/</code> and the ACME tab in the GUI will show it."
},
"step2": {
"heading": "Step 2 — Pick a challenge type",
"http01Rich": "<strong>HTTP-01</strong> is the easiest: it's built in, no extra plugin. Let's Encrypt connects to <code>http://&lt;your-host&gt;/.well-known/acme-challenge/...</code> on port 80, so port 80 must be open from the public internet to your node — typically a port forward on your router.",
"dns01Rich": "<strong>DNS-01</strong> works without exposing port 80 (good for homelabs behind CG-NAT) and is the only option for wildcard certificates. You add a DNS plugin once with your provider's API token. Cloudflare example:",
"code": "pvenode acme plugin add dns cf \\\n --api cloudflare \\\n --data CF_Token=YOUR_CLOUDFLARE_API_TOKEN",
"outroRich": "For other providers (Gandi, OVH, AWS Route 53, etc.) check <code>pvenode acme plugin add dns --help</code> — Proxmox ships <extlink2>all acme.sh DNS plugins</extlink2>."
},
"step3": {
"heading": "Step 3 — Bind the domain to your node",
"http01Rich": "For HTTP-01 (uses the built-in <code>standalone</code> plugin):",
"code1": "pvenode config set --acme domains=host.example.com,account=default",
"dns01": "For DNS-01 with the Cloudflare plugin from Step 2:",
"code2": "pvenode config set --acmedomain0 domain=host.example.com,plugin=cf\npvenode config set --acme account=default",
"wildcardRich": "Wildcard? Add <code>domain=*.example.com</code> on a separate <code>--acmedomainN</code> entry. Wildcards require DNS-01."
},
"step4": {
"heading": "Step 4 — Order the certificate",
"code": "pvenode acme cert order",
"afterRich": "First run typically takes 3060 seconds while the challenge propagates. On success Proxmox writes <code>/etc/pve/local/pveproxy-ssl.pem</code> + <code>.key</code>, restarts <code>pveproxy</code>, and a renewal cron is scheduled automatically (Let's Encrypt certs are valid 90 days; Proxmox renews at 60)."
},
"step5": {
"heading": "Step 5 — Verify the issuer",
"code": "openssl x509 -in /etc/pve/local/pveproxy-ssl.pem -noout -issuer",
"afterRich": "Should print an issuer starting with <code>O = Let's Encrypt</code>. If it instead reads <code>CN = Proxmox Virtual Environment</code> the order failed and the file is still the self-signed PVE cert — re-run <code>pvenode acme cert order --debug 1</code> to see why."
},
"gui": {
"title": "Prefer the GUI? Same five steps",
"bodyRich": "<em>Datacenter → ACME</em> registers the account, <em>Datacenter → ACME → Plugins</em> adds the DNS plugin, <em>Node → Certificates → ACME</em> binds the domain, and <em>Order Certificates Now</em> runs Step 4. The CLI commands above are useful for scripting and for headless / CLI-only setups."
}
},
"switchToHttps": {
"heading": "Switch the Monitor to HTTPS",
"bodyRich": "Once <code>/etc/pve/local/pveproxy-ssl.pem</code> is signed by Let's Encrypt, the Monitor side is one click: open <strong>Settings → Security → HTTPS / SSL</strong>, confirm the issuer shown in the detected-certificate panel reads <em>Let's Encrypt</em> (and not the local Proxmox CA), and click <strong>Use Proxmox Certificate</strong>. The Monitor service restarts and the next browser load is HTTPS on port 8008 — no certificate warning, since the chain is publicly trusted."
},
"custom": {
"heading": "Custom certificate — when to use it",
"intro": "Click <strong>Use Custom Certificate</strong> to enter two absolute paths:",
"items": [
"<strong>Certificate</strong> — full chain in PEM (<code>.pem</code> or <code>.crt</code>).",
"<strong>Private key</strong> — matching key in PEM (<code>.key</code>)."
],
"outro": "Both files are read by the Monitor process at startup. Make sure they remain readable by the user the systemd unit runs as (root by default). Common locations when ACME is managed outside Proxmox:",
"code": "# certbot\n/etc/letsencrypt/live/<your-host>/fullchain.pem\n/etc/letsencrypt/live/<your-host>/privkey.pem\n\n# acme.sh\n~/.acme.sh/<your-host>_ecc/fullchain.cer\n~/.acme.sh/<your-host>_ecc/<your-host>.key",
"symlinkCallout": {
"title": "Symlink targets vs. files",
"bodyRich": "<code>certbot</code> stores the actual files in <code>/etc/letsencrypt/archive/</code> and the <code>live/</code> path is a symlink. Point the Monitor at the <code>live/</code> symlink, not the <code>archive/</code> file — that way each renewal cycle simply rewrites the symlink target and the Monitor picks up the new cert at the next service start."
}
},
"afterHttps": {
"heading": "After enabling HTTPS",
"bodyRich": "Saving the change writes <code>/etc/proxmenux/ssl_config.json</code> and triggers a restart of the <code>proxmenux-monitor</code> systemd unit. The browser tab will lose its current connection — reload it on <code>https://&lt;host&gt;:8008/</code>. The first load with a Let's Encrypt cert should show no warning; with the Proxmox self-signed cert the browser will require an exception, the same one as for port 8006.",
"reverse": {
"heading": "Reverse proxies and webhooks",
"bodyRich": "When the Monitor switches to HTTPS, Proxmox VE webhook URLs registered for notifications also flip from <code>http://</code> to <code>https://</code> automatically. Existing webhook entries are rewritten the next time a notification rule is saved or re-detected, so no manual edit of the Proxmox notification config is needed."
}
},
"trustCa": {
"heading": "Trust the Proxmox self-signed CA",
"intro1Rich": "If you prefer to keep the default Proxmox-generated certificate (no ACME), you can stop the browser warning by importing the cluster's root CA into the OS or browser trust store. The Monitor will keep auto-detecting the same <code>/etc/pve/local/pveproxy-ssl.pem</code>; the only thing that changes is that the device viewing the dashboard now recognises the issuer.",
"intro2Rich": "The CA file lives at <code>/etc/pve/pve-root-ca.pem</code> on every node. In a cluster the path is on the shared <code>pmxcfs</code> filesystem so all nodes share the same root, and a single import covers the whole datacenter. Copy it to your machine:",
"code": "scp root@<your-host>:/etc/pve/pve-root-ca.pem ./pve-root-ca.pem",
"thenImport": "Then import it on the client side:",
"items": [
"<strong>Linux (system-wide):</strong> <code>sudo cp pve-root-ca.pem /usr/local/share/ca-certificates/pve-root-ca.crt</code> followed by <code>sudo update-ca-certificates</code>. Browsers using the system store (Chromium, Edge) pick it up after restart; Firefox uses its own store and needs the manual import below.",
"<strong>macOS:</strong> double-click the <code>.pem</code> file, Keychain Access opens → add it to the <em>System</em> keychain → set <em>Trust → Always Trust</em>.",
"<strong>Windows:</strong> right-click the file → <em>Install Certificate</em> → place it in <em>Trusted Root Certification Authorities</em>.",
"<strong>Firefox (any OS):</strong> <em>Settings → Privacy &amp; Security → Certificates → View Certificates → Authorities → Import</em>, tick <em>Trust this CA to identify websites</em>."
],
"standalone": {
"title": "Standalone nodes outside a cluster",
"bodyRich": "Each non-clustered Proxmox host has its own <code>pve-root-ca.pem</code>. If you manage several standalone hosts, repeat the copy/import for each, or join them to a cluster so they share a single root."
}
},
"disable": {
"heading": "Disabling HTTPS",
"bodyRich": "Click <strong>Disable HTTPS</strong> in the same panel. The Monitor service restarts back on plain HTTP — useful if a custom certificate file becomes unreadable and the service won't come back up. There is no separate uninstall step; the cert files themselves are not touched.",
"stateCallout": {
"title": "Where the state lives",
"bodyRich": "<code>/etc/proxmenux/ssl_config.json</code> stores the active cert paths and the source (<code>none</code>, <code>proxmox</code>, <code>custom</code>). Deleting the file is equivalent to disabling HTTPS — on next start the Monitor falls back to HTTP."
}
}
}
@@ -0,0 +1,112 @@
{
"meta": {
"title": "Change Release Channel | ProxMenux Documentation",
"description": "Switch ProxMenux between the Stable (main) and Beta (develop) channels in one dialog. Bidirectional, idempotent, runs the official installer for the chosen channel and normalises the Monitor service.",
"ogTitle": "Change Release Channel | ProxMenux Documentation",
"ogDescription": "One Settings option to switch between Stable and Beta channels — no rerunning installers by hand."
},
"header": {
"title": "Change Release Channel",
"description": "One unified Settings option to switch ProxMenux between the Stable (main branch) and Beta (develop branch) channels. The previous one-way 'Deactivate Beta Program' has been replaced by a bidirectional dialog that always offers both directions and runs the official installer for whichever channel you pick.",
"section": "Settings"
},
"intro": {
"title": "What changed",
"body": "Earlier versions of ProxMenux exposed two separate flows — “Deactivate Beta Program” (only visible when beta was active) and a manual rerun of the beta installer to re-join. They are merged into a single <strong>Change Release Channel</strong> entry that is always present, shows the current channel and lets you flip between Stable and Beta in either direction."
},
"why": {
"heading": "Why this option exists",
"intro": "ProxMenux ships from two git branches:",
"items": [
"<strong>Stable</strong> — the <code>main</code> branch. What the README points at, what most operators want, with a slower release cadence and only changes that have already been through beta validation.",
"<strong>Beta</strong> — the <code>develop</code> branch. Newer features and Monitor builds; carries the tag the next stable release will inherit. Some things may not work perfectly — that's the deal you sign up for and the way new features get tested before they ship."
],
"outro": "Hopping between channels used to require remembering the right installer URL, copying it in from the README, and editing <code>config.json</code> by hand if something got out of sync. The unified option does the whole flow as a single guided action."
},
"dialog": {
"heading": "The dialog",
"intro": "From the main menu, <strong>Settings → Change Release Channel</strong>. A two-line menu shows up:",
"options": [
"<code>stable</code> — Stable (main branch)",
"<code>beta</code> — Beta (develop branch)"
],
"behaviour": "The current channel is pre-selected and shown at the top of the menu. Picking the same channel returns a friendly “This release channel is already active” message — the dialog is fully idempotent. Picking a different channel pops up a confirmation with channel-specific text:",
"directions": [
"<strong>Stable → Beta:</strong> warns that beta builds may contain bugs or incomplete features.",
"<strong>Beta → Stable:</strong> warns that beta update checks will stop and the stable installer will reinstall the Stable channel components."
]
},
"confirm": {
"heading": "What happens when you confirm",
"items": [
"<strong>Downloads the official installer</strong> for the target channel:<ul><li>Stable: <code>install_proxmenux.sh</code> from <code>main</code></li><li>Beta: <code>install_proxmenux_beta.sh</code> from <code>develop</code></li></ul>The download is verified to exist and made executable before the next step.",
"<strong>Runs the installer</strong> end-to-end. The installer is the same one the README publishes — no custom path, no shortcut. That means existing component detection, file backups, dependency installs, language preservation, etc. all behave identically to a fresh install of the target channel.",
"When switching to <strong>Stable</strong>, the menu then prunes any leftover beta metadata from <code>config.json</code>: <code>beta_program</code>, <code>beta_version</code>, <code>install_branch</code>, <code>update_available.beta*</code> are deleted, and <code>proxmenux_monitor.status = beta_updated</code> is normalised to <code>updated</code>. The leftover <code>beta_version.txt</code> file and any downloaded beta installer are removed.",
"When switching to Stable, the Monitor systemd unit file is also re-written from the Stable template (drops the “Beta” suffix from the unit description, points <code>ExecStart</code> back at the runtime dir) so a fresh <code>systemctl status</code> reflects the channel you're on.",
"Reloads the configuration menu. The next visit to <em>Show Version Information</em> will show the new channel."
]
},
"switching": {
"heading": "Switching back and forth",
"intro": "Both directions go through the same installer — they are <strong>not</strong> special-cased uninstall + reinstall flows. Each direction simply runs the channel's own installer, which is designed to be idempotent and safe to re-execute over an existing install. Practical consequences:",
"items": [
"Your existing config, ProxMenux Monitor login (<code>auth.json</code>), notification channels, post-install registry, custom thresholds — none of those are touched. The channel switch only swaps the script tree and the binary AppImage.",
"A Monitor that was active before the switch stays active after; one that was deactivated stays deactivated.",
"ProxMenux Monitor <code>auth.json</code>, API tokens and the JWT secret are preserved across channel changes. Sessions don't get logged out.",
"You can flip channels as many times as you like — the dialog will accept it every time and rerun the installer. No restart of Proxmox is required."
]
},
"feedback": {
"heading": "Reporting issues from the beta",
"intro": "If something behaves unexpectedly while you're on the Beta channel, opening an issue with enough context is what closes the gap to a stable release. The most useful report includes:",
"items": [
"What you did and what you expected to happen.",
"Any error messages shown on screen.",
"The relevant Monitor logs:"
],
"logsCommand": "journalctl -u proxmenux-monitor -n 50 --no-pager",
"versionLine": "The current ProxMenux version (Settings → <link>Show Version Information</link>).",
"issueLine": "Open a <ghlink>GitHub Issue</ghlink> with that information and we get to the fix faster."
},
"manual": {
"heading": "Manual equivalent",
"intro": "If you prefer the shell or are scripting the channel switch, the dialog is just a thin wrapper around these commands:"
},
"unifiedCallout": {
"title": "Why both directions are now one option",
"body": "The previous “Deactivate Beta Program” only existed if the host had ever joined the beta. Operators wanting to <em>join</em> had to find the beta installer URL elsewhere; operators wanting to <em>leave</em> sometimes had to manually clean up <code>beta_*</code> metadata to be sure. The unified <strong>Change Release Channel</strong> option always shows up, makes the current channel explicit, and treats both directions as the same kind of operation — runnable, repeatable, idempotent."
},
"troubleshoot": {
"heading": "Troubleshooting",
"downloadTitle": "“Could not download the installer”",
"downloadBody": "Outbound HTTPS to <code>raw.githubusercontent.com</code> failed. Check connectivity and DNS from the host:",
"downloadCmd": "curl -fsSL -o /tmp/test https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh && head -1 /tmp/test",
"downloadOutro": "If this fails outside ProxMenux, it's a network / proxy issue on the host.",
"errorsTitle": "“Installer finished with errors”",
"errorsBody": "The installer surfaced a non-zero exit code. The previous channel and any already-installed components are left as they were before the switch. Re-run the action; if it keeps failing, run the installer manually from a shell (see the manual equivalent above) — that gives you the full output instead of the dialog summary.",
"configTitle": "“Could not update config file” after switching to Stable",
"configBody": "The post-install cleanup of beta metadata failed — usually because <code>config.json</code> has a syntax error from a manual edit. Validate it:",
"configCmd": "jq . /usr/local/share/proxmenux/config.json",
"configOutro": "Fix or restore the file and rerun the option."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/settings/show-version-information",
"label": "Show Version Information",
"tail": " — confirm which channel is active now."
},
{
"href": "/docs/settings/proxmenux-monitor",
"label": "ProxMenux Monitor",
"tail": " — the Monitor service that gets rebuilt as part of the switch."
},
{
"href": "/docs/settings",
"label": "Settings overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,98 @@
{
"meta": {
"title": "Change Language | ProxMenux Documentation",
"description": "Switch ProxMenux UI between English, Spanish, French, German, Italian or Portuguese. Translation install only — uses googletrans + a pre-cached translation table. The menu reloads automatically with the new language.",
"ogTitle": "Change Language | ProxMenux Documentation",
"ogDescription": "Pick the ProxMenux interface language from the Settings menu. Six languages supported."
},
"header": {
"title": "Change Language",
"description": "Switch the ProxMenux UI between six supported languages. Saves the choice to config.json and re-execs the menu with the new language. Only available on the Translation install type — the Normal (lightweight) install is English-only by design.",
"section": "Settings"
},
"intro": {
"title": "What this is",
"body": "A dialog menu that lists the six supported languages. Pick one, ProxMenux saves it to <code>config.json</code> as <code>.language</code>, then re-execs <code>config_menu.sh</code> so the new language takes effect immediately."
},
"warn": {
"title": "Translation install only",
"body": "This option only appears in Settings if both checks pass: <code>/opt/googletrans-env/bin/activate</code> exists (Python venv with googletrans), <em>and</em> <code>config.json</code> has a non-empty <code>.language</code>. On the Normal (English-only) install neither is present and the language picker is not shown."
},
"supported": {
"heading": "Supported languages",
"headerCode": "Code",
"headerLang": "Language",
"headerNotes": "Notes",
"rows": [
{
"code": "en",
"lang": "English",
"notes": "Source language — most accurate"
},
{
"code": "es",
"lang": "Spanish",
"notes": "Cached + auto-translated"
},
{
"code": "fr",
"lang": "French",
"notes": "Cached + auto-translated"
},
{
"code": "de",
"lang": "German",
"notes": "Cached + auto-translated"
},
{
"code": "it",
"lang": "Italian",
"notes": "Cached + auto-translated"
},
{
"code": "pt",
"lang": "Portuguese",
"notes": "Cached + auto-translated"
}
]
},
"englishTip": {
"title": "English is the most accurate",
"body": "Non-English strings are produced by a pre-cached table seeded from googletrans. Edge-case strings (rarely triggered options, recent additions) may fall through to a live googletrans call or to the English original. If a translation feels off, English is always the source of truth."
},
"underHood": {
"heading": "How it works under the hood",
"items": [
"Dialog menu lists the 6 codes; you pick one.",
"If <code>config.json</code> exists: <code>jq --arg lang \"$new_language\" '.language = $lang'</code> updates the field in place.",
"If <code>config.json</code> doesn't exist: a fresh one is created with the language code in a single-field object.",
"Confirmation dialog: <em>\"Language changed to &lt;code&gt;\"</em>.",
"<code>exec bash config_menu.sh</code> reloads the Settings menu with the new language active."
]
},
"manual": {
"heading": "Manual equivalent"
},
"troubleshoot": {
"heading": "Troubleshooting",
"noOptionTitle": "Option doesn't appear in Settings",
"noOptionBody": "You're on the Normal (English-only) install. To get language support, reinstall ProxMenux choosing the Translation install option (it pulls Python venv + googletrans).",
"stillEnglishTitle": "Language changed but UI still shows English",
"stillEnglishBody": "The menu re-execs itself after the change. If you opened a fresh shell and started a different ProxMenux entrypoint, run <code>menu</code> again to pick up the new language. Confirm: <code>jq -r '.language' /usr/local/share/proxmenux/config.json</code>."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/settings/show-version-information",
"label": "Show Version Information",
"tail": " — confirms install type and current language."
},
{
"href": "/docs/settings",
"label": "Settings overview",
"tail": "."
}
]
}
}
+81
View File
@@ -0,0 +1,81 @@
{
"meta": {
"title": "ProxMenux Settings — Monitor Activation, Release Channel, Languages | ProxMenux",
"description": "ProxMenux configuration menu: ProxMenux Monitor activation and service toggle, Reset Monitor Password, Change Release Channel between Stable and Beta, language selection (translation install), version information and uninstall. Options appear conditionally based on what is installed and active.",
"ogTitle": "ProxMenux Settings — Monitor Activation, Release Channel, Languages",
"ogDescription": "Configure ProxMenux — Monitor service, Release Channel, language, version info and uninstall.",
"twitterTitle": "ProxMenux Settings",
"twitterDescription": "Monitor activation, Release Channel switch, languages, version info and uninstall."
},
"header": {
"title": "Settings",
"description": "ProxMenux configuration menu. Lists what's installed, lets you toggle the Monitor service, reset the Monitor login password, switch between Stable and Beta release channels in either direction, change the UI language (Translation install only), and provides a clean uninstaller. Options appear conditionally — what you see depends on your install type and current state.",
"section": "Settings"
},
"intro": {
"title": "What this menu is for",
"body": "Self-administration of ProxMenux itself: monitor service, beta channel opt-out, language, version diagnostics and the uninstaller. Nothing in this menu touches your VMs, containers or storage."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, press <kbd>s</kbd>. The options shown depend on your install type and on what is currently active:",
"imageAlt": "Settings ProxMenux menu with conditional options based on install type and component state"
},
"installTypes": {
"heading": "Two install types, different menus",
"intro": "ProxMenux ships in two flavours. The Settings menu adapts to which one you have:",
"headerType": "Install type",
"headerBundles": "What it bundles",
"headerMenu": "Menu shows",
"rows": [
{
"type": "Translation",
"bundles": "Python venv + googletrans + multi-language config",
"menuRich": "<strong>Change Language</strong> + Show Version + Uninstall"
},
{
"type": "Normal (lightweight)",
"bundles": "English-only, no venv, smaller footprint",
"menu": "Show Version + Uninstall (no language picker)"
}
],
"detectionTitle": "Detection happens automatically",
"detectionBody": "The script checks for <code>/opt/googletrans-env/bin/activate</code> and a non-empty <code>language</code> key in <code>config.json</code>. Both present → Translation install. Either missing → Normal install. You don't choose; the menu adapts."
},
"options": {
"heading": "Menu options",
"intro": "Five tools. The <em>Conditional</em> badges mean the option only appears when the prerequisite is met (Monitor installed; Beta program active; Translation install).",
"list": [
{
"icon": "Activity",
"href": "/docs/settings/proxmenux-monitor",
"title": "ProxMenux Monitor",
"description": "Activate / deactivate the proxmenux-monitor.service systemd unit, check its current state, and reset the dashboard login password if it's been lost. Web UI available on TCP 8008.",
"badge": "Conditional"
},
{
"icon": "TestTube",
"href": "/docs/settings/beta-program",
"title": "Change Release Channel",
"description": "Switch between Stable (main) and Beta (develop) in either direction from a single dialog. Runs the official installer for the chosen channel; idempotent and always visible.",
"badge": "Always available"
},
{
"icon": "Info",
"href": "/docs/settings/show-version-information",
"title": "Show Version Information",
"description": "ProxMenux version, install type, installed components, file paths, virtual environment state and current language."
},
{
"icon": "Trash2",
"href": "/docs/settings/uninstall-proxmenux",
"title": "Uninstall ProxMenux",
"description": "Remove ProxMenux and (optionally) its dependencies. Also restores /root/.bashrc and /etc/motd backups created at install time."
}
]
},
"configTip": {
"title": "Where the config lives",
"bodyRich": "Most state managed by this menu lives in <code>/usr/local/share/proxmenux/config.json</code> — <code>language</code>, <code>beta_program.status</code> and per-component install flags. The Monitor service's state lives in systemd (<code>proxmenux-monitor.service</code>), not here. Version is read from <code>/usr/local/share/proxmenux/version.txt</code>."
}
}
@@ -0,0 +1,119 @@
{
"meta": {
"title": "ProxMenux Monitor | ProxMenux Documentation",
"description": "Activate or deactivate the proxmenux-monitor.service systemd unit and inspect its current state. The Monitor exposes a web UI on TCP 8008 for visual host monitoring.",
"ogTitle": "ProxMenux Monitor | ProxMenux Documentation",
"ogDescription": "Toggle the proxmenux-monitor systemd service and check its status from the Settings menu."
},
"header": {
"title": "ProxMenux Monitor",
"description": "Two related actions inside the Settings menu: toggle the proxmenux-monitor.service systemd unit (start / stop and enable / disable in one click), and view its current detailed status. The Monitor exposes a web UI on TCP 8008 for visual host monitoring.",
"section": "Settings"
},
"intro": {
"title": "What is ProxMenux Monitor?",
"body": "ProxMenux Monitor is an integrated web dashboard that provides real-time visibility into your Proxmox infrastructure — accessible from any browser on your network, without needing a terminal."
},
"offers": {
"heading": "What it offers",
"items": [
"Real-time monitoring of CPU, RAM, disk usage and network traffic.",
"Overview of running VMs and LXC containers with status indicators.",
"Login authentication to protect access.",
"Two-Factor Authentication (2FA) with TOTP support.",
"Reverse proxy support (Nginx / Traefik).",
"Designed to work across desktop and mobile devices."
]
},
"access": {
"heading": "Access",
"intro": "Once installed, the dashboard is available at:",
"url": "http://<your-proxmox-ip>:8008",
"outro": "The Monitor is installed automatically as part of the standard ProxMenux installation and runs as a systemd service (<code>proxmenux-monitor.service</code>) that starts automatically on boot."
},
"warnConditional": {
"title": "Settings options only visible when Monitor is installed",
"body": "The two menu entries described below only appear in Settings if <code>proxmenux-monitor.service</code> is registered with systemd. If you don't see them, the Monitor wasn't installed (it's optional during ProxMenux install). To add it later, reinstall ProxMenux with the latest version and pick the Monitor option."
},
"toggle": {
"heading": "Activate / Deactivate",
"intro": "The first menu entry is a single toggle that flips between two states based on whether the service is currently running:",
"headerState": "Current state",
"headerLabel": "Menu label shown",
"headerAction": "Action on confirm",
"rows": [
{
"state": "active",
"label": "Deactivate ProxMenux Monitor",
"action": "systemctl stop + disable"
},
{
"state": "inactive",
"label": "Activate ProxMenux Monitor",
"action": "systemctl enable + start"
}
],
"outro": "Each toggle requires an explicit yes/no dialog before running. Activate / Deactivate is symmetric: deactivating stops the service <em>and</em> disables auto-start at boot; activating enables auto-start <em>and</em> starts the service immediately."
},
"status": {
"heading": "Show Monitor Service Status",
"intro": "The second menu entry is read-only. It clears the screen, shows the ProxMenux logo and the title <em>\"ProxMenux Monitor Service Verification\"</em>, then reports:",
"items": [
"<strong>Service status:</strong> active, inactive or not_installed.",
"<strong>Web UI URL</strong> (only when active): <code>http://&lt;host_ip&gt;:8008</code> — derived from <code>hostname -I | awk '''{print $1}'''</code>.",
"<strong>Detailed systemd output:</strong> <code>systemctl status proxmenux-monitor.service --no-pager -l</code> — shows recent log lines, ExecStart, MainPID, etc."
]
},
"manual": {
"title": "Manual equivalents",
"intro": "From any shell:",
"code": "systemctl status proxmenux-monitor.service # detailed status\nsystemctl is-active proxmenux-monitor.service # one-word status\nsystemctl enable --now proxmenux-monitor.service # enable + start\nsystemctl disable --now proxmenux-monitor.service # stop + disable\njournalctl -u proxmenux-monitor.service -f # follow live logs"
},
"reset": {
"heading": "Reset ProxMenux Monitor Password",
"intro": "Recovery path for the operator who lost the dashboard password (or 2FA device). The option only appears when the Monitor is installed on the host. Selecting it:",
"items": [
"Asks for confirmation with a yes/no dialog — the action is destructive for the login credentials.",
"Backs up the existing <code>/root/.config/proxmenux-monitor/auth.json</code> to <code>auth.json.bak-&lt;UTC timestamp&gt;</code> (mode <code>0600</code>) so the previous state can be restored manually if the reset was a mistake.",
"Stops the <code>proxmenux-monitor</code> service so the on-disk edit can't race with an in-flight login.",
"Clears the identity fields in <code>auth.json</code>: <code>enabled=false</code>, <code>configured=false</code>, empties <code>username</code>, <code>password_hash</code>, <code>totp_secret</code> and the backup codes array.",
"<strong>Preserves</strong> the <code>jwt_secret</code> and the registered <code>api_tokens</code> / <code>revoked_tokens</code> — so long-lived API tokens used by Home Assistant or other scripts <em>continue to authenticate</em> after the reset.",
"Restarts the service. The next visit to <code>http://&lt;host&gt;:8008</code> shows the first-launch setup wizard so a fresh admin account can be created."
],
"preservedTitle": "What survives the reset, what doesn't",
"preservedBody": "<strong>Wiped:</strong> username, password hash, 2FA TOTP secret, backup codes. <strong>Preserved:</strong> <code>jwt_secret</code>, <code>api_tokens</code> metadata, <code>revoked_tokens</code> list. If you actively want to also invalidate every existing API token (full clean slate), delete <code>auth.json</code> manually instead of using this menu option — the next start of the service regenerates the JWT secret and everything else from scratch.",
"trustTitle": "Physical-host access is the trust anchor",
"trustBody": "This reset path requires root shell on the host. Anyone who can run the <code>menu</code> command as root already controls the box, so giving them password recovery is not a privilege escalation — it's consistent with how every other admin tool on Proxmox works. The corollary: the Monitor login won't protect anything from someone you've already let into the Proxmox shell.",
"seeAlso": "See also <link>Monitor → Access &amp; Auth → Recovering a lost password</link> for the same flow described from the dashboard side, plus the wider context on how passwords are hashed and how the JWT secret is generated."
},
"files": {
"heading": "Files involved",
"code": "/etc/systemd/system/proxmenux-monitor.service # systemd unit\n/root/.config/proxmenux-monitor/ # runtime config dir\n/var/log/proxmenux-auth.log # Flask app auth log\n # (read by Fail2Ban [proxmenux] jail)"
},
"troubleshoot": {
"heading": "Troubleshooting",
"missingTitle": "Both menu options are missing",
"missingBody": "The Monitor isn't registered with systemd. Confirm with <code>systemctl list-unit-files | grep proxmenux-monitor</code> — if there's no output, reinstall ProxMenux from the official installer with the latest version and pick the Monitor option during install.",
"unreachableTitle": "Service activated but the URL is unreachable",
"unreachableBody": "The Settings status output gives you the IP. Confirm:",
"unreachableCmd": "ss -tlnp | grep 8008 # is anything listening?\njournalctl -u proxmenux-monitor -n 100 --no-pager # recent errors\ncurl -sI http://localhost:8008 # local reachability",
"unreachableOutro": "If localhost works but external doesn't, check your host firewall (<code>pve-firewall</code> or nftables) for inbound TCP 8008.",
"stopsTitle": "Activated the service but it stops itself a few seconds later",
"stopsBody": "Most often a port conflict (something else on 8008) or a dependency check failing. The journal will say which: <code>journalctl -u proxmenux-monitor.service -b</code>."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/security/fail2ban",
"label": "Fail2Ban",
"tailRich": " — the <code>[proxmenux]</code> jail protects the Monitor on TCP 8008."
},
{
"href": "/docs/settings",
"label": "Settings overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,81 @@
{
"meta": {
"title": "Show Version Information | ProxMenux Documentation",
"description": "Read-only ProxMenux self-diagnostic: version number, install type (Translation / Normal), installed components from config.json, file paths, virtual environment state and current language.",
"ogTitle": "Show Version Information | ProxMenux Documentation",
"ogDescription": "Diagnostic dump of ProxMenux version, install type, components, files and language."
},
"header": {
"title": "Show Version Information",
"description": "Read-only diagnostic. Reads version.txt, config.json and a few well-known file paths, then renders a scrollable text box with version, install type, installed components, file presence, virtual environment state and current language.",
"section": "Settings"
},
"intro": {
"title": "What this is",
"body": "A self-diagnostic. Useful when reporting an issue (paste the dialog contents into the bug report) or to confirm an install completed cleanly. Modifies nothing."
},
"reports": {
"heading": "What it reports",
"headerSection": "Section",
"headerSource": "Source",
"headerContent": "Content",
"rows": [
{
"section": "Current version",
"source": "version.txt",
"contentRich": "Single-line version number; <code>Unknown</code> if file missing"
},
{
"section": "Install type",
"source": "venv + config.json checks",
"content": "Translation (multi-language) or Normal (English-only)"
},
{
"section": "Installed components",
"source": "config.json",
"content": "Per-component status (✓ installed / created / upgraded, ✗ missing)"
},
{
"section": "ProxMenux files",
"source": "filesystem checks",
"contentRich": "<code>menu</code>, <code>utils.sh</code>, <code>config.json</code>, <code>version.txt</code> presence + paths"
},
{
"section": "Virtual environment",
"source": "/opt/googletrans-env",
"content": "Translation install only — venv + pip presence"
},
{
"section": "Current language",
"source": "config.json",
"contentRich": "Translation: language code from <code>.language</code>; Normal: <code>English (Fixed)</code>"
}
]
},
"sampleHeading": "Sample output",
"manualHeading": "Manual equivalents",
"troubleshoot": {
"heading": "Troubleshooting",
"unknownTitle": "Version shows \"Unknown\"",
"unknownBody": "<code>/usr/local/share/proxmenux/version.txt</code> is missing or unreadable. Most often caused by a partial install. Reinstall from the official ProxMenux source.",
"noConfigTitle": "No installation information available",
"noConfigBody": "<code>config.json</code> is missing. The script can't enumerate components without it. Reinstall to regenerate.",
"wrongStatusTitle": "A component shows ✗ that I'm sure I installed",
"wrongStatusBody": "Means <code>config.json</code> doesn't track that component as installed — could be a script that doesn't register itself yet, or a manual install that bypassed ProxMenux. The dialog reflects what <code>config.json</code> says, not what's actually on disk."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/settings/uninstall-proxmenux",
"label": "Uninstall ProxMenux",
"tail": " — remove all of these files."
},
{
"href": "/docs/settings",
"label": "Settings overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,92 @@
{
"meta": {
"title": "Uninstall ProxMenux | ProxMenux Documentation",
"description": "Clean ProxMenux uninstaller with optional dependency removal (jq, dialog, python3-*) and automatic restoration of /root/.bashrc and /etc/motd backups created at install time. Also removes the proxmenux-monitor service if present.",
"ogTitle": "Uninstall ProxMenux | ProxMenux Documentation",
"ogDescription": "Cleanly remove ProxMenux from a Proxmox host with optional dependency cleanup."
},
"header": {
"title": "Uninstall ProxMenux",
"description": "Removes ProxMenux from the Proxmox host with an interactive flow: confirmation, optional dependency removal, ProxMenux Monitor service cleanup, restoration of /root/.bashrc and /etc/motd backups. Shows a progress bar throughout.",
"section": "Settings"
},
"scopeWarn": {
"title": "Affects the ProxMenux install only — not your VMs / CTs / storage",
"body": "Uninstalling ProxMenux removes the ProxMenux scripts, the menu launcher, the optional Monitor service and any backups ProxMenux took of system files when you installed it. <strong>It does not touch your VMs, containers, storage, network configuration, Fail2Ban, NVIDIA driver or anything else you installed via ProxMenux.</strong> Those stay as they are."
},
"flow": {
"heading": "The uninstall flow",
"items": [
"<strong>Confirmation dialog.</strong> Yes/no — “Are you sure you want to uninstall ProxMenux?”",
"<strong>Dependency removal checklist.</strong> Pre-selected list depends on install type (see table below). All boxes default to OFF — you opt in to removing each dependency.",
"<strong>Removal runs with a progress bar.</strong> Removes the venv (Translation install only), the <code>menu</code> launcher, the <code>/usr/local/share/proxmenux/</code> tree, the ProxMenux Monitor service if present, the dependencies you ticked, and finally restores the system file backups (see below).",
"<strong>Completion dialog.</strong> Lists removed dependencies and exits."
]
},
"deps": {
"heading": "Dependency removal: what's offered",
"intro": "The checklist depends on install type. <strong>None of the boxes is checked by default</strong> — these are system-wide packages that other applications might use, so the safer default is to leave them.",
"headerType": "Install type",
"headerOffered": "Offered for removal",
"rows": [
{
"type": "Translation",
"offeredRich": "<code>python3-venv</code>, <code>python3-pip</code>, <code>python3</code>, <code>jq</code>"
},
{
"type": "Normal",
"offeredRich": "<code>dialog</code>, <code>jq</code>"
}
],
"warnTitle": "System-wide packages — think twice",
"warnBody": "<code>python3</code>, <code>jq</code> and <code>dialog</code> are commonly used by other tools (including Proxmox itself in some workflows). Removing <code>python3</code> in particular can break Proxmox helpers, Ceph utilities and many third-party scripts. Leave them unless you're positive nothing else needs them."
},
"removed": {
"heading": "What gets removed",
"code": "/usr/local/bin/menu # the launcher\n/usr/local/share/proxmenux/ # everything: scripts, config, cache, version\n/opt/googletrans-env/ # virtual env (Translation install only)\n/etc/systemd/system/proxmenux-monitor.service # Monitor service unit\n/root/.config/proxmenux-monitor/ # Monitor config dir\n # + dependencies you ticked in the checklist"
},
"restored": {
"heading": "What gets restored",
"items": [
"If <code>/root/.bashrc.bak</code> exists → renamed back to <code>/root/.bashrc</code> (your original bashrc returns).",
"If <code>/etc/motd.bak</code> exists → renamed back to <code>/etc/motd</code>. Otherwise the ProxMenux line (<em>“This system is optimised by: ProxMenux”</em>) is stripped from the existing motd with sed."
]
},
"othersCallout": {
"title": "Other ProxMenux-installed components stay",
"body": "Anything ProxMenux installed via other menus — Fail2Ban, Lynis, NVIDIA drivers, post-install tweaks — is <strong>not</strong> touched by this uninstaller. Each has its own uninstall flow inside its respective menu (or you can remove with apt directly). Look at <em>Show Version Information</em> first to see what's registered."
},
"manual": {
"heading": "Manual uninstall",
"intro": "If for some reason the menu uninstaller can't run (e.g. <code>dialog</code> already missing), the equivalent manual sequence:",
"code": "# 1. Stop and remove the Monitor service (if installed)\nsystemctl stop proxmenux-monitor.service 2>/dev/null\nsystemctl disable proxmenux-monitor.service 2>/dev/null\nrm -f /etc/systemd/system/proxmenux-monitor.service\nrm -rf /root/.config/proxmenux-monitor\nsystemctl daemon-reload\nsystemctl reset-failed 2>/dev/null\n\n# 2. Remove the venv (Translation install only)\nrm -rf /opt/googletrans-env\n\n# 3. Remove ProxMenux files\nrm -f /usr/local/bin/menu\nrm -rf /usr/local/share/proxmenux\n\n# 4. Restore backups\n[ -f /root/.bashrc.bak ] && mv /root/.bashrc.bak /root/.bashrc\n[ -f /etc/motd.bak ] && mv /etc/motd.bak /etc/motd \\\n || sed -i '/This system is optimised by: ProxMenux/d' /etc/motd"
},
"reinstall": {
"heading": "Reinstalling later",
"body": "Run the official ProxMenux installer again. Pick Translation or Normal as you prefer — the choice is independent of what you had before."
},
"troubleshoot": {
"heading": "Troubleshooting",
"hangTitle": "Uninstall hangs at “Removing googletrans and virtual environment”",
"hangBody": "<code>pip uninstall</code> can stall if pip is unresponsive. From another shell: <code>rm -rf /opt/googletrans-env</code> directly (the script does the same as a fallback after pip).",
"aptTitle": "apt warns about packages still in use during dependency removal",
"aptBody": "Expected if you ticked <code>python3</code> or <code>jq</code> while other things on the host depend on them. apt's <code>autoremove</code> will refuse to remove them in that case (which is the safe behaviour). Untick that dependency and re-run.",
"motdTitle": "MOTD still shows the ProxMenux line after uninstall",
"motdBody": "Either no <code>/etc/motd.bak</code> existed and the sed strip didn't match (e.g. the line was modified). Edit <code>/etc/motd</code> by hand and remove any leftover ProxMenux line."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/settings/show-version-information",
"label": "Show Version Information",
"tail": " — see what would be removed before uninstalling."
},
{
"href": "/docs/settings",
"label": "Settings overview",
"tail": "."
}
]
}
}
@@ -0,0 +1,123 @@
{
"meta": {
"title": "Host: Add iSCSI target as Proxmox storage | ProxMenux Documentation",
"description": "Register an iSCSI target as Proxmox storage using ProxMenux. Handles open-iscsi install, portal discovery via sendtargets, target selection and pvesm add iscsi. Provides raw block devices for VM disk images.",
"ogTitle": "Host: Add iSCSI target as Proxmox storage | ProxMenux Documentation",
"ogDescription": "Register an iSCSI target as Proxmox storage with guided discovery. Uses pvesm add iscsi and provides raw block devices for VM disks."
},
"header": {
"title": "Host: Add iSCSI target as Proxmox storage",
"description": "Register an iSCSI target (from a SAN, TrueNAS / FreeNAS, Synology, a Windows Server target, any array that speaks iSCSI) as Proxmox storage. The exported LUNs appear as block devices and can host VM disk images at near-local performance over the network.",
"section": "Storage & Share · Host"
},
"intro": {
"title": "What this does",
"body": "ProxMenux wraps <code>pvesm add iscsi</code> with a guided flow: it installs <code>open-iscsi</code> if needed, asks for the iSCSI portal (IP:port), runs <code>iscsiadm --mode discovery --type sendtargets</code> against it, lets you pick a target IQN, and registers the iSCSI storage in Proxmox. The <code>iscsid</code> service then keeps the iSCSI session alive across reboots."
},
"vocab": {
"heading": "iSCSI vocabulary (quick reference)",
"headerTerm": "Term",
"headerMeaning": "Meaning",
"rows": [
{
"term": "Portal",
"meaningRich": "The iSCSI service endpoint on the target server — an IP (or hostname) plus a TCP port. Default port is <code>3260</code>; ProxMenux assumes it if you do not specify one."
},
{
"term": "Target",
"meaningRich": "A single exported \"server\" inside the portal, identified by its IQN (<em>iSCSI Qualified Name</em>). One portal can host many targets."
},
{
"term": "IQN",
"meaningRich": "Canonical form is <code>iqn.YYYY-MM.reverse.domain:identifier</code>, for example <code>iqn.2024-08.com.truenas:proxmox-pool</code>. Both the target and the initiator have their own IQN."
},
{
"term": "LUN",
"meaningRich": "A block device inside a target (Logical Unit Number). A single target can expose several LUNs; each LUN appears as its own disk in Proxmox and can become a VM disk."
},
{
"term": "Initiator",
"meaningRich": "The client that connects to a target — in this case, your Proxmox host. The initiator has its own IQN stored in <code>/etc/iscsi/initiatorname.iscsi</code>. Targets typically only accept sessions from pre-authorised initiator IQNs."
}
]
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Add iSCSI Target as Proxmox Storage</strong>. You will see this sub-menu with four options:",
"imageAlt": "iSCSI Host Manager menu — Add / View / Remove / Test connectivity"
},
"howRuns": {
"heading": "How the script runs (Add flow)",
"body": "The flow has two phases with clear separation between \"setting up the initiator, discovering targets\" and \"actually registering storage in Proxmox\". Unlike NFS / Samba, there is no auto-discovery on the subnet — you must know the portal address (iSCSI is not broadcast-friendly)."
},
"add": {
"heading": "Add iSCSI target as Proxmox storage",
"items": [
"<strong>Portal entry</strong> — type the IP or hostname of the iSCSI target server. Port <code>3260</code> is assumed unless you type <code>host:port</code>.",
"<strong>Target discovery</strong> — ProxMenux calls <code>iscsiadm --mode discovery --type sendtargets --portal &lt;ip:port&gt;</code>. The server responds with every IQN it allows this initiator to see. If discovery fails, the script shows the exact error from <code>iscsiadm</code> and lists common causes (wrong IP, firewall, initiator IQN not authorised).",
"<strong>Target selection</strong> — single target is auto-selected; multiple targets show a menu.",
"<strong>Storage ID</strong> — default is <code>iscsi-&lt;last IQN segment, 20 chars max&gt;</code>. Only letters, digits, <code>-</code> and <code>_</code>.",
"<strong>Content type</strong> — unlike NFS / Samba, iSCSI content is <strong>fixed to <code>images</code></strong>. iSCSI exposes raw block devices, not a filesystem, so Proxmox only lets you host VM disks on it."
],
"authTitle": "Authorise the Proxmox initiator on the target",
"authBody1": "Before the Add flow works end-to-end, the iSCSI target needs to know your Proxmox host. Get your initiator IQN:",
"authBody2": "Then add that IQN to the target's access list (in TrueNAS: <em>Sharing → Block → Initiators Groups</em>; in Synology: <em>SAN Manager → iSCSI → Target → Edit → Initiators</em>; etc.). If the initiator is not authorised, <code>iscsiadm</code> discovery returns an empty list or an authentication error."
},
"manual": {
"heading": "Manual equivalent",
"body": "The whole flow maps to these commands:"
},
"view": {
"heading": "View configured iSCSI storages",
"body": "Lists every iSCSI entry in Proxmox (<code>pvesm status | awk ''$2 == \"iscsi\"''</code>) with portal, target IQN, content type and live status."
},
"remove": {
"heading": "Remove iSCSI storage",
"body": "Runs <code>pvesm remove &lt;storage-id&gt;</code> after confirming portal, target and content. Only the Proxmox registration is removed — <strong>the iSCSI target itself is not touched</strong> and existing sessions on the kernel side may linger until the next reboot.",
"warnTitle": "Existing VM disks on this iSCSI first",
"warnBody": "Removing an iSCSI storage while VMs still have disks on it leaves those VMs pointing at a disappeared store. Proxmox will flag the error, but the LUN data is untouched on the target — you can re-register the storage later to get the disks back. Still, move or back up the VMs first to be safe."
},
"test": {
"heading": "Test iSCSI connectivity",
"body": "Runs a diagnostic pass: checks that <code>iscsiadm</code> is installed, prints your initiator IQN, confirms <code>iscsid</code> is running, pings each registered portal, probes its port, and reports <code>pvesm status</code> plus whether an iSCSI session is currently active (<code>iscsiadm --mode session</code>). Active session plus reachable portal but \"inactive\" in Proxmox usually means a stale state — try <code>pvesm set &lt;id&gt; --disable 0</code>."
},
"troubleshoot": {
"heading": "Troubleshooting",
"portalTitle": "\"Cannot reach portal\" but the server IP responds elsewhere",
"portalBody": "Ping failed on the portal address. Check you are reaching the <em>storage network</em> interface (iSCSI often lives on a separate VLAN / subnet from the management network). Also verify DNS if you typed a hostname.",
"discoverTitle": "\"iSCSI discovery failed\" from iscsiadm",
"discoverIntro": "The script shows the exact error. Most common causes:",
"discoverItems": [
"Portal IP / port wrong (double-check, default is 3260).",
"iSCSI service not running on the target server.",
"Firewall blocks 3260 between Proxmox and the target.",
"<strong>Initiator IQN is not authorised on the target.</strong> Most frequent cause on enterprise arrays. Add your Proxmox IQN to the target's initiator ACL first."
],
"noTargetTitle": "No targets found but discovery succeeded",
"noTargetBody": "The server accepted your initiator but does not expose any target to it. Review the target's authentication / access controls — some arrays allow discovery for all IQNs but filter which targets each IQN can see.",
"noLunTitle": "LUNs do not appear in /dev/disk/by-path after registering",
"noLunBody": "<code>pvesm add iscsi</code> succeeded but the kernel is not seeing block devices. Check <code>iscsiadm --mode session</code> — if no session is active, start one manually with <code>iscsiadm --mode node --login</code>. If a session exists but no LUNs appear, force a rescan: <code>iscsiadm --mode session --rescan</code>. If still nothing, the target probably has no LUNs assigned to this IQN yet (configure LUN mapping on the target).",
"chapTitle": "CHAP authentication",
"chapBody": "ProxMenux does not expose the CHAP username / password fields in the interactive flow. If your target requires CHAP, register with ProxMenux first (discovery with CHAP may fail, but <code>pvesm add</code> will still write the entry), then add credentials manually: <code>pvesm set &lt;id&gt; --username &lt;chap-user&gt;</code> and edit <code>/etc/iscsi/iscsid.conf</code> with the password, then <code>systemctl restart iscsid</code>. This is a gap in the current script — documented here so you know what to do."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/host-nfs",
"label": "NFS share as Proxmox storage",
"tail": " — file-level alternative. Simpler to set up, more flexible (backup / ISO / tmpl / images), slightly slower for live VM disks."
},
{
"href": "/docs/storage-share/host-samba",
"label": "Samba / CIFS as Proxmox storage",
"tail": " — another file-level option; avoid for live VM disks due to locking semantics."
},
{
"href": "/docs/storage-share/host-local-disk",
"label": "Add local disk as Proxmox storage",
"tail": " — when the disk is local to the Proxmox host, not on another box over the network."
}
]
}
}
@@ -0,0 +1,186 @@
{
"meta": {
"title": "Host: Add local disk as Proxmox storage | ProxMenux Documentation",
"description": "Format a local SATA / SAS / NVMe disk on a Proxmox host and register it as Proxmox directory or ZFS pool storage. Safe disk detection, destructive-op confirmation gate, UUID-based fstab, ZFS pool creation and pvesm add dir / zfspool under the hood.",
"ogTitle": "Host: Add local disk as Proxmox storage | ProxMenux Documentation",
"ogDescription": "Format a local disk and register it as Proxmox directory or ZFS pool storage with a guided, safety-filtered flow."
},
"header": {
"title": "Host: Add local disk as Proxmox storage",
"description": "Take a physical disk on the Proxmox host, optionally format it (ext4 / xfs / btrfs / zfs) and register it as Proxmox storage — either as a directory (pvesm add dir) or a ZFS pool (pvesm add zfspool). ProxMenux filters the disk list so you cannot pick the root disk or anything in use, and makes every destructive step explicit before running it.",
"section": "Storage & Share · Host"
},
"intro": {
"title": "What this does",
"body": "Other <em>Host</em> tools in this section deal with <strong>network</strong> storage (NFS / Samba / iSCSI). This one deals with <strong>local</strong> disks — spare drives physically attached to your Proxmox host that you want to use for VM disks, backups, ISOs or templates. ProxMenux prepares the disk (partition + format + mount) and registers it in Proxmox so the UI can place content there."
},
"destructive": {
"title": "Destructive tool for the 'format' path",
"body": "The <em>Format</em> path <strong>erases every partition and byte on the selected disk</strong>. ProxMenux shows the disk list with a warning banner, filters out disks already in use, and requires an explicit confirmation before any <code>wipefs</code> / <code>sgdisk</code> / <code>mkfs</code> runs. Still — read the device path aloud twice before typing \"yes\"."
},
"compare": {
"heading": "Directory vs ZFS pool — which to pick",
"headerDir": "Directory (ext4 / xfs / btrfs)",
"headerZfs": "ZFS pool",
"rows": [
{
"label": "Proxmox storage type",
"dirRich": "<code>dir</code>",
"zfsRich": "<code>zfspool</code>"
},
{
"label": "VM disk format",
"dir": "qcow2 / raw file on a filesystem",
"zfs": "Native ZFS dataset (zvol) per disk"
},
{
"label": "Snapshots",
"dir": "qcow2 snapshots; btrfs snapshots if fs=btrfs",
"zfs": "Native, instant, copy-on-write"
},
{
"label": "Thin provisioning",
"dir": "Yes (qcow2 default)",
"zfs": "Yes (ZFS default)"
},
{
"label": "RAM needs",
"dir": "Low",
"zfs": "High — ZFS uses free RAM as ARC cache"
},
{
"label": "Supports content types",
"dir": "images, backup, iso, vztmpl, snippets, rootdir",
"zfs": "images, rootdir only (block storage)"
},
{
"label": "Best for",
"dir": "General-purpose disk: mix of VM disks, backups, ISOs",
"zfs": "Pure VM / LXC data disk with snapshot + integrity needs"
}
]
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Add Local Disk as Proxmox Storage</strong>. You will see this sub-menu with four options:",
"imageAlt": "Local Disk Manager menu — Add / View / Remove / List available disks"
},
"howRuns": {
"heading": "How the script runs (Add flow)",
"body": "The flow has two phases with a triple-gate safety filter. Phase 1 discovers safe disks, decides what to do with the chosen one and collects storage parameters; Phase 2 does the destructive work. Until the final confirmation the disk is untouched."
},
"format": {
"heading": "Format a blank disk",
"intro": "The path for a fresh disk or one whose contents you do not care about.",
"items": [
"Pick the disk (system / in-use disks are hidden).",
"Pick \"Format disk (ERASE all data)\".",
"Pick the filesystem — see the table above for trade-offs.",
"Storage ID (default <code>disk-&lt;device&gt;</code>), mount path, content-type preset.",
"Confirm at the <strong>FINAL CONFIRMATION — DATA WILL BE ERASED</strong> dialog.",
"ProxMenux wipes the partition table, creates one partition spanning the whole disk, runs <code>mkfs.&lt;fs&gt;</code> (or <code>zpool create</code>), mounts it, adds it to <code>/etc/fstab</code> by UUID with <code>defaults,nofail</code>, and registers it in Proxmox via <code>pvesm add dir</code> or <code>pvesm add zfspool</code>."
],
"tipTitle": "Why UUID + nofail in /etc/fstab",
"tipBody": "The script writes <code>UUID=… /mnt/&lt;id&gt; &lt;fs&gt; defaults,nofail 0 2</code>. UUID survives device reordering across reboots (so <code>/dev/sdc</code> becoming <code>/dev/sdd</code> does not break boot). <code>nofail</code> means that if the disk ever disappears (hardware failure, unplugged), Proxmox still boots — storage will just show as inactive until the disk comes back."
},
"reuse": {
"heading": "Reuse an existing filesystem",
"intro": "The path for a disk you want to keep the data on — maybe you moved it from another Proxmox host, or the disk already has backups / ISOs you want to keep accessible.",
"items": [
"Pick the disk.",
"Pick \"Use existing filesystem\".",
"Storage ID, mount path, content-type preset.",
"ProxMenux does <strong>not</strong> touch the data: it creates the mount point, mounts the disk, adds a UUID entry to <code>/etc/fstab</code>, and registers it as a Proxmox <code>dir</code> storage."
],
"warnTitle": "Reuse path does not handle ZFS pools",
"warnBody": "If the disk already contains a ZFS pool, the <em>reuse</em> path here just tries to mount it as a regular filesystem — which fails. To import an existing ZFS pool use <code>zpool import &lt;name&gt;</code> on the command line and then register it manually with <code>pvesm add zfspool</code>."
},
"presets": {
"heading": "Content-type presets",
"intro": "Instead of a long checklist, ProxMenux offers 4 presets plus a custom option. The preset string is passed to <code>pvesm add … --content &lt;csv&gt;</code>:",
"headerPreset": "Preset",
"headerContent": "Content string",
"headerUse": "Use case",
"rows": [
{
"preset": "VM Storage",
"content": "images,backup",
"use": "A dedicated VM disk store that also keeps backups of those VMs nearby."
},
{
"preset": "Standard NAS",
"content": "backup,iso,vztmpl",
"use": "An archive / media disk — backups, ISOs and LXC templates. No live VM disks here."
},
{
"preset": "All types",
"content": "images,backup,iso,vztmpl,snippets",
"use": "\"Let the host decide\" — allows every content type Proxmox supports on this storage."
},
{
"preset": "Custom",
"content": "(free input)",
"useRich": "Type the exact CSV yourself, e.g. <code>images</code> alone, or <code>rootdir,images</code>."
}
],
"zfsTitle": "ZFS pool content is narrower",
"zfsBody": "If you picked <strong>zfs</strong> as the filesystem, Proxmox only accepts <code>images</code> and <code>rootdir</code> as content types on a <code>zfspool</code> (it is block storage, not a filesystem for ISOs). The presets above will still work but Proxmox silently drops the content types it cannot use — check <code>pvesm status</code> afterwards."
},
"manual": {
"heading": "Manual equivalent",
"extIntro": "Format + register a disk as ext4 directory storage:",
"zfsIntro": "Or as a ZFS pool:"
},
"view": {
"heading": "View disk storages",
"body": "Lists every disk-backed Proxmox storage (both <code>dir</code> and <code>zfspool</code> that are user-created — system pools like <code>rpool</code> are hidden). Shows the mount path / pool name, content types and live status."
},
"remove": {
"heading": "Remove disk storage",
"body": "Unregisters the storage from Proxmox (<code>pvesm remove</code>) and offers to clean up the matching entry in <code>/etc/fstab</code>. For ZFS pools the script does <strong>not</strong> automatically destroy the pool — that is a separate <code>zpool destroy &lt;name&gt;</code> step you do by hand when you are sure.",
"warnTitle": "Data and existing VM dependencies",
"warnBody": "Removing the storage does not touch the filesystem or the pool — the data stays on the disk. But VMs / CTs that reference this storage by ID will fail to start after removal. Move those VM disks to another storage (or take a backup) before removing."
},
"list": {
"heading": "List available disks",
"body": "A read-only diagnostic view: prints the output of <code>lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL</code> followed by the <code>dir</code> / <code>zfspool</code> storages Proxmox already knows about. Good first stop when you open the tool and want to see \"what is on this host?\" before adding anything."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noDisksTitle": "\"No available disks found\"",
"noDisksIntro": "The safety filter hid every disk. Common reasons:",
"noDisksItems": [
"Only the root disk is present.",
"Every other disk is part of an active ZFS / LVM / RAID array.",
"Every other disk is referenced by a VM or LXC config (passthrough).",
"The disk is in read-only mode (failing hardware or write-blocker)."
],
"noDisksOutro": "Use <em>List Available Disks</em> from the menu to see the raw <code>lsblk</code> output and understand what's happening.",
"mountedTitle": "Format fails with \"device is mounted\"",
"mountedBody": "Something auto-mounted the disk (udisksd, a desktop manager, a lingering systemd unit). Unmount it: <code>umount /dev/sdX?*</code> or <code>systemctl stop &lt;whatever-mounts-it&gt;</code>, then retry. The script's safety filter should have hidden mounted disks, so if you reached this error the mount happened between the menu showing and you confirming.",
"zpoolTitle": "zpool create fails \"invalid vdev specification\"",
"zpoolBody": "Usually means the disk still has stale GPT / LVM / ZFS signatures that <code>zpool</code> refuses to overwrite without force. The script runs <code>wipefs</code> and <code>sgdisk --zap-all</code> before format, but a very stubborn disk may still have a stale label. Force a clean wipe manually: <code>zpool labelclear -f /dev/sdX</code> or <code>dd if=/dev/zero of=/dev/sdX bs=1M count=10</code> and retry.",
"inactiveTitle": "Storage shows as inactive after reboot",
"inactiveBody": "Check <code>findmnt &lt;mount-path&gt;</code> — if the mount is missing, something in <code>/etc/fstab</code> failed. <code>dmesg | tail</code> usually points at the reason (UUID mismatch, filesystem corruption, <code>nofail</code> dropped the retry). A <code>mount -a</code> usually reactivates the storage once the cause is fixed."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/disk-manager/format-disk",
"label": "Disk Manager: Format / Wipe Physical Disk",
"tail": " — low-level alternative when you just want to prepare a disk without registering it as Proxmox storage."
},
{
"href": "/docs/storage-share/host-iscsi",
"label": "Add iSCSI target as Proxmox storage",
"tail": " — network equivalent when the block device lives on another box."
},
{
"href": "/docs/storage-share/host-local-shared",
"label": "Add Shared Directory on Host",
"tail": " — prepare a directory on the host for LXC bind mounts (does not register a Proxmox storage)."
}
]
}
}
@@ -0,0 +1,103 @@
{
"meta": {
"title": "Host: Add shared directory on Host | ProxMenux Documentation",
"description": "Create a host directory ready for LXC bind mounts, with permissions that work for privileged and unprivileged containers at once. Sticky bit + world-rwx + ACLs for default inheritance.",
"ogTitle": "Host: Add shared directory on Host | ProxMenux Documentation",
"ogDescription": "Prepare a host directory for LXC bind mounts with permissions compatible with privileged and unprivileged CTs."
},
"header": {
"title": "Host: Add shared directory on Host",
"description": "Create a host directory designed to be bind-mounted into one or more LXC containers. ProxMenux applies a set of permissions that works for both privileged and unprivileged CTs at once — no shifted UID headache, no per-container chowns — and registers the directory so the LXC Mount Manager can pick it up later.",
"section": "Storage & Share · Host"
},
"intro": {
"title": "What this is (and is NOT)",
"body": "This tool does <strong>not</strong> register anything in Proxmox (no <code>pvesm add</code> here). It just prepares a directory on the host — <code>/mnt/shared</code>, by default — with permissions that any LXC container can read and write, regardless of whether the CT is privileged or unprivileged. The usual next step is to bind-mount it into each CT with the <mountLink>LXC Mount Manager</mountLink>."
},
"why": {
"heading": "Why a dedicated tool for this",
"intro": "When you bind-mount a host directory into an LXC container, permissions depend on:",
"items": [
"Whether the CT is <strong>privileged</strong> (UID 0 in CT = UID 0 on host) or <strong>unprivileged</strong> (UID 0 in CT = UID 100000 on host — everything is shifted by +100000).",
"The ownership of the host directory (a file owned by UID 1000 on the host appears as \"others\" from the perspective of an unprivileged CT, because no CT user maps to host UID 1000).",
"Whether multiple CTs share the same directory (different CTs may have different UID ranges)."
],
"outro": "The pragmatic trick ProxMenux uses here is to <strong>give everybody access</strong> at the filesystem level: world-rwx plus the sticky bit, plus ACLs so new files inherit the same permissions. Any mapped UID can read and write; no UID / GID alignment is required."
},
"howRuns": {
"heading": "How the script runs",
"body": "The script has no main menu — it runs a single action, <strong>Create shared directory</strong>. Phase 1 collects the target path; Phase 2 creates the directory and applies permissions."
},
"bits": {
"heading": "What each permission bit does",
"intro": "The number <strong>1777</strong> is not arbitrary — it's the same mode Linux uses for <code>/tmp</code>. Three properties combined:",
"headerBit": "Bit",
"headerEffect": "Effect",
"headerWhy": "Why it matters here",
"rows": [
{
"bit": "1 (sticky)",
"effect": "Only the file owner can delete / rename a file.",
"why": "Prevents CT-A from deleting files created by CT-B in the same directory."
},
{
"bit": "777 (rwx-rwx-rwx)",
"effect": "Everyone can read, write and traverse.",
"why": "Unprivileged CT UIDs (100000+) appear as \"others\" from the host, so world-rwx gives them access."
},
{
"bit": "ACLs (default)",
"effect": "Inherited on every newly created file / subdir.",
"why": "The permissions apply forever — new content keeps the open profile without re-running the script."
}
],
"privTitle": "Privileged CTs see the same thing, just without the shift",
"privBody": "For a privileged CT, UID 0 in the CT is UID 0 on the host, so <code>root</code> inside the CT can read / write the host directory directly. <code>1777</code> is still fine — it just means non-root users inside the CT can also use the directory. The same permissions cover both cases."
},
"where": {
"heading": "Where to put the shared directory",
"intro": "The location picker offers four options:",
"opt1Title": "1. Create new folder in /mnt",
"opt1Body": "The usual choice. ProxMenux auto-suggests the first free name (<code>shared</code>, <code>shared2</code>, <code>shared3</code>, …). You just confirm or type a different name.",
"opt2Title": "2. Enter custom path",
"opt2Body": "For directories outside <code>/mnt</code>. Any absolute path works (e.g. <code>/srv/media</code>, <code>/data/family</code>). The script applies the same permissions.",
"opt3Title": "3. View existing folders in /mnt",
"opt3Body": "Read-only diagnostic: lists every directory under <code>/mnt</code> with its permissions, owner and available space. Useful before creating a new one to avoid name collisions.",
"opt4Title": "4. Cancel",
"opt4Body": "Exits without creating anything. Same as pressing <kbd>Esc</kbd>.",
"tipTitle": "Where does /mnt live?",
"tipBody": "By default <code>/mnt</code> sits on the Proxmox root filesystem. If you want the shared directory on a different disk (a data disk, a ZFS pool), mount that disk under <code>/mnt/&lt;name&gt;</code> first (Disk Manager or <diskLink>Add local disk as Proxmox storage</diskLink>), and then create the shared directory as a subfolder inside it — or pick \"Enter custom path\" here and point to the mounted disk."
},
"manual": {
"heading": "Manual equivalent",
"body": "The whole flow can be replayed by hand:"
},
"next": {
"heading": "Next step: bind-mount into containers",
"body": "Creating the directory only prepares it — no container sees it yet. To make it visible inside one or more LXCs, use the <mountLink>LXC Mount Manager</mountLink> to bind-mount <code>/mnt/&lt;name&gt;</code> into the CTs. Because the permissions are already open, the Mount Manager will <strong>not</strong> offer to change them — the directory is ready to use as-is."
},
"troubleshoot": {
"heading": "Troubleshooting",
"mkdirTitle": "\"Failed to create directory\"",
"mkdirBody": "Usually a filesystem issue: <code>/mnt</code> is on a read-only filesystem, the path contains a component that is not a directory (e.g. you typed <code>/etc/passwd/sub</code>), or disk is full. Check with <code>df -h /mnt</code> and <code>mount | grep /mnt</code>.",
"writeTitle": "Container cannot write despite open permissions",
"writeBody": "Double-check the CT is actually using the bind mount (<code>pct config &lt;ctid&gt; | grep ^mp</code>). Inside the CT, run <code>touch /mnt/data/test-$(date +%s)</code> — if this fails with permission denied, the mount may be on a host filesystem that does not honour ACLs (some older <code>ext3</code> or <code>vfat</code> mounts). Move the shared directory to an ext4 / xfs / btrfs / zfs backing.",
"aclTitle": "ACL commands silently unavailable",
"aclBody": "On a minimal Proxmox install <code>setfacl</code> / <code>getfacl</code> may not be installed. The script falls back gracefully (<code>command -v setfacl</code> check) and applies POSIX permissions only — which is often enough, but new files will not automatically inherit the permissive profile. Install <code>acl</code> with <code>apt-get install -y acl</code> and re-run the script on the directory."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Manager",
"tail": " — the natural next step: bind-mount this directory into one or more containers."
},
{
"href": "/docs/storage-share/host-local-disk",
"label": "Add local disk as Proxmox storage",
"tailRich": " — if you want the shared directory on a dedicated disk, prepare the disk first, mount it under <code>/mnt</code>, then create the shared subfolder here."
}
]
}
}
@@ -0,0 +1,174 @@
{
"meta": {
"title": "Host: Mount NFS share on Host | ProxMenux Documentation",
"description": "Mount an external NFS export on the Proxmox host — either as Proxmox storage (pvesm add nfs), as a plain host fstab mount (NOT visible in Datacenter > Storage), or both. The fstab method is ideal for bind-mounting the share into LXC containers without exposing it as a Proxmox storage.",
"ogTitle": "Host: Mount NFS share on Host | ProxMenux Documentation",
"ogDescription": "Mount an external NFS export on the Proxmox host via pvesm, fstab, or both. fstab path is ideal for LXC bind-mounts."
},
"header": {
"title": "Host: Mount NFS share on Host",
"description": "Mount an external NFS export (from a NAS, another server, a homelab share…) on the Proxmox host. Pick one or both methods: register it as Proxmox storage (visible in Datacenter > Storage) and/or add a plain /etc/fstab mount at a path you choose (useful for bind-mounting the share into LXC containers without exposing it as a Proxmox storage).",
"section": "Storage & Share · Host"
},
"intro": {
"title": "What this does",
"body": "ProxMenux offers two mount methods for any NFS export: <strong>(1) Proxmox storage</strong> via <code>pvesm add nfs</code> — the share shows up in Datacenter > Storage and Proxmox manages the mount at <code>/mnt/pve/&lt;id&gt;</code>; <strong>(2) Host fstab mount</strong> at a path you pick — persistent via <code>/etc/fstab</code>, NOT visible as Proxmox storage, ideal for bind-mounting to LXC containers (Proxmox UI stays clean). You can run one method, the other, or both."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Mount NFS Share on Host</strong>. You will see this sub-menu with four options:",
"imageAlt": "NFS Host Manager menu — Mount / View / Remove / Test connectivity"
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases with clear separation between \"discovering, validating and choosing\" and \"actually mounting / writing config\". After selecting an export, you pick mount method(s) via a checklist; the rest of the dialogs only ask for params for the methods you selected. Until the final confirmation, neither <code>/etc/pve/storage.cfg</code> nor <code>/etc/fstab</code> are touched."
},
"modes": {
"heading": "Mount method picker (two options, mark one or both)",
"intro": "After selecting and validating the export, ProxMenux shows a checklist with the two mount methods. You can mark either, or both. If you press OK without marking anything, the dialog re-appears until you choose at least one option or press Cancel to exit the flow.",
"imageAlt": "Mount method checklist with pvesm and fstab options",
"headerMethod": "Method",
"headerMount": "Mount path",
"headerUi": "Visible in Datacenter > Storage",
"headerUseCase": "Typical use case",
"rows": [
{
"method": "<strong>As Proxmox storage (pvesm)</strong>",
"mountRich": "<code>/mnt/pve/&lt;storage-id&gt;</code> (managed by Proxmox)",
"ui": "Yes",
"useCase": "VM disk images, backups, ISOs, LXC templates — anything that needs to appear in the Proxmox UI."
},
{
"method": "<strong>Host fstab only</strong>",
"mountRich": "<code>/mnt/&lt;path&gt;</code> (you pick the path)",
"ui": "No",
"useCaseRich": "Bind-mounting the share into one or more LXCs <em>without</em> exposing it as a Proxmox storage. Keeps the Datacenter UI clean."
},
{
"method": "<strong>Both</strong>",
"mount": "Both paths above (two independent NFS connections to the server)",
"ui": "Yes",
"useCase": "You want UI integration AND a stable host-side path with open permissions for LXC bind-mounts. Server sees two connections from the host."
}
],
"bothTitle": "\"Both\" creates two independent NFS mounts",
"bothBody": "Marking both options runs each method independently — pvesm mounts at <code>/mnt/pve/&lt;id&gt;</code>, fstab mounts at <code>/mnt/&lt;path&gt;</code>. The server sees two TCP connections from the Proxmox host. This is intentional: it lets you keep the pvesm storage clean (default Proxmox options) while having a separate host-side mount with open permissions for LXC bind-mounts."
},
"pvesmBranch": {
"heading": "Method A — As Proxmox storage (pvesm)",
"intro": "If <em>As Proxmox storage</em> is marked, ProxMenux runs the original pvesm flow:",
"items": [
"<strong>Storage ID</strong> — what Proxmox will call this storage. Default is <code>nfs-&lt;server-ip-with-dashes&gt;</code>. Only letters, digits, <code>-</code> and <code>_</code> are accepted.",
"<strong>Content types</strong> — Proxmox ties content categories to storage volumes; pick what this NFS is allowed to hold:"
],
"headerType": "Content type",
"headerAllows": "What it allows",
"rows": [
{
"type": "import",
"allowsRich": "Disk image imports (selected by default). Needed for <em>Import Disk Image to VM</em>."
},
{
"type": "backup",
"allowsRich": "VM and CT backup files (<code>vzdump</code>)."
},
{
"type": "iso",
"allows": "Installation ISO images."
},
{
"type": "vztmpl",
"allows": "LXC templates."
},
{
"type": "images",
"allows": "Live VM disk images (this turns the NFS into a VM disk store)."
},
{
"type": "rootdir",
"allows": "LXC root filesystems (rare for NFS — read the note below)."
},
{
"type": "snippets",
"allows": "Hook scripts and cloud-init snippets."
}
],
"warnTitle": "images and rootdir on NFS",
"warnBody": "Marking <code>images</code> on an NFS storage lets Proxmox place live VM disks there. It works, but NFS latency + its lock semantics make this noticeably slower than local storage (and a network outage pauses every VM backed by that store). Marking <code>rootdir</code> means you will host LXC root filesystems over NFS, which historically has trouble with unprivileged containers (overlay / chown interactions). Prefer keeping <code>images</code> / <code>rootdir</code> on local or iSCSI storage and using NFS for <code>backup</code> / <code>iso</code> / <code>vztmpl</code>.",
"result": "The result is <code>pvesm add nfs &lt;id&gt; --server &lt;srv&gt; --export &lt;path&gt; --content &lt;csv&gt;</code> and Proxmox auto-mounts at <code>/mnt/pve/&lt;id&gt;</code>."
},
"fstabBranch": {
"heading": "Method B — Host fstab mount only",
"intro": "If <em>As host fstab mount only</em> is marked, ProxMenux asks for a host mount path and persistent options, then mounts and writes the entry to <code>/etc/fstab</code>:",
"items": [
"<strong>Host mount path</strong> — default <code>/mnt/&lt;export-basename&gt;</code>. Must be an absolute path. If something is already mounted there, or a fstab entry exists for the same path, ProxMenux warns you and offers to replace it.",
"<strong>Mount options</strong> — pick <em>Read/Write</em> (default with <code>rw,hard,nofail,_netdev,rsize=131072,wsize=131072,timeo=600,retrans=2</code>), <em>Read-only</em>, or <em>Custom</em> (type your own option string)."
],
"appliesIntro": "Once you confirm, the script:",
"applies": [
"<code>mkdir -p</code> the mount path.",
"<code>mount -t nfs -o &lt;opts&gt; &lt;srv&gt;:&lt;export&gt; &lt;path&gt;</code>.",
"Writes a one-line entry to <code>/etc/fstab</code>: <code>&lt;srv&gt;:&lt;export&gt; &lt;path&gt; nfs &lt;opts&gt; 0 0</code>.",
"Runs <code>systemctl daemon-reload</code> so systemd picks up the new fstab entry.",
"Attempts <code>chmod 1777</code> + <code>setfacl o::rwx</code> on the mount point (silent best-effort — only succeeds if the NFS server allows it; many NAS exports already serve world-writable paths)."
],
"lxcTitle": "Using the fstab mount from an LXC",
"lxcBody": "The script prints the exact <code>pct set</code> command at the end to bind-mount the path into a container, e.g. <code>pct set &lt;ctid&gt; -mp0 /mnt/&lt;path&gt;,mp=/mnt/&lt;ct-path&gt;,shared=1,backup=0</code>. Or use the <mountLink>LXC Mount Manager</mountLink>, which detects the fstab mount automatically. <strong>No changes are made inside the container</strong> — for unprivileged LXCs to read/write the NFS data, the script relies on server-side world-writable export semantics (typical for Synology, TrueNAS, OMV defaults). If your NFS server squashes root or restricts perms, see Troubleshooting.",
"noUiTitle": "The fstab mount is NOT a Proxmox storage",
"noUiBody": "The host fstab mount is invisible to the Proxmox web UI — by design. It does not appear in <em>Datacenter > Storage</em>, you cannot select it in the VM / CT creator, and Proxmox backup jobs cannot target it. It is purely a host filesystem path. If you also want UI integration, mark <em>both</em> methods in the picker."
},
"manual": {
"heading": "Manual equivalent",
"pvesmIntro": "Method A (pvesm) maps to:",
"fstabIntro": "Method B (fstab) maps to:"
},
"view": {
"heading": "View configured NFS storages",
"body": "Lists every NFS entry in Proxmox (<code>pvesm status | awk ''$2 == \"nfs\"''</code>) with server, export, content types, mount path and live status. <strong>Note:</strong> this view only shows pvesm-registered storages — fstab-only mounts are not listed here. Check those with <code>findmnt -t nfs</code> or <code>grep nfs /etc/fstab</code>."
},
"remove": {
"heading": "Remove NFS storage",
"body": "Runs <code>pvesm remove &lt;storage-id&gt;</code> after a confirmation that shows the server / export / content. Only the Proxmox-side registration is removed — <strong>the remote NFS server itself is never touched</strong>, no files are deleted. To remove a fstab-only mount, edit <code>/etc/fstab</code> by hand and run <code>umount &lt;path&gt;</code>.",
"warnTitle": "Back up dependencies first",
"warnBody": "If VMs, CTs or backup jobs still reference this storage (by ID), removing it leaves them pointing at a disappeared store. Proxmox will flag the error but not clean up. Move or drop those references first, then remove the storage."
},
"test": {
"heading": "Test NFS connectivity",
"body": "Runs a diagnostic pass over every NFS storage registered in Proxmox: checks that <code>showmount</code> is available, that <code>rpcbind</code> is running, pings each server, probes port 2049, calls <code>showmount -e</code>, and finally reports Proxmox's own view (<code>pvesm status</code>). Good first stop when a storage shows as <em>inactive</em> in the Proxmox UI."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noServersTitle": "\"No NFS servers found on the network\"",
"noServersBody": "Auto-discover uses <code>nmap -p 2049 --open &lt;subnet&gt;/24</code>. The server may not respond if: it is on a different VLAN / subnet, its firewall blocks nmap probes (many do) or port 2049 is intentionally closed on that interface. Use the <em>Manual</em> option with the server's IP or hostname instead.",
"portTitle": "\"NFS port (2049) is not accessible\"",
"portBody": "Ping succeeded but <code>nc -z -w 3 &lt;server&gt; 2049</code> failed. Check the NFS service is running on the server (<code>systemctl status nfs-server</code> on Linux, Control Panel → File Services on Synology, NFS plugin on OMV / TrueNAS), and that the firewall allows 2049 from the Proxmox host.",
"showmountTitle": "\"Failed to connect\" from showmount",
"showmountBody": "The server refused the export-list query. Common causes: the server enforces strict client ACLs (your Proxmox IP is not on the allowed list), <code>rpcbind</code> is not running on the server, or the server exposes only NFSv4 with <code>showmount</code> disabled. The export path can still be added manually if you know it.",
"inactiveTitle": "Storage shows as inactive in the Proxmox UI",
"inactiveBody": "Run <em>Test NFS Connectivity</em> first — 99 % of the time this flags the exact hop that breaks (DNS, port, mount permissions). If connectivity is fine but Proxmox still flags inactive, check <code>journalctl -u pvestatd</code> on the Proxmox node; intermittent DNS or slow NFS mounts on boot can leave storages in an inactive state until <code>pvesm set &lt;id&gt; --disable 0</code> is re-applied.",
"lxcNoWriteTitle": "fstab mount works but unprivileged LXC can't write through a bind-mount",
"lxcNoWriteBody": "NFS permissions are enforced server-side, not by the host. The fstab options (<code>uid=</code>, <code>file_mode=</code>) that work for CIFS do <strong>not</strong> apply to NFS. If your unprivileged LXC (root inside CT = UID 100000 on host, mapped to NFS as \"others\") cannot write, the NFS server is either squashing root or has restrictive perms. Fix on the server: change the export to <code>no_root_squash</code> if you trust the host, or set the export world-writable (Synology, TrueNAS, OMV all expose this in the UI). The script tries <code>chmod 1777</code> on the mount but that only succeeds when the server permits it.",
"fstabBootTitle": "fstab mount does not come up after reboot",
"fstabBootBody": "The script adds <code>nofail,_netdev</code> so a missing share at boot does not block startup. If the mount never comes up: confirm the network is reachable (<code>ping &lt;server&gt;</code>), check <code>journalctl -u remote-fs.target</code>, and verify the entry is valid with <code>mount -fav | grep nfs</code>. <code>mount -a</code> after boot mounts everything that is currently missing."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/host-samba",
"label": "Samba / CIFS as Proxmox storage",
"tail": " — same flow pattern (Method A pvesm + Method B fstab) for SMB/CIFS shares."
},
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Manager",
"tailRich": " — bind-mount the fstab-only path <code>/mnt/&lt;path&gt;</code> into one or more containers."
},
{
"href": "/docs/storage-share/lxc-nfs-client",
"label": "NFS client in LXC",
"tail": " — alternative: mount NFS directly from inside a privileged container (skips the host)."
}
]
}
}
@@ -0,0 +1,172 @@
{
"meta": {
"title": "Host: Mount Samba share on Host | ProxMenux Documentation",
"description": "Mount an external Samba / CIFS share on the Proxmox host — either as Proxmox storage (pvesm add cifs), as a plain host fstab mount with open uid/gid/file_mode (NOT visible in Datacenter > Storage), or both. The fstab method opens permissions so an unprivileged LXC bind-mounting the path can read/write without any changes inside the container.",
"ogTitle": "Host: Mount Samba share on Host | ProxMenux Documentation",
"ogDescription": "Mount an external Samba / CIFS share on the Proxmox host via pvesm, fstab with open perms (ideal for LXC bind-mounts), or both."
},
"header": {
"title": "Host: Mount Samba share on Host",
"description": "Mount an external Samba (SMB / CIFS) share — from a NAS, a Windows box, a TrueNAS SMB export — on the Proxmox host. Pick one or both methods: register it as Proxmox storage (visible in Datacenter > Storage) and/or add a plain /etc/fstab mount at a path you choose, with open uid/gid/file_mode so unprivileged LXCs can bind-mount and write without any changes inside the container.",
"section": "Storage & Share · Host"
},
"intro": {
"title": "What this does",
"body": "ProxMenux offers two mount methods for any Samba share: <strong>(1) Proxmox storage</strong> via <code>pvesm add cifs</code> — visible in Datacenter > Storage, mounted at <code>/mnt/pve/&lt;id&gt;</code>, credentials stored encrypted in <code>/etc/pve/priv/storage/&lt;id&gt;.pw</code>; <strong>(2) Host fstab mount</strong> at a path you pick — persistent via <code>/etc/fstab</code>, mounted with <code>uid=0,gid=0,file_mode=0777,dir_mode=0777</code> so unprivileged LXC bind-mounts can write, credentials stored in a root-only <code>/etc/samba/credentials/</code> file (password never in <code>fstab</code>). You can run one method, the other, or both."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Mount Samba Share on Host</strong>. You will see this sub-menu with four options:",
"imageAlt": "Samba Host Manager menu — Mount / View / Remove / Test connectivity"
},
"howRuns": {
"heading": "How the script runs",
"body": "The flow has two phases. Phase 1: discover server, validate credentials, pick share, then pick mount method(s) via a checklist. Phase 2: only the methods you marked are executed. Credentials are needed up-front because <code>smbclient</code> needs them to list shares. Until the final confirmation, neither <code>/etc/pve/storage.cfg</code> nor <code>/etc/fstab</code> are touched."
},
"modes": {
"heading": "Mount method picker (two options, mark one or both)",
"intro": "After selecting the share and validating credentials, ProxMenux shows a checklist with the two mount methods. You can mark either, or both. If you press OK without marking anything, the dialog re-appears until you choose at least one option or press Cancel to exit the flow.",
"headerMethod": "Method",
"headerMount": "Mount path",
"headerUi": "Visible in Datacenter > Storage",
"headerUseCase": "Typical use case",
"rows": [
{
"method": "<strong>As Proxmox storage (pvesm)</strong>",
"mountRich": "<code>/mnt/pve/&lt;storage-id&gt;</code> (managed by Proxmox)",
"ui": "Yes",
"useCase": "Backups, ISOs, LXC templates — anything that needs to appear in the Proxmox UI. Live VM disks are technically supported but discouraged on CIFS (locking semantics)."
},
{
"method": "<strong>Host fstab only</strong>",
"mountRich": "<code>/mnt/&lt;path&gt;</code> with open uid/gid/file_mode",
"ui": "No",
"useCaseRich": "Bind-mounting the share into one or more LXCs <em>without</em> exposing it as a Proxmox storage. Open perms guarantee unprivileged CTs can write through the bind-mount."
},
{
"method": "<strong>Both</strong>",
"mount": "Both paths above (two independent CIFS connections to the server)",
"ui": "Yes",
"useCase": "You want UI integration AND a stable host-side path with open permissions for LXC bind-mounts. The pvesm mount uses Proxmox defaults; the fstab mount applies the open uid/gid/file_mode separately."
}
],
"bothTitle": "\"Both\" creates two independent CIFS connections",
"bothBody": "pvesm and fstab mount the same share twice with different options. The pvesm mount at <code>/mnt/pve/&lt;id&gt;</code> uses Proxmox defaults (no open uid/gid) — Proxmox UI is happy. The fstab mount at <code>/mnt/&lt;path&gt;</code> uses <code>uid=0,gid=0,file_mode=0777,dir_mode=0777</code> — unprivileged LXC bind-mounts to it can write. Two TCP connections to the SMB server from the same Proxmox host."
},
"pvesmBranch": {
"heading": "Method A — As Proxmox storage (pvesm)",
"intro": "If <em>As Proxmox storage</em> is marked, ProxMenux runs the original pvesm flow:",
"items": [
"<strong>Storage ID</strong> — default <code>cifs-&lt;server-ip-with-dashes&gt;</code>. Only letters, digits, <code>-</code> and <code>_</code>.",
"<strong>Content types</strong> — CIFS exposes <strong>6</strong> options (same as NFS minus <code>rootdir</code>, which Proxmox does not allow on CIFS because the locking semantics cannot hold a live LXC rootfs):"
],
"headerType": "Content type",
"headerAllows": "What it allows",
"rows": [
{
"type": "import",
"allows": "Disk image imports (selected by default)."
},
{
"type": "backup",
"allowsRich": "VM and CT backup files (<code>vzdump</code>)."
},
{
"type": "iso",
"allows": "Installation ISO images."
},
{
"type": "vztmpl",
"allows": "LXC templates."
},
{
"type": "images",
"allowsRich": "Live VM disk images — <strong>warned inline</strong>, see below."
},
{
"type": "snippets",
"allows": "Hook scripts and cloud-init snippets."
}
],
"warnTitle": "Live VM disks on CIFS",
"warnBody": "If you tick <code>images</code>, ProxMenux pops up a warning before continuing. CIFS uses an advisory locking model that interacts badly with KVM disk operations (snapshots, live migration, I/O under contention). A backup or ISO store on CIFS is perfectly fine; a live-disk store is asking for trouble. Use NFS (or local storage) for <code>images</code> when you can.",
"credsTitle": "Where pvesm stores credentials",
"credsBody": "When you use User authentication, the password is NOT written in <code>/etc/pve/storage.cfg</code>. Proxmox keeps it in <code>/etc/pve/priv/storage/&lt;storage-id&gt;.pw</code> — mode <code>0600</code>, owner <code>root</code>, member of the cluster sync. If you later change the password on the Samba server, use <code>pvesm set &lt;id&gt; --password &lt;new&gt;</code> or remove and re-add through ProxMenux."
},
"fstabBranch": {
"heading": "Method B — Host fstab mount only",
"intro": "If <em>As host fstab mount only</em> is marked, ProxMenux asks for a host mount path and persistent options, writes a root-only credentials file (User mode), then mounts and writes the entry to <code>/etc/fstab</code>:",
"items": [
"<strong>Host mount path</strong> — default <code>/mnt/&lt;share-name&gt;</code>. Must be an absolute path. If something is already mounted there, or a fstab entry exists, ProxMenux offers to replace it.",
"<strong>Mount options</strong> — pick <em>Read/Write</em> (default with <code>rw,uid=0,gid=0,file_mode=0777,dir_mode=0777,iocharset=utf8,nofail,_netdev</code>), <em>Read-only</em> (read-only variant with <code>file_mode=0555,dir_mode=0555</code>), or <em>Custom</em> (type your own option string). Open uid/gid/file_mode are always recommended for LXC bind-mount writes."
],
"credsTitle": "Credentials file (User mode)",
"credsBody": "If you authenticated with a username + password, ProxMenux writes a root-only credentials file at <code>/etc/samba/credentials/&lt;server&gt;_&lt;share&gt;.cred</code> (mode <code>0600</code>) with <code>username=</code> and <code>password=</code> lines, and references it in the fstab entry via the <code>credentials=</code> mount option. Plain text never lands in <code>/etc/fstab</code>. For Guest mode, the option <code>guest</code> is appended instead and no credentials file is created.",
"appliesIntro": "Once you confirm, the script:",
"applies": [
"<code>mkdir -p</code> the mount path.",
"<code>mount -t cifs -o &lt;opts&gt;,credentials=&lt;file&gt;</code> (or <code>guest</code>) <code>//&lt;srv&gt;/&lt;share&gt; &lt;path&gt;</code>.",
"Writes a one-line entry to <code>/etc/fstab</code>: <code>//&lt;srv&gt;/&lt;share&gt; &lt;path&gt; cifs &lt;opts&gt; 0 0</code>.",
"Runs <code>systemctl daemon-reload</code> so systemd picks up the new fstab entry."
],
"lxcTitle": "Using the fstab mount from an unprivileged LXC",
"lxcBody": "Because the CIFS client applies <code>uid=0,gid=0,file_mode=0777,dir_mode=0777</code>, every file in the mount is owned by host UID 0 with mode 0777. An unprivileged LXC bind-mounting the path sees \"others\" perms on every entry (CT root = host UID 100000 = others on the host filesystem), so reads and writes succeed. <strong>No changes are made inside the container</strong> — no <code>chown</code> in the CT, no group setup, nothing modified in <code>/etc/lxc</code> beyond the single <code>mp</code> bind-mount line. The script prints the exact <code>pct set</code> command at the end, or use the <mountLink>LXC Mount Manager</mountLink> to attach the path.",
"noUiTitle": "The fstab mount is NOT a Proxmox storage",
"noUiBody": "The host fstab mount is invisible to the Proxmox web UI — by design. It does not appear in <em>Datacenter > Storage</em>, you cannot select it in the VM / CT creator, and Proxmox backup jobs cannot target it. It is purely a host filesystem path. If you also want UI integration, mark <em>both</em> methods in the picker."
},
"manual": {
"heading": "Manual equivalent",
"pvesmIntro": "Method A (pvesm) maps to:",
"fstabUserIntro": "Method B (fstab, user auth) — credentials file + mount:",
"fstabGuestIntro": "Method B (fstab, guest auth) — no credentials file:"
},
"view": {
"heading": "View configured CIFS storages",
"body": "Lists every CIFS entry in Proxmox (<code>pvesm status | awk ''$2 == \"cifs\"''</code>) with server, share, content types, username (or <em>Guest</em>), mount path and live status. Password is <strong>never printed</strong>. <strong>Note:</strong> this view only shows pvesm-registered storages — fstab-only mounts are not listed. Check those with <code>findmnt -t cifs</code> or <code>grep cifs /etc/fstab</code>."
},
"remove": {
"heading": "Remove CIFS storage",
"body": "Runs <code>pvesm remove &lt;storage-id&gt;</code> after a confirmation that shows the server / share / content. Only the Proxmox-side registration is removed — <strong>the remote Samba server is not touched</strong>. Proxmox also deletes the paired credentials file. To remove a fstab-only mount, edit <code>/etc/fstab</code> by hand, run <code>umount &lt;path&gt;</code>, and remove the file from <code>/etc/samba/credentials/</code>.",
"warnTitle": "Back up dependencies first",
"warnBody": "VMs, CTs or backup jobs that reference this storage by ID will fail after removal. Move / drop those references before removing the storage."
},
"test": {
"heading": "Test Samba connectivity",
"body": "Runs a diagnostic pass over every CIFS storage registered in Proxmox: checks that <code>smbclient</code> is available, pings each server, probes ports 445 and 139, tries a guest listing, and reports Proxmox's own view (<code>pvesm status</code>). \"Requires authentication\" on guest-list means your server only exposes shares to authenticated users — normal for most NAS setups."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noServersTitle": "\"No Samba servers found on the network\"",
"noServersBody": "Auto-discover uses <code>nmap -p 139,445</code>. The server may be on a different subnet, firewalled, or only reachable by hostname (mDNS / WINS). Use the <em>Manual</em> option with the IP or hostname instead.",
"noSharesTitle": "\"No accessible shares found\"",
"noSharesBody": "<code>smbclient -L</code> returned nothing for these credentials. Causes: the user has no permission to list shares (try with admin credentials once, or enter the share name manually), the server has share visibility disabled, or the credentials are wrong. The script lets you type the share name by hand in this case.",
"denyTitle": "Proxmox mount fails with NT_STATUS_ACCESS_DENIED",
"denyBody": "The credentials pvesm stored are out of sync with the Samba server (password changed, account disabled, domain / workgroup mismatch). Re-enter credentials with <code>pvesm set &lt;id&gt; --username &lt;u&gt; --password &lt;p&gt;</code> or remove and re-add from ProxMenux. If the server is in an AD domain, append <code>--domain &lt;DOMAIN&gt;</code> to the <code>pvesm set</code> call.",
"sleepTitle": "\"host is down\" or storage status goes inactive at night",
"sleepBody": "Some NAS appliances put SMB to sleep aggressively. <code>pvestatd</code> then sees the storage as inactive until the first access wakes the NAS. If this is cosmetic, nothing is broken. If it causes backup failures, disable SMB idle disconnect on the NAS or schedule backups outside the sleep window.",
"lxcNoWriteTitle": "Unprivileged LXC bind-mount can't write to the fstab path",
"lxcNoWriteBody": "Confirm the mount uses the open options: <code>findmnt /mnt/&lt;path&gt;</code> should show <code>uid=0,gid=0,file_mode=0777,dir_mode=0777</code>. If a Custom option string omits those, an unprivileged LXC will get permission denied (CT UIDs map to host \"others\", which without open file_mode have no write bit). Re-mount with the default RW preset or add the four options back to your custom string.",
"fstabBootTitle": "fstab mount does not come up after reboot",
"fstabBootBody": "The script adds <code>nofail,_netdev</code> so a missing share at boot does not block startup. If the mount never comes up: confirm the network is reachable (<code>ping &lt;server&gt;</code>), check <code>journalctl -u remote-fs.target</code>, verify the credentials file still exists (<code>ls -l /etc/samba/credentials/</code>) and is readable, and try <code>mount -a</code> manually."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/host-nfs",
"label": "NFS share as Proxmox storage",
"tail": " — sibling page with the same flow pattern (Method A pvesm + Method B fstab) and side-by-side trade-offs."
},
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Manager",
"tailRich": " — bind-mount the fstab-only path <code>/mnt/&lt;path&gt;</code> into one or more containers."
},
{
"href": "/docs/storage-share/lxc-samba-client",
"label": "Samba client in LXC",
"tail": " — alternative: mount Samba directly from inside a privileged container (skips the host)."
}
]
}
}
@@ -0,0 +1,135 @@
{
"meta": {
"title": "Proxmox NFS, Samba, iSCSI & LXC Mount Points — Storage & Share | ProxMenux",
"description": "Integrate external and local storage into Proxmox VE and share folders between host and LXC containers. Add NFS shares, Samba (CIFS) shares and iSCSI targets as Proxmox storage, set up LXC bind mounts (Mount Manager) and run NFS / Samba clients and servers inside containers.",
"ogTitle": "Proxmox NFS, Samba, iSCSI & LXC Mount Points — Storage & Share",
"ogDescription": "Integrate external / local storage into Proxmox VE — NFS, Samba, iSCSI registration plus LXC bind mounts and network sharing.",
"twitterTitle": "Proxmox NFS, Samba, iSCSI | ProxMenux",
"twitterDescription": "Add NFS / Samba / iSCSI as Proxmox storage and share folders between host and LXC."
},
"header": {
"title": "Storage & Share Manager",
"description": "Integrate external or local storage into Proxmox VE and share folders between the host and LXC containers. Three blocks of tools: Host storage integration (register storage in Proxmox itself), the LXC Mount Manager (bind mounts with pragmatic permission handling), and LXC network sharing (NFS / Samba client and server flows for specific use cases).",
"section": "Storage & Share"
},
"intro": {
"title": "What this menu is for",
"body": "The Disk Manager works at the level of <em>individual physical disks</em>. Storage &amp; Share Manager works one level up — it <strong>registers storage pools and network shares in Proxmox</strong> (so the UI and the VM creator can use them) and <strong>sets up file sharing between the host and your containers</strong>."
},
"opening": {
"heading": "Opening the menu",
"body": "From ProxMenux's main menu, select <strong>Storage &amp; Share Manager</strong>. You will see this:",
"imageAlt": "Storage & Share Manager menu with HOST and LXC blocks"
},
"groups": {
"heading": "Three tool groups",
"intro": "The menu is split into three blocks. <strong>Host storage integration</strong> registers external or local storage in Proxmox itself. The <strong>LXC Mount Manager</strong> is the primary tool for sharing folders with containers — a pragmatic bind-mount flow that handles unprivileged UID mapping on the host side. <strong>LXC network sharing</strong> covers four additional scenarios where a container needs to <em>consume</em> or <em>expose</em> NFS / Samba shares directly.",
"hostTitle": "Host storage",
"hostBody": "Register external and local storage in Proxmox via <code>pvesm add …</code>. Once registered, the storage appears in the Proxmox UI and is available to the VM and CT creators.",
"hostItems": [
"External NFS / Samba / iSCSI → Proxmox storage",
"Local disk → Proxmox directory or ZFS storage",
"Local shared directory (for cross-CT bind mounts)"
],
"lxcMountTitle": "LXC Mount Manager",
"lxcMountBody": "The primary LXC sharing tool. Bind-mounts host directories into containers via <code>pct set -mpN</code> and handles the permission quirks of unprivileged CTs without creating any group or user inside the container.",
"lxcMountItems": [
"Works with privileged and unprivileged CTs",
"Offers to set <code>o+rwx</code> on the host dir for unprivileged UIDs",
"Fixes existing CIFS / NFS mounts if needed"
],
"lxcNetTitle": "LXC network sharing",
"lxcNetBody": "Four additional flows for scenarios where a container needs to consume or expose NFS / Samba shares directly. All require a <strong>privileged</strong> container.",
"lxcNetItems": [
"NFS / Samba <strong>client</strong> (consume external shares)",
"NFS / Samba <strong>server</strong> (expose CT folders)"
]
},
"host": {
"heading": "Host storage integration",
"intro": "Register storage in Proxmox. Every option calls <code>pvesm add …</code> under the hood, so the storage shows up in <strong>Datacenter → Storage</strong> and becomes available to the VM / CT creators.",
"options": [
{
"href": "/docs/storage-share/host-nfs",
"icon": "Network",
"title": "Add NFS share as Proxmox storage",
"description": "Register an external NFS export as Proxmox storage via pvesm add nfs. Proxmox handles the mount — no fstab entries needed."
},
{
"href": "/docs/storage-share/host-samba",
"icon": "Share2",
"title": "Add Samba share as Proxmox storage",
"description": "Register an external Samba / CIFS share as Proxmox storage via pvesm add cifs. Proxmox handles the mount and credentials."
},
{
"href": "/docs/storage-share/host-iscsi",
"icon": "Database",
"title": "Add iSCSI target as Proxmox storage",
"description": "Connect to an external iSCSI target and register it as Proxmox storage (block device) for VM disk images."
},
{
"href": "/docs/storage-share/host-local-disk",
"icon": "HardDrive",
"title": "Add local disk as Proxmox storage",
"description": "Format a local SATA / SAS / NVMe disk and register it as a Proxmox directory or ZFS pool storage."
},
{
"href": "/docs/storage-share/host-local-shared",
"icon": "FolderOpen",
"title": "Add shared directory on Host",
"description": "Create a host directory meant to be bind-mounted into multiple CTs. Not a Proxmox storage — purely a host-side resource for LXC bind mounts."
}
]
},
"lxcMount": {
"heading": "LXC Mount Manager",
"intro": "The primary tool for sharing folders between the Proxmox host and LXC containers. It uses <code>pct set -mpN</code> to bind-mount a host directory into the container, and handles the permission quirks of unprivileged CTs on the host side (no groups or users are created inside the container).",
"card": {
"title": "LXC mount points (Host ↔ CT)",
"description": "Bind-mount any host directory into an LXC container via pct set -mpN. Works with both privileged and unprivileged CTs; offers chmod o+rwx / ACLs on the host dir and fixes existing CIFS / NFS mounts when needed."
}
},
"lxcNet": {
"heading": "LXC network sharing",
"intro": "Use these flows when a container needs to <em>be</em> an NFS / Samba endpoint — either consuming an external share (client) or exposing its own folders (server). For most file-sharing needs (host ↔ CT bind mounts), the <mountLink>LXC Mount Manager</mountLink> is simpler and does not require privileged containers.",
"options": [
{
"href": "/docs/storage-share/lxc-nfs-client",
"icon": "Download",
"title": "NFS client in LXC",
"description": "Mount external NFS shares from inside a privileged LXC container. Supports auto-discovery, /etc/fstab persistence and clean unmounts."
},
{
"href": "/docs/storage-share/lxc-samba-client",
"icon": "Download",
"title": "Samba client in LXC",
"description": "Mount Samba / CIFS shares from inside a privileged LXC container. Credentials stored securely, auto-discovery available."
},
{
"href": "/docs/storage-share/lxc-nfs-server",
"icon": "Upload",
"title": "NFS server in LXC",
"description": "Export folders over NFS from inside a privileged LXC container."
},
{
"href": "/docs/storage-share/lxc-samba-server",
"icon": "Upload",
"title": "Samba server in LXC",
"description": "Expose folders over SMB / CIFS from inside a privileged LXC container."
}
]
},
"privReq": {
"title": "Privileged container requirement",
"body": "The four <strong>LXC network sharing</strong> flows above require a <strong>privileged</strong> container — the kernel modules (<code>nfs-kernel-server</code>, <code>smbd</code>, <code>mount.nfs</code>, <code>mount.cifs</code>) need capabilities that unprivileged CTs do not expose. If you only need to share files between the host and an unprivileged CT, use the <mountLink>LXC Mount Manager</mountLink> instead — it bind-mounts from the host and adjusts permissions on the host side so the container can read and write without any kernel-module magic."
},
"unprivExplain": {
"title": "How ProxMenux handles unprivileged CT permissions",
"body": "Unprivileged LXC containers shift their UIDs by <strong>+100000</strong> on the host (container UID 0 = host UID 100000, container UID 1000 = host UID 101000, …). A file created by a container user therefore appears on the host as <em>others</em> — not belonging to any real host user or group. The LXC Mount Manager addresses this pragmatically: instead of trying to align UIDs / GIDs between host and CT, it offers to apply <code>chmod o+rwx</code> (plus matching ACLs) on the host directory, so any mapped UID can read and write. For CIFS it remounts with <code>uid=0,gid=0,file_mode=0777,dir_mode=0777</code>; for NFS it sets a sticky world-writable directory and, if the server squashes root, guides you to the right server-side fix."
},
"scripts": {
"heading": "Scripts involved",
"intro": "Each individual page links to the script that drives its flow. The file below is a shared helper that is not documented as its own page but is used by several of the LXC network-sharing flows:",
"itemTail": " — CT validation, mount point selection, privileged check and universal group setup helpers shared across the LXC client / server flows."
}
}
@@ -0,0 +1,174 @@
{
"meta": {
"title": "LXC Mount Points (Host ↔ Container) | ProxMenux Documentation",
"description": "The LXC Mount Manager — bind-mount any host directory into one or more LXC containers via pct set -mpN. Handles permission quirks of unprivileged containers, fixes existing CIFS / NFS mounts on the host side, and never modifies anything inside the container.",
"ogTitle": "LXC Mount Points (Host ↔ Container) | ProxMenux Documentation",
"ogDescription": "Bind-mount host directories into LXC containers. Handles unprivileged UID mapping pragmatically, fixes CIFS / NFS access on the host side."
},
"header": {
"title": "LXC Mount Points (Host ↔ Container)",
"description": "The primary tool for sharing folders between the Proxmox host and LXC containers. Bind-mounts any host directory into one or more containers using Proxmox's native pct set -mpN syntax. The smart bit: it solves the permission headaches of unprivileged containers on the host side — it never modifies anything inside the container.",
"section": "Storage & Share · LXC"
},
"intro": {
"title": "What this does",
"body": "Take a directory that lives on the Proxmox host (a local folder, a mounted NAS share, a Proxmox-managed storage…) and make it appear inside an LXC container at a path you choose, with permissions that work even for unprivileged containers — without touching anything inside the container."
},
"bigPicture": {
"heading": "How it works (the big picture)",
"intro": "A bind mount is exactly what the name says: Proxmox tells the kernel \"the host directory <code>X</code> should also appear at path <code>Y</code> inside this container\". There's no copy, no sync, no network — both sides see the <em>same files</em> at the same time.",
"sourceLabel": "Proxmox Host",
"sourceDetail": "/mnt/data\n(your folder)",
"targetLabel": "LXC Container",
"targetDetail": "/mnt/data\n(shows up here)",
"arrowLabel": "bind mount",
"outro": "The host path on the left and the container path on the right can be different — for example, <code>/mnt/nas-films</code> on the host can become <code>/media/films</code> inside the container. The script adds the entry to the container config (<code>/etc/pve/lxc/&lt;ctid&gt;.conf</code>) using the next free <code>mpN</code> index, with two safe-defaults baked in:",
"items": [
"<code>shared=1</code> — tells Proxmox the data is shared storage, so it does not try to migrate the disk when you migrate the container.",
"<code>backup=0</code> — excludes the bind mount from <code>vzdump</code> backups (the data lives on the host, you back it up separately)."
]
},
"perms": {
"heading": "Permission handling — the smart part",
"intro": "Bind mounts are easy in principle. The hard part is permissions: an <strong>unprivileged</strong> LXC container shifts every UID by <strong>+100000</strong>, so a file created inside the container by user 1000 appears on the host as UID 101000 — a UID nobody on the host owns. To make this work without aligning UIDs across hosts and containers, ProxMenux applies the right \"open up permissions\" trick on the <em>host</em> side, depending on what kind of directory you picked:",
"headerType": "Host directory type",
"headerAction": "What the script offers to do",
"localType": "Local folder",
"localTypeSub": "e.g. /mnt/data",
"localActionRich": "<code>chmod o+rwx</code> + <code>setfacl o::rwx</code> on the host directory. Only offered if the CT is unprivileged and current permissions are insufficient.",
"cifsType": "Mounted CIFS / SMB",
"cifsTypeSub": "e.g. /mnt/pve/cifs-…",
"cifsActionRich": "Remount with <code>uid=0, gid=0, file_mode=0777, dir_mode=0777</code> so the CT (any UID) can read and write the share. <code>/etc/fstab</code> is updated.",
"nfsType": "Mounted NFS",
"nfsTypeSub": "e.g. /mnt/pve/nfs-…",
"nfsActionRich": "<code>chmod 1777</code> + <code>setfacl o::rwx</code> on the NFS mount. Cannot override server-side squashing — if even host root can't write, you are guided to fix the export on the NFS server.",
"privTitle": "Privileged containers don't need any of this",
"privBody": "For privileged containers, UID 0 in the CT is UID 0 on the host — root inside the CT can read and write the host directory directly without any permission tricks. The script detects this and skips the \"open up permissions\" step entirely.",
"noCtTitle": "The script never modifies anything inside the container",
"noCtBody": "All permission tweaks happen on the <strong>host filesystem</strong>. No <code>pct exec</code> chowns, no groups created in the CT, no fstab inside the container. If you reuse the bind-mounted directory in a different CT later, the same permissions apply automatically — no per-container setup."
},
"writes": {
"heading": "What ProxMenux writes — and what it doesn't",
"intro": "A common confusion when bind-mounting into an unprivileged CT: people assume ProxMenux must be writing <code>lxc.idmap</code> entries into <code>/etc/pve/lxc/&lt;CTID&gt;.conf</code>. <strong>It does not.</strong> Only one line is appended to that file — the bind mount itself:",
"outro": "The output line you see at the end of the run, <em>\"Unprivileged container — UID offset: 100000\"</em>, is purely informational — it just tells you the CT is using Proxmox's default unprivileged mapping (root in CT = UID 100000 on host). The script does not configure anything around it.",
"twoWaysHeading": "The two ways to make permissions work — and why ProxMenux picks one",
"headerApproach": "Approach",
"headerChanges": "What it changes",
"headerWhen": "When it fits",
"hostType": "Host-side perms",
"hostTypeSub": "(what this script does)",
"hostChangesRich": "<code>chmod o+rwx</code> + <code>setfacl o::rwx</code> on the host directory. The CT's mapped UIDs (100000+) fall into the \"others\" bucket, so opening <em>others</em> is enough.",
"hostWhen": "Generic shared-folder access from any CT. Multiple CTs sharing the same host directory. Simple and reusable.",
"idmapTypeRich": "<code>lxc.idmap</code>",
"idmapTypeSub": "(not used by this script)",
"idmapChangesRich": "Custom UID/GID mapping in <code>/etc/pve/lxc/&lt;CTID&gt;.conf</code> plus matching <code>/etc/subuid</code> + <code>/etc/subgid</code> entries on the host. CT must be restarted on every change.",
"idmapWhenRich": "You need a <em>specific</em> UID inside the CT to map to a <em>specific</em> UID on the host (e.g. <code>media:1000</code> in the CT must own files as <code>media:1000</code> on the host so NFS doesn't squash). A more rigid setup, normally only worth it for that exact scenario.",
"idmapTipTitle": "When you actually need lxc.idmap",
"idmapTipBody": "If the LXC Mount Manager doesn't cover your case — typically because you need files written from inside the CT to land on the host as a specific UID/GID (NFS exports with <code>all_squash</code>, Samba shares with strict ownership, sharing a directory with a host user that has the same name as someone inside the CT) — that is the moment to add <code>lxc.idmap</code> entries by hand. The Mount Manager won't fight you: the bind-mount line it wrote is independent of any idmap configuration you add later."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Configure LXC Mount Points (Host ↔ Container)</strong>. You will see this sub-menu with three options:",
"imageAlt": "LXC Mount Manager menu — Add / View / Remove"
},
"addFlow": {
"heading": "Add a mount — full flow",
"intro": "The technical view, for when you want to know exactly what each dialog does:"
},
"sources": {
"heading": "What you can pick as a host directory",
"intro": "The host-directory picker is the most thorough one in the Storage &amp; Share section. It scans four sources and presents a deduplicated list:",
"headerSource": "Source",
"headerWhere": "Where it comes from",
"headerLabel": "Label in the menu",
"rows": [
{
"source": "Active network mounts",
"whereRich": "CIFS / NFS shares currently mounted, parsed from <code>/proc/mounts</code>.",
"labelRich": "<code>NFS [used/size]</code> or <code>CIFS/SMB [used/size]</code>"
},
{
"source": "Inactive fstab mounts",
"whereRich": "Defined in <code>/etc/fstab</code> but not currently mounted.",
"labelRich": "<code>fstab(off)-NFS</code> / <code>fstab(off)-CIFS/SMB</code>"
},
{
"source": "Local directories",
"whereRich": "Sub-directories under <code>/mnt</code> that are not network mounts.",
"labelRich": "<code>Local [size]</code>"
},
{
"source": "Proxmox storages",
"whereRich": "Storage paths under <code>/mnt/pve/*</code> (NFS / CIFS registered via <code>pvesm</code>).",
"labelRich": "<code>PVE-NFS</code> / <code>PVE-CIFS/SMB</code> / <code>Proxmox-Storage</code>"
},
{
"source": "Manual entry",
"where": "Anything else — type the absolute path yourself.",
"labelRich": "<em>Enter path manually</em>"
}
],
"tipTitle": "Internal Proxmox paths are filtered out",
"tipBody": "The picker explicitly skips internal Proxmox paths (<code>/mnt/pve/local</code>, <code>/mnt/pve/local-lvm</code>, <code>/mnt/pve/backup</code>, …) — those are reserved for Proxmox internals and you should not bind-mount them. Only user-added storages show up."
},
"manual": {
"heading": "Manual equivalent",
"privIntro": "For a privileged container — the simplest case, no permission tricks:",
"unprivLocalIntro": "For an unprivileged container with a local host directory — open up permissions on the host first:",
"unprivCifsIntro": "For an unprivileged container with a CIFS share already mounted on the host:"
},
"view": {
"heading": "View mount points",
"body": "Lists every <code>mpN</code> entry across every container on this Proxmox host, grouped by CT id and showing host path → container path plus any extra options. Read-only — useful as a sanity check before you add or remove anything."
},
"remove": {
"heading": "Remove a mount point",
"body": "Pick the container, pick the <code>mpN</code> entry, confirm. The script runs <code>pct set --delete mpN</code> to drop the entry from the CT config and offers to restart the container if it's running. The host directory and its contents are <strong>not touched</strong> — you can re-add the mount later (or attach the same directory to a different CT).",
"warnTitle": "Live-running containers need a restart for changes to take effect",
"warnBody": "Both adding and removing mount points only become visible inside the container after a restart. The script offers a one-click <code>pct reboot</code> at the end of each operation; you can decline and reboot manually later."
},
"troubleshoot": {
"heading": "Troubleshooting",
"noMountTitle": "Mount appears in pct config but not inside the container",
"noMountBody": "Bind mounts only attach when the container starts. If you added the mount while the CT was running, restart it (<code>pct reboot &lt;ctid&gt;</code>). If it's already restarted and still missing, check <code>pct config &lt;ctid&gt;</code> to confirm the entry exists and the host path actually contains a directory.",
"noWriteTitle": "Container can see the directory but cannot write",
"noWriteBody": "Almost always a permissions issue. For unprivileged containers, run the script's permission fix again — the host directory's ACLs may have been reset by another tool (rsync, restore from backup, manual <code>chmod</code>). For CIFS, double-check the mount options on the host: <code>findmnt /mnt/pve/cifs-…</code>, look for <code>uid=</code> / <code>gid=</code> / <code>file_mode=</code> values.",
"alreadyTitle": "\"This path is already used as a mount point in this container\"",
"alreadyBody": "You picked the same container path that's already wired to a different host directory. Either pick a different container path, or remove the existing mount point first.",
"nfsTitle": "NFS access blocked even after applying the host fix",
"nfsIntro": "Your NFS server is squashing root or all connections. The script can detect this (it tries to write a test file from the host) and shows server-side guidance. Two common server-side fixes for the export:",
"nfsItems": [
"<code>no_root_squash</code> — privileged CTs can write directly.",
"<code>all_squash,anonuid=65534,anongid=65534</code> — for unprivileged CTs."
],
"nfsOutro": "These changes happen on the NFS server (TrueNAS, Synology, your custom export, …), not on Proxmox.",
"fstabOffTitle": "Mounting \"fstab(off)\" entries does nothing",
"fstabOffBody": "The picker shows <code>fstab(off)-</code> entries when a network mount is defined in fstab but not currently mounted. The script lets you bind-mount the path, but the directory will be empty until you actually mount the share (<code>mount &lt;path&gt;</code> on the host). Mount it first, then bind it into the CT."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/host-local-shared",
"label": "Add Shared Directory on Host",
"tailRich": " — typical first step: prepare a <code>/mnt/shared</code> on the host before bind-mounting it into one or more CTs here."
},
{
"href": "/docs/storage-share/host-nfs",
"label": "Add NFS share as Proxmox storage",
"extraHref": "/docs/storage-share/host-samba",
"extraLabel": "Add Samba share as Proxmox storage",
"joiner": " / ",
"tailRich": " — register an external share in Proxmox first, then bind-mount its <code>/mnt/pve/&lt;id&gt;</code> path into the CT here."
},
{
"href": "/docs/storage-share/lxc-nfs-client",
"label": "NFS client in LXC",
"extraHref": "/docs/storage-share/lxc-samba-client",
"extraLabel": "Samba client in LXC",
"joiner": " / ",
"tail": " — the alternative when you want the CT itself to mount the share (requires a privileged container)."
}
]
}
}
@@ -0,0 +1,128 @@
{
"meta": {
"title": "NFS client in LXC | ProxMenux Documentation",
"description": "Mount NFS shares directly from inside a Proxmox LXC container with ProxMenux. Auto-installs nfs-common, supports auto-discovery on the LAN, persistent mounts via /etc/fstab, and safe boot behaviour. Requires a privileged container.",
"ogTitle": "NFS client in LXC | ProxMenux Documentation",
"ogDescription": "Mount NFS shares from inside a privileged LXC container. Auto-discovery, /etc/fstab persistence, safe boot defaults."
},
"header": {
"title": "NFS client in LXC",
"description": "Mount NFS shares directly from inside a Proxmox LXC container. The container becomes a real NFS client — talks to the NFS server over the network, runs mount.nfs, writes to /etc/fstab. ProxMenux installs nfs-common for you, helps you find servers and exports, and applies safe boot defaults.",
"section": "Storage & Share · LXC"
},
"privReq": {
"title": "Privileged container required",
"body": "The kernel <code>mount.nfs</code> client needs capabilities (<code>SYS_ADMIN</code> at minimum) that unprivileged LXC containers do not expose. The script enforces this — it asks you to pick a CT and <strong>aborts if it is unprivileged</strong>. If you need the share inside an unprivileged CT, mount it on the Proxmox host first (with <hostNfsLink>NFS share as Proxmox storage</hostNfsLink>) and bind-mount it into the CT with the <mountLink>LXC Mount Manager</mountLink>."
},
"what": {
"heading": "What this does",
"body": "Unlike the LXC Mount Manager — which makes the CT see something <em>via</em> the Proxmox host — this script gives the container its <strong>own NFS client</strong>: it speaks NFS over the network, mounts shares directly from the NFS server, and stores the mount in the container's <code>/etc/fstab</code>. The Proxmox host is not in the data path.",
"diagramServerLabel": "NFS Server",
"diagramServerDetail": "/export/data",
"diagramHostLabel": "Proxmox Host",
"diagramHostDetail": "(just a\nnetwork bridge)",
"diagramCtLabel": "LXC (privileged)",
"diagramCtDetail": "/mnt/data\nmount.nfs inside CT",
"diagramArrow": "NFS",
"twoWaysTitle": "Two ways to give a CT NFS access — pick one",
"twoWaysBind": "<strong>Bind mount via host</strong> (<mountLink>LXC Mount Manager</mountLink>): host mounts the NFS once, every CT bind-mounts the same path. Works with unprivileged CTs. Recommended when several CTs need the same share.",
"twoWaysDirect": "<strong>Direct NFS mount inside the CT</strong> (this page): the CT mounts the NFS itself. Requires privileged. Useful when the CT must own its connection / credentials, or for setups where each CT talks to a different server."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Configure NFS Client in LXC (only privileged)</strong>. ProxMenux first asks you to <strong>pick the target CT</strong> (and starts it if stopped); aborts if unprivileged. Once the CT is selected, you see this sub-menu:",
"imageAlt": "NFS Client Manager menu — Mount / View / Unmount / Test connectivity"
},
"howRuns": {
"heading": "How the script runs (Mount flow)"
},
"fstabFlags": {
"heading": "Why those fstab flags",
"intro": "For permanent mounts the script adds three flags beyond the standard NFS options: <code>_netdev,x-systemd.automount,noauto</code>. Each one solves a real boot-time problem:",
"headerFlag": "Flag",
"headerEffect": "What it does",
"rows": [
{
"flag": "_netdev",
"effect": "Tells the init system this mount needs the network. Boot does not block waiting for it before networking is up."
},
{
"flag": "x-systemd.automount",
"effectRich": "Creates a systemd auto-mount unit: the mount only happens the first time something accesses <code>/mnt/&lt;path&gt;</code>. NFS server unreachable at boot does not stall the CT."
},
{
"flag": "noauto",
"effect": "Skip the eager mount at boot. Combined with the automount unit above, the mount is established lazily on first access."
}
],
"netEffectTitle": "Net effect",
"netEffectBody": "Your container always boots, even if the NFS server is offline. The first time something touches the mount path, systemd quietly mounts it. If the server is still down, that one access fails with <em>resource temporarily unavailable</em> — but nothing else in the CT is affected."
},
"manual": {
"heading": "Manual equivalent",
"body": "Replicate the whole flow by hand — every command runs <strong>inside the CT</strong> via <code>pct exec &lt;ctid&gt; --</code> or directly via <code>pct enter &lt;ctid&gt;</code>:"
},
"view": {
"heading": "View current mounts",
"body": "Lists every NFS mount point active inside the CT (<code>mount | grep nfs</code>) plus every NFS line in the CT's <code>/etc/fstab</code>. For each fstab entry, the live mount status is shown — useful to spot permanent mounts that did not come up at boot."
},
"unmount": {
"heading": "Unmount NFS share",
"body": "Combines the live mounts and the fstab entries into one list, lets you pick one, and <strong>removes the corresponding line from <code>/etc/fstab</code></strong>. The script does <em>not</em> run <code>umount</code> on the live mount — instead it tells you a CT reboot is needed for the unmount to take effect.",
"warnTitle": "The script removes fstab entries, not live mounts",
"warnBody": "This is a deliberate design choice: <code>umount</code> on a busy mount fails with \"device busy\" when something inside the CT is still using it. Removing the fstab entry guarantees the mount disappears cleanly on the next CT start. If you want the mount gone <em>now</em> and you are sure nothing is using it, run <code>pct exec &lt;ctid&gt; -- umount /mnt/&lt;path&gt;</code> by hand after the script finishes."
},
"test": {
"heading": "Test NFS connectivity",
"body": "Diagnostic pass inside the CT: confirms <code>nfs-common</code> is installed, <code>rpcbind</code> is running, lists current NFS mounts, then iterates over every NFS server referenced in fstab and checks ping → port 2049 → <code>showmount -e</code>. Good first stop when a permanent mount fails to come up."
},
"troubleshoot": {
"heading": "Troubleshooting",
"privTitle": "Privileged container required (script aborts)",
"privBody": "The selected CT is unprivileged. The kernel NFS client needs <code>SYS_ADMIN</code> capability that unprivileged CTs do not expose. Either convert the CT to privileged (Disk Manager &amp; conversion is documented in the <importLink>Import Disk to LXC</importLink> page) or use the alternative path described in the warning at the top of this page.",
"aptTitle": "apt-get install nfs-common fails",
"aptIntro": "The script assumes a Debian-family CT (<code>apt-get</code>). If the CT runs Alpine / Arch / Rocky / Alma, the install step fails silently. Install the NFS client by hand for that distro:",
"aptItems": [
"Alpine: <code>apk add nfs-utils</code>",
"Arch: <code>pacman -S nfs-utils</code>",
"Rocky / Alma: <code>dnf install nfs-utils</code>"
],
"aptOutro": "Then re-run the ProxMenux script — the install step skips when the tools are already present.",
"portTitle": "\"NFS port (2049) is not accessible\"",
"portBody": "Ping succeeded but <code>nc -z &lt;server&gt; 2049</code> failed from inside the CT. Check that the NFS service is running on the server, that the firewall allows 2049 from the CT's network, and that the CT actually has a valid network route (try <code>pct exec &lt;ctid&gt; -- ip route</code>).",
"bootTitle": "Permanent mount succeeds but does not come up at boot",
"bootBody": "Almost always one of: the network is not ready when the CT mounts (the script's <code>_netdev,x-systemd.automount,noauto</code> flags fix this — re-add the mount via the script if you wrote the fstab line by hand without those), the server is unreachable at boot (auto-mount waits for first access — that's normal), or DNS is unresolved at boot (use the server's IP, not its hostname).",
"squashTitle": "Server squashes root, no write access from inside CT",
"squashIntro": "The NFS export uses <code>root_squash</code> (the default) and the CT writes as root. Two options:",
"squashItems": [
"Server-side: change the export to <code>no_root_squash</code> (only if you trust the CT).",
"CT-side: write as a non-root user that the server accepts, or chown the share appropriately."
],
"squashOutro": "ProxMenux cannot fix this — it is server policy."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Points (Host ↔ Container)",
"tail": " — the alternative for unprivileged CTs: mount on host, bind into CT."
},
{
"href": "/docs/storage-share/lxc-samba-client",
"label": "Samba client in LXC",
"tail": " — sibling page, same pattern for SMB / CIFS shares."
},
{
"href": "/docs/storage-share/lxc-nfs-server",
"label": "NFS server in LXC",
"tailRich": " — the inverse: expose folders <em>from</em> a CT over NFS."
},
{
"href": "/docs/storage-share/host-nfs",
"label": "NFS share as Proxmox storage",
"tail": " — register the share in Proxmox itself instead of inside a single CT."
}
]
}
}
@@ -0,0 +1,159 @@
{
"meta": {
"title": "NFS server in LXC | ProxMenux Documentation",
"description": "Expose folders over NFS from inside a Proxmox LXC container with ProxMenux. Auto-installs nfs-kernel-server, sets up a universal sharedfiles group convention, manages /etc/exports, network ACL and uninstall. Requires a privileged container.",
"ogTitle": "NFS server in LXC | ProxMenux Documentation",
"ogDescription": "Run an NFS server inside a privileged LXC container. Universal sharedfiles group, network ACL and full uninstall."
},
"header": {
"title": "NFS server in LXC",
"description": "Run an NFS kernel server inside a Proxmox LXC container and expose folders to other machines on the network. ProxMenux installs nfs-kernel-server, sets up a universal sharedfiles group convention so multiple privileged CTs can share files cleanly, manages /etc/exports and offers a full uninstall path.",
"section": "Storage & Share · LXC"
},
"privReq": {
"title": "Privileged container required",
"body": "<code>nfs-kernel-server</code> needs to mount the kernel filesystem <code>nfsd</code> at <code>/proc/fs/nfsd</code>, which requires <code>CAP_SYS_ADMIN</code> in the host kernel namespace — not just in the container's user namespace. Unprivileged LXC does not expose that capability. In practice, the service simply fails to start with <code>rpc.nfsd: Unable to access /proc/fs/nfsd errno 2 (No such file or directory)</code> and systemd marks <code>nfs-server.service</code> as a failed dependency. The script enforces a privileged CT and <strong>aborts if it is unprivileged</strong>. If you cannot use a privileged CT, run the NFS server inside a VM."
},
"what": {
"heading": "What this does",
"body": "This is the <em>opposite</em> of the NFS client page. The container becomes an NFS <strong>server</strong>: it exposes a folder of its filesystem to clients on the network. Other CTs, the Proxmox host, VMs or physical machines can then mount that folder.",
"diagramServerLabel": "LXC (privileged) — NFS server",
"diagramServerDetail": "/mnt/data\n(folder you expose)\n\nchown root:sharedfiles\nchmod 2775 (SGID)\n\nnfs-kernel-server\n+ rpcbind running",
"diagramClientLabel": "Any client on the network",
"diagramClientDetail": "another CT, the host,\na VM, a physical machine…",
"diagramArrow": "NFS export"
},
"shared": {
"heading": "The \"sharedfiles\" group convention",
"body": "Before exporting the folder, ProxMenux creates a group called <code>sharedfiles</code> with <strong>GID 101000</strong> inside the container, adds every regular user to it, then sets the export directory to <code>root:sharedfiles</code> with mode <code>2775</code>. The <code>2</code> at the front is the SGID bit — every file or folder created inside automatically inherits the <code>sharedfiles</code> group.",
"gidTitle": "Why GID 101000 specifically",
"gidBody": "It maps to host GID <strong>1000</strong> when an unprivileged container reads the same file (LXC default idmap shifts everything by +100000). In the current ProxMenux flow the NFS server itself runs in a <strong>privileged</strong> CT (no shift on its side), but the convention keeps the group ID numerically consistent with unprivileged client CTs that may mount this share later. Two privileged CTs both using <code>sharedfiles</code> at GID 101000 can read / write each other's files cleanly because the GID numbers match end-to-end.",
"remapTitle": "The script also creates 'remap_*' users — they are vestigial here",
"remapBody": "For every regular user in the CT (and for common UIDs like 33 = www-data, 1000, 1001, 1002), the script creates a parallel <code>remap_&lt;uid&gt;</code> user with UID = <code>&lt;uid&gt; + 100000</code>, all members of <code>sharedfiles</code>. The <code>+100000</code> shift mimics the LXC unprivileged idmap, but since this script enforces a <strong>privileged</strong> CT (no shift), those <code>remap_*</code> users are shadow accounts with no real-world counterpart on the host. They are harmless leftovers from a more ambitious design intent. If you don't see them in <code>getent passwd</code>, nothing breaks."
},
"defaults": {
"heading": "Default export options — read this first",
"warnTitle": "Default options include no_root_squash",
"warnBody": "ProxMenux defaults to <code>rw,sync,no_subtree_check,'<'strong'>'no_root_squash'<'/strong'>'</code>. This means <strong>any client root user can write as root on the export</strong> — appropriate for a trusted home LAN but never for an untrusted network. If your CT is reachable from an untrusted segment (a public network, a VPS, a hostile VLAN), <strong>change the export options to <code>root_squash</code></strong> in the custom-options dialog."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Configure NFS Server in LXC (only privileged)</strong>. ProxMenux first asks you to pick the target CT (and starts it if stopped); aborts if unprivileged. Once the CT is selected you see this sub-menu with five options:",
"imageAlt": "NFS Server Manager menu — Create / View / Delete / Status / Uninstall"
},
"howRuns": {
"heading": "How the script runs (Create flow)"
},
"network": {
"heading": "Network ACL — who can mount the share",
"intro": "The network field in <code>/etc/exports</code> filters which clients are allowed to mount. ProxMenux offers three modes:",
"headerMode": "Mode",
"headerValue": "Value written to /etc/exports",
"headerWhen": "When to pick it",
"rows": [
{
"mode": "Local network",
"value": "192.168.0.0/16",
"whenRich": "Standard home / SOHO LAN. Covers every <code>192.168.*.*</code> address."
},
{
"mode": "Custom subnet",
"value": "your CIDR (e.g. 10.0.0.0/24)",
"when": "When your LAN is not in 192.168.x.x or you want a tighter scope."
},
{
"mode": "Single host",
"value": "your IP (e.g. 10.0.0.42)",
"when": "Only one specific machine should mount. Most restrictive."
}
]
},
"options": {
"heading": "Export options explained",
"headerOption": "Option",
"headerEffect": "What it does",
"rows": [
{
"option": "rw / ro",
"effect": "Allow read-write or read-only access for connecting clients."
},
{
"option": "sync",
"effectRich": "Reply to write requests only after the data is on disk. Safer than <code>async</code> at the cost of throughput."
},
{
"option": "no_subtree_check",
"effect": "Skip the per-request check that the file is still inside the exported subtree. Faster and avoids issues when files are renamed mid-flight."
},
{
"option": "no_root_squash",
"effectRich": "<strong>Trust client root.</strong> A client mounting as root writes as root on the server. Good for trusted LANs (e.g. backup tooling needs to preserve ownership). Replace with <code>root_squash</code> if you don't fully trust every machine on the network ACL."
}
]
},
"manual": {
"heading": "Manual equivalent",
"body": "Replicate the whole flow by hand — every command runs <strong>inside the CT</strong> via <code>pct exec &lt;ctid&gt; --</code> or <code>pct enter &lt;ctid&gt;</code>:"
},
"view": {
"heading": "View current exports",
"body": "Cats <code>/etc/exports</code> from inside the CT (skipping comments / blanks) and prints each export with its network ACL and option string. Useful to check which folders are exposed before sharing the CT's IP with someone."
},
"delete": {
"heading": "Delete an export",
"body": "Lists every line in <code>/etc/exports</code> for selection, removes the chosen one (<code>sed -i</code>), runs <code>exportfs -ra</code> and restarts <code>nfs-kernel-server</code>. The folder itself and its contents are left intact."
},
"status": {
"heading": "Check NFS status",
"body": "Diagnostic pass: confirms <code>nfs-kernel-server</code> and <code>rpcbind</code> are installed and active, prints <code>exportfs -v</code> output, lists active NFS sessions (<code>showmount -a</code>) and current client connections."
},
"uninstall": {
"heading": "Uninstall NFS server",
"body": "Full clean-up after confirmation: stops + disables <code>nfs-kernel-server</code> and <code>rpcbind</code>, clears <code>/etc/exports</code>, <code>apt-get purge</code> the NFS packages, removes the <code>sharedfiles</code> group and the <code>remap_*</code> users, kills any leftover processes. The exported <strong>folders themselves are not deleted</strong> — only the NFS configuration and packages.",
"warnTitle": "The script stops at the export line, not at the data",
"warnBody": "Both <em>Delete export</em> and <em>Uninstall NFS server</em> remove the export configuration. The data on the exported folder is preserved. To delete the data too, do it explicitly with <code>rm -rf</code> after the script finishes — and back it up first if anyone might still need it."
},
"troubleshoot": {
"heading": "Troubleshooting",
"privTitle": "Privileged container required (script aborts)",
"privBody": "The selected CT is unprivileged. <code>nfs-kernel-server</code> cannot start there because mounting <code>/proc/fs/nfsd</code> needs <code>CAP_SYS_ADMIN</code> in the host kernel namespace, and the <code>nfsd</code> module is not exposed to the container's namespace either (<code>modprobe nfsd</code> from inside returns <code>FATAL: Module nfsd not found</code>). If you bypass the gate, you will see <code>rpc.nfsd: Unable to access /proc/fs/nfsd errno 2 (No such file or directory)</code> in the journal and no NFS ports will ever open. The only workable options are: convert the CT to privileged, or move the NFS server to a VM.",
"aptTitle": "apt-get install fails",
"aptIntro": "The script assumes a Debian-family CT. On Alpine / Arch / Rocky / Alma, install the NFS server packages by hand:",
"aptItems": [
"Alpine: <code>apk add nfs-utils</code>",
"Arch: <code>pacman -S nfs-utils</code>",
"Rocky / Alma: <code>dnf install nfs-utils</code>"
],
"aptOutro": "Then re-run the ProxMenux script — the install step skips when the tools are already present.",
"aclTitle": "Client cannot mount: 'access denied by server'",
"aclBody": "The client's IP is outside the network ACL you configured. Re-create the export with a wider subnet, or add the client's exact IP. Common gotcha: clients connecting through a router NAT may appear with the router's WAN IP, not the client's LAN IP — check on the server with <code>tcpdump -n port 2049</code>.",
"ownTitle": "Files written by the client appear with weird ownership on the server",
"ownIntro": "Two possibilities:",
"ownItems": [
"With <code>no_root_squash</code> (default), client root writes as root on the server. Files are owned by <code>root:sharedfiles</code> thanks to the SGID on the folder.",
"Non-root client users write as their own UID/GID. If their UID does not exist on the server, files appear with raw numbers (e.g. <code>1234:1234</code>). Use the <code>sharedfiles</code> group on the client too, or align UIDs across the systems that share files."
],
"noShowTitle": "Server reachable but showmount returns nothing",
"noShowBody": "After editing <code>/etc/exports</code>, you must reload the export table with <code>exportfs -ra</code> and restart <code>nfs-kernel-server</code> — the script does both, but if you edited the file by hand, do it yourself. Also confirm the firewall on the CT (and on the Proxmox host) allows TCP/UDP 2049 and the rpcbind port (111)."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/lxc-nfs-client",
"label": "NFS client in LXC",
"tail": " — the inverse: mount external NFS shares from inside a CT."
},
{
"href": "/docs/storage-share/lxc-samba-server",
"label": "Samba server in LXC",
"tail": " — sibling page, same pattern with SMB / CIFS instead of NFS."
},
{
"href": "/docs/storage-share/host-nfs",
"label": "NFS share as Proxmox storage",
"tailRich": " — once your CT is exporting, register that NFS share in Proxmox so it appears under <em>Datacenter → Storage</em>."
}
]
}
}
@@ -0,0 +1,155 @@
{
"meta": {
"title": "Samba client in LXC | ProxMenux Documentation",
"description": "Mount Samba / CIFS shares directly from inside a Proxmox LXC container with ProxMenux. Auto-installs cifs-utils + smbclient, supports auto-discovery, secure credential storage, and persistent mounts via /etc/fstab. Requires a privileged container.",
"ogTitle": "Samba client in LXC | ProxMenux Documentation",
"ogDescription": "Mount Samba / CIFS shares from inside a privileged LXC container. Auto-discovery, secure credential file, /etc/fstab persistence."
},
"header": {
"title": "Samba client in LXC",
"description": "Mount Samba (SMB / CIFS) shares directly from inside a Proxmox LXC container. The container becomes a real CIFS client — talks to the Samba server over the network, runs mount.cifs, stores credentials securely, and writes to /etc/fstab. ProxMenux installs cifs-utils + smbclient for you and validates credentials against the server before mounting.",
"section": "Storage & Share · LXC"
},
"privReq": {
"title": "Privileged container required",
"body": "The kernel <code>mount.cifs</code> client needs capabilities (<code>SYS_ADMIN</code> at minimum) that unprivileged LXC containers do not expose. The script enforces this — it asks you to pick a CT and <strong>aborts if it is unprivileged</strong>. If you need the share inside an unprivileged CT, mount it on the Proxmox host first (with <hostSambaLink>Samba / CIFS as Proxmox storage</hostSambaLink>) and bind-mount it into the CT with the <mountLink>LXC Mount Manager</mountLink>."
},
"what": {
"heading": "What this does",
"body": "The container speaks CIFS over the network and mounts the share on its own. The Proxmox host is just the network bridge — it does not see or manage the mount.",
"diagramServerLabel": "Samba Server",
"diagramServerDetail": "//srv/share",
"diagramHostLabel": "Proxmox Host",
"diagramHostDetail": "(just a\nnetwork bridge)",
"diagramCtLabel": "LXC (privileged)",
"diagramCtDetail": "/mnt/share\nmount.cifs inside CT",
"diagramArrow": "CIFS",
"twoWaysTitle": "Two ways to give a CT a Samba share — pick one",
"twoWaysBind": "<strong>Bind mount via host</strong> (<mountLink>LXC Mount Manager</mountLink>): host mounts the CIFS once, every CT bind-mounts the same path. Works with unprivileged CTs. Recommended when several CTs need the same share.",
"twoWaysDirect": "<strong>Direct CIFS mount inside the CT</strong> (this page): the CT mounts the CIFS itself. Requires privileged. Useful when the CT must own its own credentials, or when each CT talks to a different server."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Configure Samba Client in LXC (only privileged)</strong>. ProxMenux first asks you to <strong>pick the target CT</strong> (and starts it if stopped); aborts if unprivileged. Once the CT is selected you see this sub-menu:",
"imageAlt": "Samba Client Manager menu — Mount / View / Unmount / Test connectivity"
},
"howRuns": {
"heading": "How the script runs (Mount flow)"
},
"creds": {
"heading": "Where the password lives",
"body": "ProxMenux <strong>never stores the password in plain text</strong> in the mount command or in <code>/etc/fstab</code>. Instead it writes a credentials file inside the CT:",
"whyTitle": "Why a separate file rather than fstab",
"whyBody": "The CIFS module accepts <code>username=</code> / <code>password=</code> options inline in fstab, but anyone who can read <code>/etc/fstab</code> sees the password in clear. Putting credentials in a root-only file and pointing fstab at it (<code>credentials=</code>) keeps the password out of world-readable config."
},
"options": {
"heading": "Mount options explained",
"headerOption": "Option",
"headerEffect": "What it does",
"rows": [
{
"option": "rw / ro",
"effect": "Read-write or read-only mode for the whole mount."
},
{
"option": "file_mode=0664",
"effect": "Permissions reported for files via CIFS. Default lets owner+group write, others read."
},
{
"option": "dir_mode=0775",
"effect": "Permissions reported for directories. Default lets owner+group enter and create, others traverse."
},
{
"option": "iocharset=utf8",
"effect": "Force UTF-8 for filenames coming over the wire. Avoids mojibake on non-ASCII names."
},
{
"option": "credentials=file",
"effect": "Read username / password from the file (added automatically for user auth)."
},
{
"option": "guest",
"effect": "Authenticate as guest, no credentials needed (added automatically when guest is chosen)."
},
{
"option": "_netdev",
"effect": "Tells the init system this mount needs the network. Boot does not block waiting for it."
},
{
"option": "x-systemd.automount",
"effect": "Lazy mount: only mounts on first access. CIFS server unreachable at boot does not stall the CT."
},
{
"option": "noauto",
"effect": "Skip eager mount at boot. Combined with the automount unit, the mount is established lazily."
}
],
"netEffectTitle": "Net effect of the fstab flags",
"netEffectBody": "Your container always boots, even if the Samba server is offline. The first time something touches the mount path, systemd quietly mounts it. If the server is still down, that one access fails with <em>resource temporarily unavailable</em> — but nothing else in the CT is affected."
},
"manual": {
"heading": "Manual equivalent",
"body": "Replicate the whole flow by hand — every command runs <strong>inside the CT</strong> via <code>pct exec &lt;ctid&gt; --</code> or directly via <code>pct enter &lt;ctid&gt;</code>:",
"guestIntro": "Guest variant — no credentials file needed:"
},
"view": {
"heading": "View current mounts",
"body": "Lists every CIFS mount point active inside the CT (<code>mount -t cifs</code>) plus every CIFS line in the CT's <code>/etc/fstab</code>. For each fstab entry the live mount status is shown — useful to spot permanent mounts that did not come up at boot."
},
"unmount": {
"heading": "Unmount Samba share",
"body": "Combines the live mounts and the fstab entries into one list, lets you pick one, and <strong>removes the corresponding line from <code>/etc/fstab</code></strong> plus the matching credentials file. The script does not run <code>umount</code> on the live mount — instead it tells you a CT reboot is needed for the unmount to take effect.",
"warnTitle": "The script removes fstab entries, not live mounts",
"warnBody": "Same design as the NFS client: <code>umount</code> on a busy mount fails with \"device busy\". Removing the fstab entry guarantees the mount disappears cleanly on the next CT start. If you want the mount gone <em>now</em>, run <code>pct exec &lt;ctid&gt; -- umount /mnt/&lt;path&gt;</code> by hand after the script finishes."
},
"test": {
"heading": "Test Samba connectivity",
"body": "Diagnostic pass inside the CT: confirms <code>cifs-utils</code> is installed, lists current CIFS mounts, then for every server referenced in fstab checks ping → ports 139/445 → guest listing. \"Requires authentication\" on the guest test is normal for any server that doesn't expose public shares."
},
"troubleshoot": {
"heading": "Troubleshooting",
"privTitle": "Privileged container required (script aborts)",
"privBody": "The selected CT is unprivileged. The kernel CIFS client needs <code>SYS_ADMIN</code> capability that unprivileged CTs do not expose. Either convert the CT to privileged, or use the alternative path described in the warning at the top of this page.",
"aptTitle": "apt-get install fails",
"aptIntro": "The script assumes a Debian-family CT (<code>apt-get</code>). On Alpine / Arch / Rocky / Alma, install the CIFS client by hand:",
"aptItems": [
"Alpine: <code>apk add cifs-utils samba-client</code>",
"Arch: <code>pacman -S cifs-utils smbclient</code>",
"Rocky / Alma: <code>dnf install cifs-utils samba-client</code>"
],
"aptOutro": "Then re-run the ProxMenux script — the install step skips when the tools are already present.",
"guestFallbackTitle": "\"The server connected you as guest instead of the specified user\"",
"guestFallbackBody": "The script's active validation caught a real auth problem. The server accepted the connection but downgraded it to guest because the credentials are wrong. Common causes: typo in the username / password, the user does not exist on the server, the user is locked out, or the workgroup / domain is mismatched. Re-run the flow and re-enter credentials carefully (the password is hidden in the dialog).",
"denyTitle": "\"NT_STATUS_ACCESS_DENIED\" when mounting",
"denyBody": "Credentials were validated but the share denies access. Check on the server side whether the user has permissions on that specific share (validation only confirms login, not per-share ACLs). Also check whether the server requires a specific SMB protocol version: append <code>vers=3.0</code> (or <code>2.1</code>, <code>2.0</code>) to the mount options.",
"utf8Title": "UTF-8 / non-ASCII filenames are mangled",
"utf8Body": "The default options include <code>iocharset=utf8</code>, but some server configurations report an unexpected codepage. If filenames with accents / symbols look wrong, also try <code>nounix</code> (some Linux Samba servers need this when the client is also Linux) or set the server side to <code>unix extensions = no</code>.",
"bootTitle": "Permanent mount succeeds but does not come up at boot",
"bootBody": "Almost always one of: the network is not ready when the CT mounts (the script's <code>_netdev,x-systemd.automount,noauto</code> flags fix this), the server is unreachable at boot (auto-mount waits for first access — that's normal), or DNS is unresolved at boot (use the server's IP, not its hostname)."
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/lxc-mount-points",
"label": "LXC Mount Points (Host ↔ Container)",
"tail": " — the alternative for unprivileged CTs: mount on host, bind into CT."
},
{
"href": "/docs/storage-share/lxc-nfs-client",
"label": "NFS client in LXC",
"tail": " — sibling page, same pattern for NFS shares."
},
{
"href": "/docs/storage-share/lxc-samba-server",
"label": "Samba server in LXC",
"tailRich": " — the inverse: expose folders <em>from</em> a CT over Samba."
},
{
"href": "/docs/storage-share/host-samba",
"label": "Samba / CIFS as Proxmox storage",
"tail": " — register the share in Proxmox itself instead of inside a single CT."
}
]
}
}
@@ -0,0 +1,132 @@
{
"meta": {
"title": "Samba server in LXC | ProxMenux Documentation",
"description": "Run a Samba (SMB / CIFS) server inside a Proxmox LXC container with ProxMenux. Auto-installs samba, manages /etc/samba/smb.conf, smbpasswd users, sharedfiles group for bind-mounted folders. Requires a privileged container.",
"ogTitle": "Samba server in LXC | ProxMenux Documentation",
"ogDescription": "Expose folders over SMB/CIFS from inside a privileged LXC container. Auto-install, smbpasswd user, bind-mount aware permissions."
},
"header": {
"title": "Samba server in LXC",
"description": "Run a Samba (SMB / CIFS) server inside a Proxmox LXC container and expose folders to Windows / macOS / Linux clients on the network. ProxMenux installs samba, creates a Samba user with smbpasswd, manages /etc/samba/smb.conf, and applies bind-mount aware permissions when the shared folder comes from the host.",
"section": "Storage & Share · LXC"
},
"privReq": {
"title": "Privileged container required",
"body": "Samba impersonates the connecting user with <code>setgroups()</code> on every tree connection (the moment a client opens a share). In an unprivileged LXC, the kernel rejects that syscall because the container's user namespace is created with <code>setgroups=deny</code> — and <code>smbd</code> responds by aborting the worker process with <code>PANIC: sys_setgroups failed</code>. The result is that <code>smbd</code> starts and binds ports 139/445, but every client connection fails with <code>NT_STATUS_CONNECTION_DISCONNECTED</code>. The script enforces a privileged CT for this reason and <strong>aborts if it is unprivileged</strong>. There is no clean fix on the server side; use a privileged CT, or run Samba inside a VM."
},
"what": {
"heading": "What this does",
"body": "The container becomes an SMB/CIFS server: it runs <code>smbd</code>, exposes a folder via <code>/etc/samba/smb.conf</code> and accepts client connections on ports <code>139</code> / <code>445</code>. Clients see the share at <code>\\\\&lt;ct-ip&gt;\\&lt;share-name&gt;</code> in Windows Explorer, <code>smb://&lt;ct-ip&gt;/&lt;share-name&gt;</code> in macOS Finder, or via <code>mount.cifs</code> on Linux.",
"diagramServerLabel": "LXC (privileged) — Samba server",
"diagramServerDetail": "/mnt/data\n(folder you expose)\n\nsmbd + nmbd running\n\nUser: <username>\n(via smbpasswd)\n\nForce group:\nsharedfiles",
"diagramClientLabel": "Any client on the network",
"diagramClientDetail": "Windows: \\\\<ip>\\<share>\nmacOS: smb://<ip>/<share>\nLinux: mount.cifs",
"diagramArrow": "SMB / CIFS"
},
"perms": {
"heading": "Two permission paths depending on the folder type",
"body": "Before adding the share to <code>smb.conf</code>, the script checks whether the chosen folder is a <strong>bind mount from the host</strong> or a regular <strong>local folder inside the CT</strong> — and applies different ownership / permissions accordingly:",
"headerType": "Folder type",
"headerAction": "What the script does",
"bindType": "Bind-mount from host",
"bindTypeSubRich": "detected via <code>mount</code> output",
"bindActionRich": "Creates group <code>sharedfiles</code> (default GID 999, dynamic if taken), adds the Samba user to it, then <code>chown root:sharedfiles</code> + <code>chmod 2775</code> (SGID — new files inherit the group). If the user still cannot write, applies <code>setfacl -m u:&lt;user&gt;:rwx</code>.",
"localType": "Local folder inside CT",
"localTypeSub": "no bind mount detected",
"localActionRich": "Standard ownership: <code>chown -R &lt;user&gt;:&lt;user&gt;</code> + <code>chmod -R 755</code>. No shared group needed because no other CT writes to this folder. Falls back to <code>setfacl</code> if write access is still missing.",
"gidTitle": "GID for 'sharedfiles' differs from the NFS server flow",
"gidBody": "The Samba server script uses GID <strong>999</strong> for <code>sharedfiles</code>, while the <nfsLink>NFS server flow</nfsLink> uses GID <strong>101000</strong>. If you run both servers in the same CT and want a single shared group across both protocols, edit one of them to match the other after the install (e.g. <code>groupmod -g 101000 sharedfiles</code>) and re-apply ownership on the affected folders. This is a known inconsistency in the current scripts."
},
"opening": {
"heading": "Opening the tool",
"body": "From ProxMenux's main menu, open <strong>Storage &amp; Share Manager → Configure Samba Server in LXC (only privileged)</strong>. ProxMenux first asks you to pick the target CT (and starts it if stopped); aborts if unprivileged. Once the CT is selected you see this sub-menu with five options:",
"imageAlt": "Samba Server Manager menu — Create / View / Delete / Status / Uninstall"
},
"howRuns": {
"heading": "How the script runs (Create flow)"
},
"modes": {
"heading": "The three share modes",
"intro": "Each mode writes a different stanza to <code>smb.conf</code>. All three include <code>valid users = &lt;username&gt;</code> (no anonymous), <code>force group = sharedfiles</code> (so new files belong to the shared group) and <code>veto files = /lost+found/</code> (hides it from clients).",
"headerMode": "Mode",
"headerBlock": "Block written to smb.conf",
"rwMode": "Read-Write",
"roMode": "Read-Only",
"customMode": "Custom",
"customBodyRich": "You type your own directives in a free-text box. ProxMenux still wraps them in a <code>[share]</code> block with the standard <code>path</code>, <code>valid users</code>, <code>force group</code> and <code>veto files</code>."
},
"manual": {
"heading": "Manual equivalent",
"body": "Replicate the whole flow by hand — every command runs <strong>inside the CT</strong> via <code>pct exec &lt;ctid&gt; --</code> or <code>pct enter &lt;ctid&gt;</code>:"
},
"connect": {
"heading": "Connecting from clients",
"headerOs": "Client OS",
"headerHow": "How to connect",
"windowsOs": "Windows",
"windowsHowRich": "File Explorer → address bar: <code>\\\\&lt;ct-ip&gt;\\&lt;share-name&gt;</code>. Or <em>Map Network Drive</em> → check \"Connect using different credentials\".",
"macosOs": "macOS",
"macosHowRich": "Finder → <em>Go → Connect to Server…</em> → <code>smb://&lt;ct-ip&gt;/&lt;share-name&gt;</code>. Or <code>mount_smbfs //user@&lt;ct-ip&gt;/&lt;share&gt; /mountpoint</code>.",
"linuxOs": "Linux",
"linuxHowRich": "<code>mount -t cifs //&lt;ct-ip&gt;/&lt;share&gt; /mnt/x -o username=&lt;u&gt;,password=&lt;p&gt;,iocharset=utf8</code>. Or use the <clientLink>Samba client in LXC</clientLink> page if the client is another Proxmox CT."
},
"view": {
"heading": "View current shares",
"body": "Parses <code>/etc/samba/smb.conf</code> inside the CT and lists every <code>[share]</code> block (skipping <code>[global]</code>, <code>[homes]</code>, <code>[printers]</code>) with its path. Useful as a quick inventory."
},
"delete": {
"heading": "Delete a share",
"body": "Lets you pick a share by name, removes the block from <code>smb.conf</code> (<code>sed</code> deletes from <code>[share]</code> down to the next blank line), and restarts <code>smbd</code>. The folder itself and its contents are left intact."
},
"status": {
"heading": "Check Samba status",
"body": "Reports whether <code>smbd</code> and <code>nmbd</code> are installed and active, lists Samba users (<code>pdbedit -L</code>) and prints active sessions (<code>smbstatus</code>)."
},
"uninstall": {
"heading": "Uninstall Samba server",
"body": "Full clean-up after confirmation: stops + disables <code>smbd</code> and <code>nmbd</code>, backs up <code>smb.conf</code> to <code>smb.conf.backup.YYYYMMDD_HHMMSS</code>, removes Samba users with <code>smbpasswd -x</code>, and <code>apt-get purge</code> the Samba packages. The exported <strong>folders themselves are not deleted</strong>.",
"warnTitle": "Folders survive — back up data separately",
"warnBody": "Both <em>Delete share</em> and <em>Uninstall Samba server</em> remove the share configuration. The data on the exported folders is preserved. To delete the data too, do it explicitly with <code>rm -rf</code> after the script finishes."
},
"troubleshoot": {
"heading": "Troubleshooting",
"privTitle": "Privileged container required (script aborts)",
"privBody": "The selected CT is unprivileged and <code>smbd</code> cannot serve files there. If you bypass the gate and configure Samba by hand, <code>smbd</code> starts and the ports open, but the first client connection panics with <code>PANIC: sys_setgroups failed</code> in <code>/var/log/samba/log.&lt;client&gt;</code> and the client sees <code>NT_STATUS_CONNECTION_DISCONNECTED</code>. The cause is the unprivileged user namespace having <code>setgroups=deny</code>, which blocks Samba's per-connection impersonation. Neither <code>features=keyctl=1</code> nor removing <code>force user</code> / <code>force group</code> changes this. The only workable options are: convert the CT to privileged, or move Samba to a VM.",
"aptTitle": "apt-get install fails",
"aptIntro": "The script assumes a Debian-family CT. On Alpine / Arch / Rocky / Alma, install Samba by hand:",
"aptItems": [
"Alpine: <code>apk add samba</code>",
"Arch: <code>pacman -S samba</code>",
"Rocky / Alma: <code>dnf install samba</code>"
],
"aptOutro": "Then re-run the ProxMenux script — the install step skips when the tools are already present.",
"noShareTitle": "Client connects but cannot see the share",
"noShareBody": "Check that <code>browseable = yes</code> is set in the share block (default for rw / ro modes; may be missing in custom). Also check the CT firewall and the Proxmox host firewall allow TCP 445 (SMB) and 139 (NetBIOS). Some Windows clients also require name resolution — try the IP directly first.",
"authTitle": "Authentication fails (NT_STATUS_LOGON_FAILURE)",
"authBody": "Either the wrong password (Samba passwords are <em>separate</em> from system passwords — see them with <code>pdbedit -L</code>) or the user is not in <code>valid users</code> for that share. Reset the password with <code>smbpasswd &lt;user&gt;</code> inside the CT.",
"groupTitle": "Files written by the client appear with wrong group on the server",
"groupBody": "The script sets <code>force group = sharedfiles</code> in the share block, so new files should be group <code>sharedfiles</code>. If they aren't, the SGID bit on the parent directory may have been lost (someone ran <code>chmod</code> by hand). Reapply: <code>chmod 2775 /mnt/&lt;share&gt;</code>.",
"bothTitle": "Sharing the same folder over both NFS and Samba",
"bothBody": "ProxMenux uses different GIDs for <code>sharedfiles</code> in each script (Samba: 999, NFS: 101000). If you serve the same folder via both, decide on one GID and align both. The simplest fix: after running both scripts, edit the smaller GID:"
},
"related": {
"heading": "Related",
"items": [
{
"href": "/docs/storage-share/lxc-samba-client",
"label": "Samba client in LXC",
"tail": " — the inverse: mount external Samba shares from inside a CT."
},
{
"href": "/docs/storage-share/lxc-nfs-server",
"label": "NFS server in LXC",
"tail": " — sibling page, same pattern with NFS instead of CIFS."
},
{
"href": "/docs/storage-share/host-samba",
"label": "Samba / CIFS as Proxmox storage",
"tailRich": " — once your CT is exposing, register that share in Proxmox so it appears under <em>Datacenter → Storage</em>."
}
]
}
}

Some files were not shown because too many files have changed in this diff Show More