Zero-knowledge backups seal your server's backups to encryption keys that only you hold. Once you register a recovery key set for a server, our backup system seals each backup's data-encryption key (DEK) to your whole registered key set as one age file. Any single key you registered opens it. We never see a private key, a passphrase, or an open DEK — so we can never recover your data for you, and neither can anyone who compromises us.
This guide is about the part that matters: getting your data back. Recovery always ends the same way, no matter which key you hold:
age -d -i <your-identity-file> backup.dek.age > dek.bin
age is the small, widely audited file-encryption tool (age-encryption.org), packaged on every major OS. Every recovery option below (a “rung”) is a deterministic mapping from a secret only you hold to an age identity (AGE-SECRET-KEY-1...). Registering a rung means sending us only the derived public half (an age1... recipient). Recovering means re-deriving the identity from your secret and running age -d. The exact byte-level constructions and test vectors are published in the key derivation reference, so you can verify or reimplement every rung with standard tools — no SHC software required.
For convenience, SHC provides a small recovery-key helper, shc-age.py (python3, standard library only, no network access — read it before you run it). The per-rung commands below use it; because the constructions are open (see the reference above), you can equally do everything with standard tools. To turn encryption on and manage keys from your server's Backups tab, see Zero-knowledge backups: turning it on.
You can recover if you still hold any one registered key. You lose access only if you lose all of them. Register at least two independent rungs, stored in two different places, and you are safe.
There are also two more key types, covered below: PGP — not a derivation but a self-wrap — and a post-quantum hybrid that pairs an age key with an ML-KEM-1024 key for the longest horizon. You arm an ssh-ed25519 key in one click from your server's Backups tab, and register any other rung there too by pasting its derived age1... recipient into the panel's Add a recovery recipient control (or through the zero-knowledge routes in the API reference) — see turning it on. In every case what you submit is only the derived public key.
If you have an ed25519 SSH key, you already have a recovery key.
~/.ssh/id_ed25519 (it never leaves your machine).ssh-ed25519 AAAA... you@host) as a recipient of kind ssh-ed25519.age -d -i ~/.ssh/id_ed25519 backup.dek.age > dek.bin
That is the whole procedure — plain age, no SHC tooling at all.
This is the rung the Backups-tab Encryption panel arms in one click — see turning it on.
fine-unfair-saddle-grid-find-correct.age1... recipient, kind password.age -d as above.python3 shc-age.py passphrase register --new-salt # prints the salt + your age1... recipient
python3 shc-age.py passphrase recover --salt <salt-hex> -o pw.key
age -d -i pw.key backup.dek.age > dek.bin
recovery-key.age -d.python3 shc-age.py card generate # shows the 24 words + your age1... recipient
python3 shc-age.py card recover -o card.key # prompts for the 24 words
age -d -i card.key backup.dek.age > dek.bin
Your hardware or software wallet can deterministically mint an independent 32-byte secret for SHC backups using BIP-85 (“Deterministic Entropy From BIP32 Keychains”). The derivation happens on your wallet — Coldcard, Sparrow, and others support it — and your bitcoin keys never touch anything.
What you hold: your wallet seed. Our published convention path:
m/83696968'/128169'/32'/0' (BIP-85 hex application, 32 bytes, index 0)
btc. The 24-word BIP-85 mnemonic application is accepted too — note down which path you used.age -d.python3 shc-age.py btc register # paste the BIP-85 entropy (64 hex, or 24 words)
python3 shc-age.py btc recover -o btc.key
age -d -i btc.key backup.dek.age > dek.bin
secp256k1 (the API also accepts nostr as an alias). The derivation runs locally; your nsec is never transmitted.age -d.python3 shc-age.py nostr register # paste nsec1... or 64 hex (processed locally)
python3 shc-age.py nostr recover -o nostr.key
age -d -i nostr.key backup.dek.age > dek.bin
PGP keys are often hardware-bound (YubiKey, OpenPGP card) and cannot be exported, so there is deliberately no derivation from a PGP key. Instead you mint a dedicated age key and lock it under your PGP key, yourself, with your own gpg:
age-keygen | gpg -ea -r <your-key-id> > envelope.asc
Register the printed age1... recipient as kind pgp, and keep the envelope file with your PGP backups. To recover:
gpg -d envelope.asc > pgp.key
age -d -i pgp.key backup.dek.age > dek.bin
The same wrap and recovery are scripted by the helper: python3 shc-age.py pgp wrap --gpg-recipient <your-key-id> --envelope envelope.asc to mint and wrap the age key, and python3 shc-age.py pgp recover --envelope envelope.asc -o pgp.key to unwrap it for age -d.
Every rung above rests on X25519 (elliptic-curve) cryptography. A cryptographically relevant quantum computer — if one is ever built — would break X25519, and an adversary who archives your sealed key files today could open them then (“harvest now, decrypt later”). If your backups must stay sealed on that horizon, register a post-quantum hybrid key: an age key paired with an ML-KEM-1024 key, the NIST post-quantum encryption standard (FIPS 203).
age-keygen, or derive one with any rung above) and the ML-KEM-1024 private key you generate beside it. A hybrid seal opens only with both halves, so store them together and treat the pair as one key when you count your rungs.pq-hybrid, via the zero-knowledge routes in the API (the panel dropdown does not list this type yet): submit the age key's X25519 public key as pubkey and the ML-KEM-1024 public key as mlkem_pubkey. As always, only the public halves are sent. Both are bound write-once into your key set, and the recipients endpoint returns a reader_id fingerprint covering the pair.backup.dek.age exactly like any other rung, with plain age -d. A hybrid-sealed key file additionally demands the ML-KEM half: breaking X25519 alone is not enough, which is the point.The hybrid seal itself is not an age file. It is a small published construction — the X25519 and ML-KEM-1024 shared secrets combined into one AES-256-GCM seal — pinned byte-for-byte with test vectors in the key derivation reference, so opening one needs standard implementations, not SHC software. Hybrid seals ride alongside the classic age seal rather than replacing it. Because your key set is write-once, the time to include the ML-KEM half is when you choose the set — adding it later means a destructive re-key.
backup.dek.age) — the DEK sealed to your whole registered key set. When you restore, that file and the fingerprints of your registered keys are made available to you.age -d. Compare the key's printed age1... recipient against the one you recorded at registration — if it differs, stop: wrong key or wrong data.Your passphrase, private keys, and words never touch our systems at any step.
Use any other rung — every registered key opens every backup made while it was registered. Once you are back in, consider re-keying to a fresh set.
If you lose all registered keys, the backups are unrecoverable — by anyone, including us. That is not a limitation we can waive; it is the direct, deliberate consequence of us never holding your key. There is no “reset password” for zero-knowledge data.
age1... recipient shown at registration alongside (not with) each key — it lets you verify you hold the right key without exposing it.If you believe a key was exposed, or you want a new set, use the re-key action. It installs a brand-new key generation, and every backup made under the previous generation becomes permanently unrecoverable. It is deliberately hard to trigger: you must type DESTROY-MY-BACKUPS and complete a two-step confirmation. Only re-key when you truly intend to abandon the old backups.
For the exact constructions, parameters, and test vectors — enough to verify or reimplement everything yourself — see the key derivation reference. For endpoints and payloads, see the API reference. For what backups are included with your plan, see Backups and snapshots.