BackupHelper can optionally encrypt each archive client-side — with age or GnuPG — before it is written to any destination, so off-site copies are unreadable without your private key.
Encryption is per job and off by default. When enabled, it runs in the pipeline right after the deterministic tar.gz bundle is built and before the archive is uploaded to any destination:
sources → bundle (tar.gz) → encrypt (age | gpg) → sidecar manifest → upload → retention
The stored artifact gains a .age or .gpg suffix, and the manifest's archive_sha256 is computed over the encrypted artifact. Both age and gnupg are installed in the container image, so no extra tooling is required.
See the configuration reference for where encryption sits inside a job.
{
"encryption": { "mode": "age", "recipient": "age1qz...publickey" }
}| Field | Type | Default | Meaning |
|---|---|---|---|
mode |
none | age | gpg |
none |
Encryption backend. none is a passthrough (archive stored as-is). |
recipient |
string | null |
The public recipient. Required for age and gpg — encryption raises without it. |
- For age,
recipientis an age public key (e.g.age1qz...). - For gpg,
recipientis a key id, fingerprint or email present in the encrypting keyring.
The engine shells out to the CLI tools. The exact argument vectors are:
| Mode | Encrypt | Resulting suffix |
|---|---|---|
age |
age --encrypt --recipient <recipient> --output <out> <archive> |
.age |
gpg |
gpg --batch --yes --encrypt --recipient <recipient> --output <out> <archive> |
.gpg |
| Mode | Decrypt (during restore) |
|---|---|
age |
age --decrypt --output <out> <artifact> |
gpg |
gpg --batch --yes --decrypt --output <out> <artifact> |
Decryption relies on the matching private key being available to the tool in the environment where restore runs — the secret keyring for gpg, the age identity for age.
Restore does not need to be told the encryption mode. It selects the decrypt backend from the artifact's file suffix:
*.tar.gz.age→ decrypted withage*.tar.gz.gpg→ decrypted withgpg*.tar.gz→ used as-is (no decryption)
So backuphelper restore <snapshot_id> transparently decrypts an encrypted snapshot before extracting it, provided the private key is present.
If encryption fails (tool missing, bad recipient, non-zero exit), the runner records an error, falls back to storing the unencrypted archive, and reports the job as a warning rather than aborting. Treat a warning status on an encryption-enabled job as a signal that the stored copy may be unencrypted, and check the logs.
Generate an identity (keep the private half safe — it is what restores the backups):
age-keygen -o age-identity.txt
# Public key: age1qz9v... <- use this as encryption.recipientSet the public key as the recipient:
{ "encryption": { "mode": "age", "recipient": "age1qz9v..." } }At restore time, age-identity.txt (the private identity) must be available to the age CLI in the restore environment.
Use an existing keypair, or generate one, then point recipient at a key present in the keyring:
{ "encryption": { "mode": "gpg", "recipient": "ops@example.com" } }The corresponding secret key must be in the keyring of whatever runs backuphelper restore.