docs: review backup and restore documentation in all seven translations

This commit is contained in:
Jonatan
2026-10-17 15:08:53 +02:00
parent ce1a3de719
commit ea6f6dbf6e
86 changed files with 11849 additions and 244 deletions
@@ -24,19 +24,47 @@
"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." }
{
"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." }
{
"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": {
@@ -50,30 +78,62 @@
"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.",
"lxcWarningBody": "If the Borg server runs inside an LXC, generate-auto requires an account that accepts SSH password authentication during key installation. If password login is unavailable, use manual key installation or the generate-pct alternative through the PVE host.",
"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." }
{
"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."
"minimalSetupNote": "With the server prepared and SSH password authentication available, ProxMenux’s <code>generate-auto</code> mode can install its SSH key using an account permitted to write the borg user’s authorized_keys file. Subsequent backups use that key, restricted to <code>borg serve</code> on the configured path. Without password login, install the key manually or use the PVE-host alternative."
},
"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:",
"strategiesTitle": "SSH key strategies",
"strategiesIntro": "When a remote target is added, ProxMenux asks for the SSH user, host and remote path, then offers four authentication choices. The additional generate-pct path is offered when password authentication is refused. The modes are described below:",
"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)." }
{
"mode": "generate-auto",
"label": "Recommended",
"detail": "ProxMenux generates or reuses an ed25519 keypair at <code>~/.ssh/borg_proxmenux_HOST_ed25519</code>, then uses <code>sshpass</code> for a login probe and installation of the public key in <code>~borg/.ssh/authorized_keys</code>. The password belongs to an account allowed to write that file, usually root or the borg user. It is used during setup and is not saved."
},
{
"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:",
@@ -84,24 +144,50 @@
"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." }
{
"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."
"outro": "Saving the target is optional. Declining the save prompt omits the named target configuration, but does not remove a generated SSH key. If repokey encryption is enabled without a saved target, ProxMenux still saves the passphrase in the legacy borg-pass.txt file."
},
"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."
"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> for saved targets (or in the legacy file described above). 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." }
{
"var": "BORG_RSH",
"value": "ssh -i SSH_KEY_PATH -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new [-p PORT]",
"purpose": "The remote-shell command Borg uses for SSH repositories. A selected key adds the identity options; a non-default port adds -p PORT. With no custom key and the default port, the variable is unset so Borg uses the host’s 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": {
@@ -14,7 +14,7 @@
},
"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."
"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 three 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",
@@ -29,8 +29,8 @@
{
"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."
"pbs": "Managed by proxmox-backup-client. ProxMenux does not override compression settings.",
"borg": "Borg’s built-in compression. ProxMenux invokes borg create without overriding compression settings."
},
{
"feature": "Deduplication",
@@ -41,7 +41,7 @@
},
"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.",
"intro": "The upload is a single invocation of <code>proxmox-backup-client backup</code>. ProxMenux uses <code>env</code> to pass the password, encryption password and fingerprint to the client as environment variables.",
"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.",
@@ -61,13 +61,13 @@
"modesSharedTitle": "Shared keyfile (import on every host)",
"modesSharedBody": "One master keyfile generated once and installed on every host via the <em>Use an existing keyfile</em> option. Management is simpler: a single secret to safeguard, and any host can decrypt the archives of any other (useful for consolidation, cross-host restore drills or centralised backup verification). The trade-off is that a leak of the shared keyfile exposes every host at once. Recommended for homelabs and for fleets where all hosts have the same owner and trust boundary.",
"recoveryTitle": "Upload key to PBS — the operator decides",
"recoveryBody": "Right after the keyfile is chosen, ProxMenux asks a single explicit question — <em>Upload key to PBS?</em> — with two answers. <strong>Nothing gets uploaded to PBS until the operator answers Yes.</strong> The default is <em>No, keep local only</em>: the keyfile stays only at the canonical local path, ProxMenux never touches PBS with any recovery artefact, and the operator handles the offsite copy themselves (the Monitor's <em>Download keyfile</em> button in the PBS destination row provides one on demand). Choosing <em>Yes, upload</em> prompts for a recovery passphrase — twice, with match validation — and ProxMenux wraps the keyfile with that passphrase using AES-256-CBC and PBKDF2 (600 000 iterations, random salt) to produce <code>pbs-key.recovery.enc</code>. Every subsequent encrypted backup uploads that envelope to PBS as a paired backup group. Neither the passphrase nor a plaintext copy of the keyfile ever leaves the host. The choice can be changed later from the Monitor at any time — the escrow toggle inline in the PBS destination row flips Yes/No and applies immediately (Start uploading, Stop uploading, or Update passphrase, matching the current state).",
"recoveryBody": "Right after the keyfile is chosen, ProxMenux asks a single explicit question — <em>Upload key to PBS?</em> — with two answers. <strong>No recovery artifact is uploaded to PBS until the operator answers Yes.</strong> The default is <em>No, keep local only</em>: the keyfile stays at the canonical local path, ProxMenux uploads no recovery artifact to PBS, and the operator handles the offsite copy themselves (the Monitor’s <em>Download keyfile</em> button in the PBS destination row provides one on demand). Choosing <em>Yes, upload</em> prompts for a recovery passphrase — twice, with match validation — and ProxMenux wraps the keyfile with that passphrase using AES-256-CBC and PBKDF2 (600 000 iterations, random salt) to produce <code>pbs-key.recovery.enc</code>. Every subsequent encrypted backup uploads that envelope to PBS as a paired backup group. Neither the passphrase nor a plaintext copy of the keyfile is sent to PBS during these uploads. The choice can be changed later from the Monitor at any time — the escrow toggle inline in the PBS destination row flips Yes/No and applies immediately (Start uploading, Stop uploading, or Update passphrase, matching the current state).",
"blobUploadTitle": "Paired backup group on PBS",
"blobUploadBody1": "When the escrow mode is <em>Yes, upload</em>, ProxMenux uploads the recovery envelope to PBS after every encrypted backup as a second, paired backup group with the same name as the host group but ending in <code>-keyrecovery</code>. The two groups sit next to each other in the datastore listing — one for host backups, one for recovery envelopes. <strong>The envelope never leaves the host in plaintext</strong>: encryption happens on the host itself with AES-256-CBC and PBKDF2 before any bytes go on the wire (<code>openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -salt</code>). PBS receives only the already-encrypted envelope.",
"envelopeSecurityTitle": "Is uploading the keyrecovery file to PBS a security risk?",
"envelopeSecurityBody": "The keyrecovery file is encrypted in transit and at rest. The recovery passphrase never leaves the host: encryption happens locally before the upload, and PBS only ever sees the already-encrypted result. A PBS administrator — or anyone with access to the datastore — can download the keyrecovery file, but without the recovery passphrase they cannot read the keyfile inside: it is opaque ciphertext. Reconstructing the keyfile requires both pieces at once, the keyrecovery file and the passphrase, and only the operator holds both.",
"blobUploadConstraintTitle": "Why two groups instead of a single encrypted one",
"blobUploadConstraintBody": "A single <code>proxmox-backup-client backup</code> invocation encrypts every one of its archives with the same keyfile, or none at all — there is no in-between. The host backup has to be encrypted with the host keyfile, but the recovery envelope cannot ride along in that same upload, because it would end up encrypted with the very keyfile it contains: on a freshly reinstalled host there would be no way to open it (you would need the keyfile to decrypt the keyfile). That is why the two artefacts are uploaded independently and appear as two separate groups: the host backup is encrypted by PBS with the keyfile, and the recovery envelope is encrypted by ProxMenux with the passphrase before upload. Two different encryption layers protecting two different assets.",
"blobUploadConstraintBody": "A single <code>proxmox-backup-client backup</code> invocation encrypts every one of its archives with the same keyfile, or none at all — there is no in-between. The host backup has to be encrypted with the host keyfile, but the recovery envelope cannot ride along in that same upload, because it would end up encrypted with the very keyfile it contains: on a freshly reinstalled host there would be no way to open it (you would need the keyfile to decrypt the keyfile). That is why the two artefacts are uploaded independently and appear as two separate groups: the host backup is encrypted by the PBS client with the keyfile, and the recovery envelope is encrypted by ProxMenux with the passphrase before upload. Two different encryption layers protecting two different assets.",
"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 passphrase-wrapped keyfile.",
"recoverTitle": "Recovery on a fresh host",