docs: promote /web from develop for backup-restore, Log2RAM and Network Flow guides

Brings 69 files from develop under /web/:
- Full Backup & Restore section (11 pages EN + ES: overview, how-it-works, destinations,
  creating backups, scheduled jobs, restoring, cross-kernel hydration)
- Log2RAM dedicated block in post-install/optional with commands + upstream link
- Network Flow diagram documented on monitor/dashboard/network
- Rewritten category descriptions in post-install/customizable
- Fixed automated.json thresholds + link to Log2RAM section
- Updated screenshots (network-flow-overview, storage-top-row, vms modals)

No code, config or AppImage binaries touched — /web/ scope only. Merging deploys
the documentation site to the current beta release notes.
This commit is contained in:
MacRimi
2026-07-04 22:10:49 +02:00
parent a92420d654
commit 720f3fdbd2
69 changed files with 7246 additions and 48 deletions
@@ -0,0 +1,148 @@
{
"meta": {
"title": "Borg destination — repository types, SSH auth, encryption | ProxMenux",
"description": "The Borg destination writes ProxMenux host backups to a Borg repository — local, on a mounted external disk, or on a remote server accessed via SSH. Covers the borg binary resolution chain, the four SSH key strategies, repokey encryption, saved target configuration and per-scheduled-job retention.",
"ogTitle": "ProxMenux Backup — Borg destination",
"ogDescription": "How ProxMenux writes host backups to Borg repositories, with SSH auth strategies and repokey encryption.",
"twitterTitle": "Borg backup destination | ProxMenux",
"twitterDescription": "Local, USB and SSH-served Borg repositories for host backups."
},
"header": {
"title": "Borg",
"description": "The Borg destination writes host backups to a Borg repository. Three repository types are supported: local filesystem path, mounted external disk, or remote server via SSH. Chunk-level deduplication across all archives in the repository and optional repokey encryption.",
"section": "Backup & Restore"
},
"aboutBorg": {
"heading": "What Borg is",
"body": "Borg (also spelled BorgBackup) is an open-source deduplicating backup tool maintained by the Borg Backup community. It stores every archive as a set of variable-length chunks inside a repository; chunks are shared across archives so re-backing up unchanged data has near-zero storage cost. Borg is not tied to Proxmox — it is a general-purpose backup tool used across many environments. ProxMenux uses it as one of the three destinations for host backups; every Borg-specific mechanism described on this page (repository types, borg-serve over SSH, repokey encryption, prune) is standard Borg behaviour."
},
"intro": {
"title": "Chunk-based deduplication with local or SSH-served repositories",
"body": "A Borg repository stores chunks that are shared across every archive it contains, so re-backing up an unchanged file transfers and stores nothing new. ProxMenux invokes <code>borg create</code> against a repository at backup time and <code>borg extract</code> at restore time. The repository can live on the same filesystem as the source, on a mounted external disk, or on a remote host accessed over SSH."
},
"binarySourcing": {
"heading": "The borg binary",
"intro": "Borg is not a base dependency of the ProxMenux installer. When a backup runs, <code>hb_ensure_borg</code> resolves the binary from four sources in order and returns the first that works:",
"rows": [
{ "priority": "1", "source": "System <code>borg</code>", "detail": "If the host already has <code>borg</code> installed via APT (<code>which borg</code> resolves), that binary is used." },
{ "priority": "2", "source": "State-dir cache", "detail": "<code>/usr/local/share/proxmenux/borg</code> — kept from a prior GitHub download on this host." },
{ "priority": "3", "source": "Monitor AppImage bundle", "detail": "<code>/usr/local/share/proxmenux/monitor-app/usr/bin/borg</code> — the AppImage bundles a signed borg-linux64. This is the offline-safe path: a host with no internet still has a working <code>borg</code>." },
{ "priority": "4", "source": "GitHub download", "detail": "<code>wget</code> against the pinned <code>borg-linux64</code> URL under <code>github.com/borgbackup/borg/releases/</code>, verified against a constant SHA-256 in <code>lib_host_backup_common.sh</code> (<code>HB_BORG_LINUX64_SHA256</code>). On checksum mismatch the binary is discarded and the backup aborts. The downloaded file is cached in the state dir so subsequent backups use path 2." }
]
},
"repoTypes": {
"heading": "Repository types",
"intro": "The repository type is chosen when a target is added. Each type resolves to a different repository URL that Borg understands.",
"rows": [
{ "type": "remote", "url": "ssh://USER@HOST/RPATH", "detail": "Repository lives on a remote server that runs <code>borg serve</code>. Requires an SSH connection to that server." },
{ "type": "usb", "url": "/mnt/MOUNTPOINT/borgbackup", "detail": "Repository lives on a mounted external disk (typically USB). The mount is resolved via <code>hb_prompt_mounted_path</code>, which detects, mounts or formats USB partitions as needed." },
{ "type": "local", "url": "/backup/borgbackup (any absolute path)", "detail": "Repository lives on a local directory. Meaningful only when the target directory is on a separate physical disk — a repository on the same disk as the source protects against operator error but not against disk failure." }
]
},
"serverSetup": {
"heading": "Preparing the Borg server (server side)",
"intro": "The <code>remote</code> repository type expects a working Borg server accessible over SSH. ProxMenux does not bootstrap the server itself — it only authorises a key against an existing account on it. This section documents what the server needs before ProxMenux can connect.",
"hostChoicesTitle": "Where the server can live",
"hostChoicesBody": "Any Linux host with SSH access qualifies. Common setups:",
"hostChoicesItems": [
"A dedicated NAS or backup box (Debian, Ubuntu, TrueNAS SCALE with a shell).",
"An LXC container inside a Proxmox node. Small footprint, isolated from the host running the backups.",
"Another Proxmox host on the same LAN, or a VM anywhere reachable over SSH."
],
"lxcWarningTitle": "LXC as Borg server",
"lxcWarningBody": "If the Borg server runs inside an LXC, the container must have a user account with a password.",
"requirementsTitle": "Requirements on the server",
"requirementsRows": [
{ "requirement": "borg binary at <code>/usr/bin/borg</code>", "detail": "The <code>command=\"/usr/bin/borg serve ...\"</code> line ProxMenux writes into <code>authorized_keys</code> hard-codes that path. Installing via APT (<code>apt install borgbackup</code>) puts it there. A standalone binary must be symlinked to <code>/usr/bin/borg</code>." },
{ "requirement": "A dedicated user account (typically <code>borg</code>)", "detail": "Owns the repository directory and receives incoming SSH connections. Does not need sudo or shell access — the authorized_keys line disables interactive shells anyway." },
{ "requirement": "A writable repository directory", "detail": "The path the operator gives ProxMenux (for example <code>/backup/borgbackup</code>) must exist on the server and be owned by the borg user." },
{ "requirement": "SSH daemon accepting the borg user", "detail": "<code>PubkeyAuthentication yes</code> (default). Password authentication is only needed for the one-shot <em>generate-auto</em> flow — after the key is installed, the server can disable password auth entirely." }
],
"minimalSetupTitle": "Minimal server setup",
"minimalSetupBody": "On a Debian or Ubuntu Borg server, a working baseline is four commands as root:",
"minimalSetupCmd": "apt install borgbackup\nuseradd -m -d /home/borg -s /bin/bash borg\nmkdir -p /backup/borgbackup\nchown borg:borg /backup/borgbackup",
"minimalSetupNote": "After this, ProxMenux's <code>generate-auto</code> mode can connect using the borg user's password once, install its own SSH key, and every subsequent backup uses that key. No further server-side configuration is needed — the key restricts itself to <code>borg serve</code> on that path."
},
"sshAuth": {
"heading": "SSH authentication (client side)",
"intro": "Remote Borg repositories are accessed over SSH. The connection runs from the ProxMenux host to a user account on the Borg server that runs <code>borg serve</code>. This user is typically named <code>borg</code>, NOT the admin/root user of the server — the borg-serve command line locks the connection to that specific repository path (see the key strategies below).",
"strategiesTitle": "The four key strategies",
"strategiesIntro": "When a remote target is added, ProxMenux prompts for the SSH user, host and remote path, then asks how to authenticate. Four modes:",
"strategyRows": [
{ "mode": "generate-auto", "label": "Recommended", "detail": "ProxMenux generates a new ed25519 keypair at <code>~/.ssh/borg_proxmenux_HOST_ed25519</code>, then uses <code>sshpass</code> to log in ONCE to the server with the admin password and append the public key to <code>~borg/.ssh/authorized_keys</code>. The admin password is only used for this one call — it is never stored." },
{ "mode": "generate-manual", "label": "No admin password on this host", "detail": "ProxMenux generates the keypair as above but displays the full <code>authorized_keys</code> line for the operator to paste manually into the server. The admin password never leaves the ProxMenux host because it is never asked for." },
{ "mode": "generate-pct", "label": "Borg server is a PVE LXC", "detail": "The Borg server runs inside an LXC on a PVE node. ProxMenux authorises the key via <code>pct exec</code> from the PVE host — root on the PVE host writes into the LXC's <code>~borg/.ssh/authorized_keys</code> without needing SSH into the LXC itself." },
{ "mode": "existing", "label": "Use an existing key", "detail": "ProxMenux scans <code>/root/.ssh/</code> and <code>$HOME/.ssh/</code> for parseable ed25519/RSA private keys and lists them. The operator picks one or browses manually to a non-standard path." },
{ "mode": "none", "label": "Default SSH config", "detail": "No custom key — Borg relies on the host's default SSH configuration (typically <code>~/.ssh/id_rsa</code> or an SSH agent)." }
],
"restrictTitle": "The authorized_keys line",
"restrictBody": "For every generated key, the <code>authorized_keys</code> line ProxMenux writes on the server locks the key to a single borg-serve invocation against the configured repository path:",
"restrictLine": "command=\"/usr/bin/borg serve --restrict-to-path RPATH\",restrict PUBKEY",
"restrictNote": "The <code>command=</code> forces every SSH session using this key to run only that borg-serve command; <code>restrict</code> disables port forwarding, agent forwarding, X11 forwarding and PTY allocation. The key cannot be used to open an interactive shell on the server or to access any other repository path, even if the account has broader privileges."
},
"savedTargets": {
"heading": "Saved targets",
"intro": "A saved target persists the repository configuration under a friendly name so the details do not have to be re-entered. Storage layout in the ProxMenux state directory:",
"rows": [
{ "file": "borg-targets.txt", "content": "One line per target: <code>NAME|REPO|SSH_KEY_PATH|ENCRYPT_MODE</code>. Read by <code>hb_collect_borg_configs</code> to populate the target-selection menu." },
{ "file": "borg-pass-NAME.txt", "content": "Passphrase for the target NAMEd above (<code>chmod 600</code>). Only present when the operator chose repokey encryption." }
],
"outro": "Saving is optional — the operator can decline the save prompt for a one-shot backup that leaves no credentials on the host."
},
"encryption": {
"heading": "Encryption",
"body": "Repositories are initialised with an encryption mode via <code>hb_borg_init_if_needed</code>: the modern <code>borg repo-create -e MODE</code> when available, or the legacy <code>borg init --encryption=MODE</code>. ProxMenux exposes two modes: <code>repokey</code> (default) and <code>none</code>. In <code>repokey</code> mode Borg stores the encryption key inside the repository itself; access requires a passphrase, which ProxMenux prompts for twice with match validation and stores at <code>borg-pass-NAME.txt</code>. A mandatory acknowledgement dialog is shown after the passphrase is saved: the passphrase is the only way to access the encrypted archives, and losing it makes every archive in the repository unrecoverable."
},
"runtimeEnv": {
"heading": "Runtime environment",
"intro": "ProxMenux exports the following environment variables before invoking <code>borg</code>. They configure the connection and unlock the repository without embedding secrets in the command line.",
"rows": [
{ "var": "BORG_RSH", "value": "ssh -i SSH_KEY_PATH -o StrictHostKeyChecking=accept-new", "purpose": "The remote-shell command Borg uses for SSH-served repositories. Set only when a custom key was selected; otherwise unset so Borg uses the default SSH configuration." },
{ "var": "BORG_PASSPHRASE", "value": "(passphrase from borg-pass-NAME.txt)", "purpose": "Unlocks the repokey. Set only when the target uses <code>repokey</code> encryption. Never appears in the process argument list." },
{ "var": "BORG_ENCRYPT_MODE", "value": "repokey | none", "purpose": "Used by <code>hb_borg_init_if_needed</code> when initialising a repository that does not yet exist. Ignored by <code>borg create</code> on existing repositories." },
{ "var": "BORG_RELOCATED_REPO_ACCESS_IS_OK", "value": "yes", "purpose": "Suppresses the interactive prompt Borg raises when the repository URL differs from the URL it was originally reached from (common after a mount-point rename or SSH-host reachable via new address)." },
{ "var": "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK", "value": "yes", "purpose": "Suppresses the interactive prompt Borg raises the first time an unencrypted repository is accessed from a new client." }
]
},
"archiveFormat": {
"heading": "Archive naming and retention",
"intro": "Every backup creates a new archive inside the repository.",
"namePattern": "hostcfg-HOSTNAME-YYYYMMDD_HHMMSS",
"retentionBody": "For scheduled jobs, <code>run_scheduled_backup.sh</code> runs <code>borg prune</code> against the repository after each successful backup with the retention values configured on the job (<code>--keep-last</code>, <code>--keep-daily</code>, <code>--keep-weekly</code>). Interactive backups do not prune."
},
"restoreAccess": {
"heading": "Retrieval on the restore side",
"body": "The restore flow lists archives with <code>borg list REPO</code> and extracts the selected one with <code>borg extract REPO::ARCHIVE-NAME</code> into a staging directory that <code>_rs_check_layout</code> feeds to the standard restore pipeline. For manual retrieval outside ProxMenux the same commands work; the extracted tree is the standard three-payload layout described in <em>How it works</em>."
},
"references": {
"heading": "References",
"intro": "Official Borg documentation for the components ProxMenux relies on.",
"items": [
{
"label": "Borg documentation",
"href": "https://borgbackup.readthedocs.io/",
"tail": " — main entry point covering concepts, deployment, quickstart and every command."
},
{
"label": "borg create",
"href": "https://borgbackup.readthedocs.io/en/stable/usage/create.html",
"tail": " — the command ProxMenux invokes on every backup, with all supported flags."
},
{
"label": "Repository encryption",
"href": "https://borgbackup.readthedocs.io/en/stable/usage/init.html#encryption-mode",
"tail": " — the encryption modes Borg supports, including repokey which ProxMenux uses by default."
},
{
"label": "borg serve and SSH deployment",
"href": "https://borgbackup.readthedocs.io/en/stable/deployment/central-backup-server.html",
"tail": " — how to set up a central Borg server accessed over SSH, including the borg-serve command and the restrict-to-path flag ProxMenux writes into authorized_keys."
},
{
"label": "borg prune",
"href": "https://borgbackup.readthedocs.io/en/stable/usage/prune.html",
"tail": " — the retention model behind --keep-last / --keep-daily / --keep-weekly that ProxMenux applies per scheduled job."
}
]
}
}
@@ -0,0 +1,110 @@
{
"meta": {
"title": "Backup destinations — Local, Proxmox Backup Server, Borg | ProxMenux",
"description": "Three storage backends receive the same ProxMenux backup payload: a local .tar.zst archive on any writeable filesystem, a PBS backup in a Proxmox Backup Server datastore, or a Borg archive in a local or remote Borg repository. Each backend has its own compression, deduplication, encryption and network characteristics.",
"ogTitle": "ProxMenux Backup Destinations",
"ogDescription": "Local, Proxmox Backup Server and Borg — three storage backends for the same host backup payload.",
"twitterTitle": "ProxMenux Backup Destinations | ProxMenux",
"twitterDescription": "Local archive, Proxmox Backup Server and Borg backends for host backups."
},
"header": {
"title": "Destinations",
"description": "Three storage backends supported by ProxMenux Backup: local archive, Proxmox Backup Server (recommended) and Borg. Each receives the same three-payload archive; they differ in storage format, deduplication, encryption model and network requirements.",
"section": "Backup & Restore"
},
"intro": {
"title": "Same payload, three backends",
"body": "Every backup produces the same three payloads (rootfs, manifest, applications). What changes between destinations is how those payloads are stored and how the operator retrieves them for a restore. Each backend is implemented as a separate function in <code>backup_host.sh</code> — <code>_bk_local</code>, <code>_bk_pbs</code>, <code>_bk_borg</code> — but all four share the same staging step (<code>hb_prepare_staging</code>) and the same restore code path. The choice of destination only affects the write and the retrieval; it does not change what a restore does or how it consumes the archive."
},
"comparison": {
"heading": "Feature comparison",
"intro": "The following table lists the concrete differences between the three backends as they behave in ProxMenux today. All values describe observed behaviour of the backend itself, not editorial recommendations.",
"rows": [
{
"feature": "Storage format",
"local": "Single <code>.tar.zst</code> file (or <code>.tar.gz</code> if <code>zstd</code> is absent).",
"pbs": "PBS backup (<code>.pxar</code> chunks in the datastore).",
"borg": "Borg archive inside a Borg repository (segment files)."
},
{
"feature": "Compression",
"local": "zstd (default level) via <code>tar --zstd</code>. gzip fallback.",
"pbs": "PBS-managed. The client streams uncompressed; the server chunks + compresses.",
"borg": "Borg's built-in (lz4 default). Configurable at repo init."
},
{
"feature": "Deduplication",
"local": "None. Each backup is a full independent archive.",
"pbs": "Full chunk-level deduplication across all backups in the datastore.",
"borg": "Full chunk-level deduplication across all archives in the repository."
},
{
"feature": "Encryption at rest",
"local": "None (relies on filesystem-level protection).",
"pbs": "Optional client-side keyfile encryption. Recovery blob uploaded as separate backup group when enabled.",
"borg": "Optional repokey encryption (key stored in the repo, unlocked by a passphrase)."
},
{
"feature": "Retention / pruning",
"local": "Applied per scheduled job via <code>KEEP_LAST</code>. Old archives (and their sidecars + runner logs) are deleted symmetrically. Interactive backups do not prune.",
"pbs": "Applied per scheduled job via <code>proxmox-backup-client prune --keep-last / --keep-daily / --keep-weekly</code>. Interactive backups do not prune.",
"borg": "Applied per scheduled job via <code>borg prune --keep-last / --keep-daily / --keep-weekly</code>. Interactive backups do not prune."
},
{
"feature": "Network",
"local": "None. Writes to a local mount point (typically an internal disk or a USB drive).",
"pbs": "TCP to the PBS server (default port 8007). Requires PBS credentials + fingerprint.",
"borg": "Local filesystem path or SSH tunnel to a remote Borg host."
},
{
"feature": "Dependencies",
"local": "<code>tar</code>, <code>zstd</code> (present on Proxmox by default).",
"pbs": "<code>proxmox-backup-client</code> package (bundled with Proxmox VE 8+).",
"borg": "<code>borg</code> binary. Auto-provisioned by ProxMenux from the Monitor AppImage bundle when missing."
},
{
"feature": "Restore access",
"local": "Any host with tar+zstd can extract the archive. No PBS/Borg needed.",
"pbs": "Requires <code>proxmox-backup-client</code> + PBS credentials + the keyfile (if encrypted).",
"borg": "Requires <code>borg</code> + the repository path + the passphrase (if encrypted)."
}
],
"captionCode": "feature",
"captionLocal": "Local",
"captionPbs": "Proxmox Backup Server (recommended)",
"captionBorg": "Borg"
},
"sameArchive": {
"heading": "The archive layout does not change with the destination",
"body": "Inside any of the three destinations, the same <code>rootfs/</code> + <code>metadata/</code> + <code>manifest.json</code> layout described in <em>How it works</em> is present. A <code>.tar.zst</code> extracted from a local archive, a <code>.pxar</code> restored from PBS, and a Borg archive extracted with <code>borg extract</code> all yield an identical directory tree. The restore code path (<code>_rs_check_layout</code>, <code>_rs_apply</code>, <code>_rs_prepare_pending_restore</code>) reads the same three payloads without knowing which destination they came from."
},
"extractStandalone": {
"heading": "Extracting a backup outside of ProxMenux",
"intro": "Any of the three archive formats can be read with standard tools without ProxMenux installed on the reading host. The commands below produce the same directory tree that a restore consumes internally.",
"localCmd": "# From a local .tar.zst archive:\ntar --zstd -xf hostcfg-HOST-TIMESTAMP.tar.zst\n\n# From a .tar.gz fallback:\ntar -xzf hostcfg-HOST-TIMESTAMP.tar.gz",
"pbsCmd": "# From a PBS backup (requires proxmox-backup-client):\nproxmox-backup-client restore \\\n --repository USER@REALM@HOST:DATASTORE \\\n host/hostcfg-HOST/BACKUP-TIME \\\n hostcfg.pxar /tmp/hostcfg\n\n# Add --keyfile KEY-PATH when the backup is encrypted.",
"borgCmd": "# From a Borg archive (requires borg binary + passphrase for encrypted repos):\nborg extract REPO-PATH::ARCHIVE-NAME\n\n# On a remote SSH-served repo:\nborg extract ssh://USER@HOST:PORT/REPO-PATH::ARCHIVE-NAME",
"note": "The extracted tree can then be inspected manually or fed to a manual restore. See the individual destination pages for the exact retrieval flow ProxMenux uses under the hood."
},
"whereNext": {
"heading": "Per-destination detail",
"intro": "Each destination has its own page covering the configuration flow, the on-disk format and the retrieval command used by the restore.",
"items": [
{
"label": "Local archive",
"href": "/docs/backup-restore/destinations/local",
"tail": " — pre-configuring a local target, USB drive mounting, the safety check against writing the archive into itself, the sidecar JSON that lets the Monitor identify the file."
},
{
"label": "Proxmox Backup Server (recommended)",
"href": "/docs/backup-restore/destinations/pbs",
"tail": " — datastore selection, credentials and fingerprint, encryption keyfile lifecycle, recovery passphrase, uploading the recovery blob to PBS for fresh-install recovery."
},
{
"label": "Borg",
"href": "/docs/backup-restore/destinations/borg",
"tail": " — local vs. SSH-served repositories, the Borg binary sourcing (system / cache / Monitor AppImage bundle / GitHub download), repository initialization, passphrase handling, SSH key setup for remote repos."
}
]
}
}
@@ -0,0 +1,63 @@
{
"meta": {
"title": "Local archive destination — tar.zst on a filesystem or USB drive | ProxMenux",
"description": "The local backup destination writes a single .tar.zst archive to any writeable directory: an internal disk, a Proxmox mount point, an NFS share, or a USB drive. Documents the configuration flow, the USB detection and mounting logic, the safety check against writing the archive into a path being backed up, and the sidecar JSON that identifies the file.",
"ogTitle": "ProxMenux Backup — Local archive destination",
"ogDescription": "How ProxMenux writes local backups as .tar.zst archives and how to configure the destination directory or USB drive.",
"twitterTitle": "Local backup destination | ProxMenux",
"twitterDescription": "How ProxMenux writes local backups as .tar.zst archives on a filesystem or USB drive."
},
"header": {
"title": "Local archive",
"description": "The local destination writes a single compressed tar archive to any writeable directory on the host: an internal disk, an NFS or SMB mount, or a USB drive.",
"section": "Backup & Restore"
},
"intro": {
"title": "One file, self-contained",
"body": "A local backup produces a single <code>hostcfg-HOST-TIMESTAMP.tar.zst</code> file (or <code>.tar.gz</code> when <code>zstd</code> is absent). The file contains the entire archive tree — <code>manifest.json</code>, <code>metadata/</code> and <code>rootfs/</code> — and can be restored on any Proxmox host with the ProxMenux restore flow, or extracted manually with <code>tar --zstd -xf</code> on any Linux system. No server, no repository init, no external dependency. This is the destination with the shortest recovery path when neither PBS nor Borg is available."
},
"targetConfig": {
"heading": "Configuring the target directory",
"intro": "The local destination is a <strong>single persisted target directory</strong> — not a list. ProxMenux stores the operator's choice at <code>/usr/local/share/proxmenux/local-target.conf</code> and reads it on every backup. When no target has been configured, the default <code>HB_LOCAL_TARGET_DEFAULT = /var/lib/vz/dump</code> is used (the same directory Proxmox uses for its own <code>vzdump</code> outputs). The target is configured from <em>Configure backup destinations → Local destinations</em>:",
"options": [
"<strong>Use default (<code>/var/lib/vz/dump</code>).</strong> The Proxmox local storage. Present on every Proxmox install; the archive sits next to vzdump outputs and is picked up by the Monitor's Backups tab automatically.",
"<strong>Enter a custom path.</strong> Any absolute filesystem path can be used: an NFS mount, an SMB share mounted via <code>fstab</code>, a dedicated ZFS dataset, a second internal disk. ProxMenux validates that the path exists and is a directory before persisting it.",
"<strong>Pick a USB drive.</strong> Opens the USB submenu (below), which detects removable devices and offers to mount or format one."
]
},
"usbFlow": {
"heading": "USB drive detection and mounting",
"intro": "The USB submenu lists partitions on removable devices reported by <code>lsblk</code>. Each partition is presented with its size, filesystem label and current state. The state determines the action ProxMenux offers.",
"statesTitle": "The three device states",
"stateRows": [
{ "state": "mounted", "shown": "Size · label · [fstype] · → /mount/point", "action": "The partition is already mounted somewhere. Selecting it persists the current mount point as the local target. No mounting is performed." },
{ "state": "unmounted", "shown": "Size · label · [fstype] · (not mounted — will be mounted)", "action": "A filesystem is present but not mounted. On confirmation, ProxMenux runs <code>hb_mount_usb_partition</code>: creates <code>/mnt/backup-LABEL</code> (or a UUID-based path if there is no label), mounts the partition and persists the mount point as the local target." },
{ "state": "empty", "shown": "Size · raw USB disk — no filesystem (will be FORMATTED)", "action": "The device has no filesystem. A destructive path — protected by two confirmations. First a Yes/No dialog explains that the operation will erase the disk. Second, an inputbox requires the operator to <strong>type the exact device path</strong> (e.g. <code>/dev/sdb</code>) before ProxMenux creates a fresh GPT + ext4 partition and mounts it." }
],
"notMountedFallback": "When no USB device is detected, the submenu falls back to a plain inputbox. The operator can enter an arbitrary mount point path; if the path is not a registered mount point, a confirmation dialog warns before proceeding."
},
"safetyCheck": {
"heading": "Safety check — destination inside a backup path",
"body": "Before writing the archive, <code>_bk_local</code> verifies that the destination directory is <strong>not</strong> a subpath of any directory being backed up. A common footgun would be adding <code>/root</code> to the profile and picking <code>/root/backups</code> as the destination — the archive would then include itself, either producing a corrupt archive or growing without bound until the disk fills. The check resolves both paths with <code>readlink -m</code>, compares them and, on conflict, aborts the backup with a dialog that names the conflicting path and lists three ways to resolve it: choose a destination outside the conflicting path, remove the custom entry that contains the destination, or use Custom mode to uncheck the conflicting path for this run."
},
"archiveFormat": {
"heading": "Archive format and compression",
"intro": "The output filename embeds the source hostname and the backup timestamp so that a directory holding several archives sorts chronologically and each file is self-identifying.",
"namePattern": "hostcfg-HOSTNAME-YYYYMMDD_HHMMSS.tar.zst",
"compressionTitle": "Compression",
"compressionBody": "The primary path uses <code>tar --zstd -cf</code> — a single-command pipeline that compresses at zstd's default level. When <code>zstd</code> is not present on the source (rare on Proxmox but possible on minimal installs), ProxMenux falls back to <code>gzip</code>. In the fallback path, if <code>pv</code> is available, a progress bar is added to the pipeline so the operator sees the archive size grow in real time; without <code>pv</code>, plain <code>tar -czf</code> is used silently.",
"sourceTitle": "What goes into the archive",
"sourceBody": "The tar command is invoked with <code>-C \"$staging_root\" .</code>, which archives the <strong>full staging root</strong>: <code>rootfs/</code>, <code>metadata/</code> and <code>manifest.json</code>. All three payloads land side by side at the top of the tarball. Extracting the archive produces the exact same tree that the restore code consumes."
},
"sidecar": {
"heading": "The sidecar JSON",
"intro": "Every successful local backup produces a companion file: <code>HOSTNAME-TIMESTAMP.tar.zst.proxmenux.json</code>, written next to the archive by <code>hb_write_archive_sidecar</code>. This small JSON file lets the ProxMenux Monitor identify the archive as a ProxMenux host backup even if it is later moved, renamed or archived elsewhere.",
"contentTitle": "Sidecar contents",
"contentBody": "The sidecar stores the schema version, whether the backup came from an interactive run or a scheduled job (<code>kind</code>), the job ID for scheduled runs, the profile mode used (<code>default</code> or <code>custom</code>), the source hostname, the original archive basename, an ISO-8601 creation timestamp and the archive size in bytes.",
"whyBody": "The Monitor's Backups tab scans configured local directories for <code>*.proxmenux.json</code> sidecars — not for <code>*.tar.zst</code> files — because a <code>.tar.zst</code> without a sidecar might not be a ProxMenux backup at all. The scan is fast (JSON files are tiny) and the pairing is stable across renames of the archive as long as the sidecar is renamed to match."
},
"restoreAccess": {
"heading": "Restoring from a local archive",
"body": "The ProxMenux restore flow discovers local archives by scanning the configured local target for sidecars and displaying them in the Archives list. Selecting one triggers <code>_rs_check_layout</code>, which extracts the tarball into a staging directory and confirms the three-payload layout before proceeding. For manual extraction outside of ProxMenux, <code>tar --zstd -xf hostcfg-HOSTNAME-TIMESTAMP.tar.zst -C /tmp/hostcfg</code> yields the same tree the restore code consumes."
}
}
@@ -0,0 +1,102 @@
{
"meta": {
"title": "Proxmox Backup Server destination — repository, encryption, recovery | ProxMenux",
"description": "The PBS destination writes ProxMenux host backups as PBS backups. Documents repository auto-discovery from /etc/pve/storage.cfg, manual PBS configuration, the .pxar upload command, the client-side keyfile encryption model, the recovery passphrase escrow blob, and the fresh-install keyfile recovery from PBS.",
"ogTitle": "ProxMenux Backup — Proxmox Backup Server destination",
"ogDescription": "How ProxMenux writes host backups to Proxmox Backup Server with client-side keyfile encryption and recovery escrow.",
"twitterTitle": "PBS backup destination | ProxMenux",
"twitterDescription": "Proxmox Backup Server destination with keyfile encryption and recovery passphrase escrow."
},
"header": {
"title": "Proxmox Backup Server",
"description": "The PBS destination uploads the staging root as a single .pxar backup to a Proxmox Backup Server datastore, with optional client-side keyfile encryption and an automatic recovery passphrase escrow for fresh-install disaster recovery.",
"section": "Backup & Restore"
},
"recommendedBadge": "Recommended destination",
"aboutPbs": {
"heading": "What Proxmox Backup Server is",
"body": "Proxmox Backup Server (PBS) is Proxmox's own backup server product, developed and maintained by the same team that authors Proxmox VE. It is a dedicated backup server designed to receive backups from Proxmox VE hosts (VMs, LXCs and — via <code>proxmox-backup-client</code> — arbitrary host directories) with chunk-based deduplication, client-side encryption, and retention policies applied server-side. ProxMenux uses PBS as one of the three destinations for host backups; every PBS-specific mechanism described on this page (backup groups, <code>.pxar</code> archives, <code>--backup-id</code>, keyfile encryption) is standard PBS behaviour."
},
"intro": {
"title": "One backup per run, chunk-level dedup",
"body": "A PBS backup produces a single backup entry in the datastore, grouped under the backup ID <code>host/hostcfg-HOSTNAME/BACKUP-TIME</code>. The payload is a <code>.pxar</code> archive containing the same three-block layout described in <em>How it works</em>. PBS deduplicates at the chunk level across all backups in the datastore, so subsequent backups of the same host transfer and store only the chunks that changed. Retention is applied by ProxMenux itself for scheduled jobs — <code>run_scheduled_backup.sh</code> runs <code>proxmox-backup-client prune</code> with <code>--keep-last</code> / <code>--keep-daily</code> / <code>--keep-weekly</code> after each successful run using the values configured on the job."
},
"repoSelection": {
"heading": "Repository selection",
"intro": "ProxMenux discovers PBS repositories from two sources on every backup. The operator picks one from a unified menu; the choice determines <code>HB_PBS_REPOSITORY</code>, <code>HB_PBS_SECRET</code> and <code>HB_PBS_FINGERPRINT</code> for the run.",
"sourceRows": [
{
"source": "Proxmox storage.cfg (auto-discovered)",
"path": "/etc/pve/storage.cfg + /etc/pve/priv/storage/NAME.pw",
"content": "Any <code>pbs:</code> stanza in Proxmox's own storage config is picked up automatically. Server, datastore, username and fingerprint come from the stanza. The password is read from Proxmox's own credentials directory. No re-entry needed on the ProxMenux side — the repository is available as soon as it is configured in Proxmox."
},
{
"source": "ProxMenux manual config",
"path": "/usr/local/share/proxmenux/pbs-manual-configs.txt + pbs-pass-NAME.txt + pbs-fingerprint-NAME.txt",
"content": "Added from <em>Configure backup destinations → PBS destinations → Add PBS</em>. Prompts for a name, username (<code>root@pam</code> or <code>user@pbs!token</code>), host or IP, datastore and password. The password re-prompts on empty input — an empty save would otherwise persist silently and every subsequent backup would fail with an opaque authentication error. This path is used when the target PBS is not registered as Proxmox storage."
}
],
"menuTitle": "Selection menu",
"menuBody": "Both sources are shown in a single menu, each row tagged with its origin (<code>[proxmox]</code> or <code>[manual]</code>). Entries whose password could not be resolved are tagged with a <code>⚠ no password</code> warning — selecting one triggers a password re-entry before the backup starts. The fingerprint is passed to <code>proxmox-backup-client</code> via the <code>PBS_FINGERPRINT</code> environment variable; when absent, the client asks the operator to accept the server certificate interactively on the first backup."
},
"backupCommand": {
"heading": "The backup command",
"intro": "The upload is a single invocation of <code>proxmox-backup-client backup</code>. ProxMenux runs it inside an <code>env</code> wrapper so credentials never appear in the process argument list.",
"cmd": "env \\\n PBS_PASSWORD=\"$HB_PBS_SECRET\" \\\n PBS_ENCRYPTION_PASSWORD=\"$HB_PBS_ENC_PASS\" \\\n PBS_FINGERPRINT=\"$HB_PBS_FINGERPRINT\" \\\n proxmox-backup-client backup \\\n hostcfg.pxar:$staging_root \\\n --repository USER@REALM@HOST:DATASTORE \\\n --backup-type host \\\n --backup-id hostcfg-HOSTNAME \\\n --backup-time BACKUP-EPOCH \\\n [--keyfile /usr/local/share/proxmenux/pbs-key.conf]",
"backupIdTitle": "Backup ID naming",
"backupIdBody": "The default backup ID is <code>hostcfg-HOSTNAME</code>. The operator is asked to confirm or edit it before the upload; any characters outside <code>[A-Za-z0-9_-]</code> are stripped and trailing dashes are trimmed. Reusing the same ID across runs is intentional — PBS treats the ID as a <em>group</em>, and every subsequent backup appears as a new backup inside that group, sharing dedup with prior runs.",
"pxarTitle": "Why the source is the full staging root",
"pxarBody": "The <code>.pxar</code> source is the entire <code>staging_root</code> — <code>rootfs/</code>, <code>metadata/</code> and <code>manifest.json</code> together. Earlier versions passed <code>$staging_root/rootfs</code> as the source; that left <code>metadata/</code> out of the archive and the restore's compatibility check had nothing to read, degrading to cross-host warnings even on same-host restores. Old backups created with the rootfs-only source still restore correctly via <code>_rs_check_layout</code>'s case-3 branch, which wraps a flat <code>etc/var/root/usr</code> tree back into a <code>rootfs/</code> hierarchy."
},
"encryption": {
"heading": "Client-side encryption",
"intro": "PBS client-side keyfile encryption encrypts chunks on the source host before upload. ProxMenux enables the feature with one added constraint: a recovery passphrase is mandatory when encryption is enabled. The passphrase does not protect the local keyfile; it protects the escrow copy of the keyfile that ProxMenux uploads to PBS for disaster recovery.",
"keyfileTitle": "Keyfile",
"keyfileBody": "On first use, <code>proxmox-backup-client key create --kdf none</code> generates the keyfile at <code>/usr/local/share/proxmenux/pbs-key.conf</code> (<code>chmod 600</code>). Subsequent backups reuse it after a single confirmation dialog. If key creation fails, the backup is cancelled and the tool's error output is shown in a dialog.",
"recoveryTitle": "Recovery passphrase and escrow blob",
"recoveryBody": "After the keyfile is created, ProxMenux prompts twice for a recovery passphrase (with match validation) and runs <code>openssl</code> to produce <code>pbs-key.recovery.enc</code> — the keyfile encrypted with the passphrase. A copy is written to <code>/root/pbs-key.recovery-HOSTNAME-YYYYMMDD.enc</code> for offsite storage. Cancelling the passphrase dialog wipes the freshly-created keyfile.",
"blobUploadTitle": "Paired backup group on PBS",
"blobUploadBody1": "After a PBS backup that used the keyfile, the escrow blob is uploaded as a second backup group: <code>host/hostcfg-HOSTNAME-keyrecovery/BACKUP-TIME</code>. The shared <code>hostcfg-HOSTNAME</code> prefix places both groups adjacent in the PBS UI; the <code>-keyrecovery</code> suffix labels the relationship. The upload runs without <code>--keyfile</code> (the blob is already passphrase-protected by openssl) and only when the current backup used the keyfile.",
"blobUploadConstraintTitle": "Why two groups",
"blobUploadConstraintBody": "<code>--keyfile</code> is a per-invocation flag in <code>proxmox-backup-client backup</code>: all archives in a single invocation are encrypted with the keyfile or none are. <code>hostcfg.pxar</code> requires encryption; <code>keyrecovery.conf</code> cannot be encrypted with the same keyfile (fresh-install recovery would then require the keyfile it is meant to recover). Two invocations, two backup IDs.",
"blobUploadImageAlt": "PBS UI showing the hostcfg-HOSTNAME and hostcfg-HOSTNAME-keyrecovery backup groups adjacent in the datastore listing.",
"blobUploadImageCaption": "PBS UI — the paired backup groups. The main group holds the host backups; the -keyrecovery group holds the escrow blob.",
"recoverTitle": "Fresh-install recovery",
"recoverBody": "On a host without a local keyfile, the restore flow calls <code>hb_pbs_try_keyfile_recovery</code>. The function lists keyrecovery groups on the configured PBS, downloads the newest and prompts for the passphrase. On success, <code>pbs-key.conf</code> is written to the ProxMenux state directory and the encrypted backup can be restored. Without both the keyfile and the passphrase, the encrypted backup is not recoverable."
},
"restoreAccess": {
"heading": "Retrieval on the restore side",
"body": "The restore flow discovers ProxMenux host backups on PBS by listing backup groups under the configured repository and filtering by backup ID pattern. The Monitor's Backups tab renders the same list. Selecting a backup triggers <code>proxmox-backup-client restore</code> with the same repository + password + fingerprint (and <code>--keyfile</code> when the backup was encrypted), extracting the <code>.pxar</code> into a staging directory that <code>_rs_check_layout</code> then feeds to the standard restore pipeline. For manual retrieval outside ProxMenux, the same command extracts the archive to any path — the resulting tree can be inspected or fed to a hand-driven restore."
},
"references": {
"heading": "References",
"intro": "Official Proxmox Backup Server documentation for the components ProxMenux relies on.",
"items": [
{
"label": "Proxmox Backup Server documentation",
"href": "https://pbs.proxmox.com/docs/",
"tail": " — main entry point covering installation, administration, storage, users and roles."
},
{
"label": "proxmox-backup-client",
"href": "https://pbs.proxmox.com/docs/backup-client.html",
"tail": " — the command-line tool ProxMenux invokes for every backup and restore. Covers backup IDs, backup types, archives, repository syntax and environment variables."
},
{
"label": "Client-side encryption",
"href": "https://pbs.proxmox.com/docs/backup-client.html#encryption",
"tail": " — keyfile creation, --kdf modes, the encryption model that ProxMenux extends with a passphrase escrow."
},
{
"label": "Datastore management",
"href": "https://pbs.proxmox.com/docs/storage.html",
"tail": " — creating and managing the datastores that receive host backups, including chunk-store layout and permissions."
},
{
"label": "Pruning and garbage collection",
"href": "https://pbs.proxmox.com/docs/maintenance.html#pruning",
"tail": " — the retention model behind --keep-last / --keep-daily / --keep-weekly that ProxMenux applies per scheduled job, plus how PBS reclaims chunks after prune."
}
]
}
}