Recovery Kit
Emergency decryption tool for encrypted backups.
Overview
A Recovery Kit is a standalone package that lets you decrypt backups without access to DBackup. It's essential for disaster recovery scenarios.
What's Included
Each Recovery Kit contains:
recovery-kit/
├── README.txt # Instructions
├── master.key # Your encryption key (64 hex characters)
├── dbackup-recover.js # The recovery tool
├── START-Windows.bat # Double-click launcher
├── START-macOS.command # Double-click launcher
└── START-Linux.sh # LauncherA kit covering several profiles carries a keys/ folder instead of master.key, with one file per profile named after it and an index tying each key to the backups it opens:
recovery-kit/
├── keys/
│ ├── Production.key
│ ├── Legacy-2024.key
│ └── keys.json # which key opens which backups
└── ...One tool handles every backup format DBackup writes - database dumps, file backups and incremental chains, encrypted or not. It works out which one it is looking at, so you do not have to, and everything it restores lands in a restored folder ready to use.
It streams every entry it extracts, so a backup containing a 50 GB VM image needs no more memory than one containing text files - which matters precisely when you are recovering onto whatever machine happens to be available. Files are written to a temporary name and only put in place once their authentication tag and recorded checksum both verify, so a damaged archive never leaves something that looks like a recovered file.
Why You Need It
Disaster Scenarios
- DBackup server destroyed
- Database corrupted
- Lost access to application
ENCRYPTION_KEYlost- Need offline access
Without Recovery Kit
❌ Cannot decrypt backups ❌ Data potentially lost forever ❌ No way to recover encryption key
With Recovery Kit
✅ Decrypt backups anywhere ✅ Only need Node.js ✅ Works offline ✅ Independent of DBackup
Downloading a Recovery Kit
- Go to Settings → Vault
- Click Recovery Kit
- Tick the encryption profiles the kit should carry - everything is ticked by default
- Click Download and save the zip securely
One kit can hold several keys. That is usually what you want: a backup records which profile encrypted it, so the tool picks the right key by itself and you never have to work out which of your kits belongs to which job. Untick profiles when you need a kit that only opens part of your backups - handing one to someone who should not see everything, for instance.
A multi-key kit opens everything
A kit with one key exposes one profile's backups if it leaks. A kit with all of them exposes all of them. Weigh that against the convenience before you store it somewhere less protected than your backups are.
Store Securely
The Recovery Kit contains your encryption key! Store it:
- In a password manager
- On encrypted storage
- In a secure physical location
- NOT in the same place as backups
Using the Recovery Kit
The only prerequisite is Node.js 18 or newer. No npm install, no DBackup server, no database.
Unzip the Recovery Kit.
Copy the backup next to the unzipped files. If the backup is a folder - which is how an incremental chain is stored - copy the whole folder.
Start the tool. Double-clicking a launcher is the quick way:
System Launcher Windows START-Windows.batmacOS START-macOS.commandLinux START-Linux.shIf a launcher is blocked or does nothing, open a terminal instead - this always works, on every system:
bashcd /path/to/the/unzipped/kit node dbackup-recover.jsTo open a terminal: Windows Start menu, type
cmd. macOS Applications → Utilities → Terminal. Linux your terminal application, or Ctrl + Alt + T. Instead of typing the path, typecdand then drag the kit's folder onto the terminal window.It shows what it found and asks what to do with it:
DBackup Recovery
Key loaded from master.key
Found 2 backup(s):
> chain-2026-07-25T20-10-37-652 25.07.2026 20:11 1.0 GB encrypted incremental chain, 2 archive(s)
MyDb_2026-07-20.sql.gz.enc 20.07.2026 03:00 348 MB encrypted
QuitChoosing a backup offers restoring everything, looking inside first, picking an older state of a chain, or restoring only part of it - certain files, or certain databases by name.
You never have to type the key: the tool reads master.key from its own folder. If the key is somewhere else, it asks for it.
macOS blocks the launcher on its first run
Anything downloaded from the internet is quarantined, so the first double-click is refused with "Apple could not verify START-macOS.command is free of malware". Click Done, then open System Settings → Privacy & Security, scroll to Security, and click Open Anyway next to the blocked file. Confirm with Touch ID or your password, then Open Anyway once more. It starts normally from then on.
On macOS 14 and older, right-clicking the file and choosing Open does the same in one step. Either way, the terminal command above is unaffected by this.
Command line
The same tool, for scripting or over SSH. Every mode accepts a folder wherever it accepts an archive.
node dbackup-recover.js --list <archive or folder>
node dbackup-recover.js --extract <archive or folder> <output_dir> [pattern...]
node dbackup-recover.js --decrypt <backup.enc> [output_dir] [database...]Everything lands in ./restored unless another folder is named.
--list prints the databases, the directory sources, and every file with its size and modification time. For an incremental snapshot it also names every archive the snapshot needs and marks any that are missing, so a gap is visible before you start extracting.
--extract patterns accept * and **, and naming a folder selects everything inside it:
node dbackup-recover.js --extract backup.tar ./restored 'www/**'
node dbackup-recover.js --extract backup.tar ./restored docsEvery extracted file is verified against the checksum recorded when the backup was made. A mismatch is reported and the command exits non-zero.
--decrypt handles a database backup encrypted as a single file. It decompresses in the same pass, and a backup holding several databases is unpacked into one dump per database - the output is always ready to feed to mysql, psql or mongorestore, never a .gz or a .tar to take apart first.
Restoring a single database
Name it, and nothing else is written. Which form you use depends on where the database lives, and --list tells you which databases a backup contains:
# A database-only backup (a .tar of dumps)
node dbackup-recover.js --decrypt AllDbs.tar.enc ./restored shop
# A database inside a file backup, addressed under the databases/ prefix
node dbackup-recover.js --extract backup.tar ./restored databases/shopNaming a database in the second form also keeps the archive's directory sources out of the restore, so you get the dump on its own.
The key is read from master.key next to the tool. Pass it as an extra argument to override, or leave it out entirely for unencrypted backups.
Incremental chains
An incremental backup is stored as a chain in one folder: one full backup plus the changes made after it.
MyJob/chain-2026-07-24T03-00-00-000/
..._full-000.tar the full backup the chain is built on
..._inc-001.tar what changed after it
..._inc-002.tar what changed after thatCopy the whole folder and point the tool at it. It picks the newest snapshot on its own and rebuilds the current state from all of them, every file at its latest version, merged into a single output folder. There is no separate step to replay the chain.
node dbackup-recover.js --extract ./chain-2026-07-24T03-00-00-000 ./restoredTo recover an older state, choose "Pick an older state" in the wizard, or name that archive directly - each one rebuilds the snapshot as it was at its own point in time.
Keep the archives of a chain together in one folder; that is how they find each other. A missing archive aborts the extract by name instead of writing an incomplete restore.
Unencrypted archives need no kit at all
If the job had no encryption profile, the archive is a plain TAR:
tar -xf backup.tar
# If the job used compression, the extracted files are gzip streams:
find . -name '*.gz' -exec gunzip {} +Encrypted archives always require this kit, because each file inside is individually encrypted.
How It Works
There are two shapes of backup, and the tool tells them apart on its own. What follows is only needed if you want to write your own recovery code.
Database-only backups
One stream: the dump, optionally compressed, optionally encrypted with AES-256-GCM as a whole. Everything needed to open it apart from the key is in the .meta.json next to it.
{
"compression": "GZIP",
"encryption": {
"enabled": true,
"iv": "hex-encoded-initialization-vector",
"authTag": "hex-encoded-authentication-tag"
}
}Decrypt with the IV and authentication tag from that file, then decompress. A job backing up several databases produces a TAR of dumps, so unpack that afterwards as well.
File backups
A seekable archive that encrypts each entry separately, which is what makes it possible to pull one file out of a large backup. It is a different job entirely, specified byte by byte in the Archive Format reference.
WARNING
The single-stream approach below does not work on a file backup. Decrypting it as one blob produces nothing usable - use the Recovery Kit, or implement the format from that reference.
Best Practices
Storage Recommendations
| Location | Security | Accessibility |
|---|---|---|
| Password Manager | ✅ High | ✅ Easy |
| Encrypted USB | ✅ High | ⚡ Medium |
| Bank Safe Deposit | ✅ Very High | ❌ Difficult |
| Printed (sealed) | ✅ High | ❌ Manual entry |
Multiple Copies
Store Recovery Kit in:
- Primary: Password manager (Bitwarden, 1Password)
- Secondary: Encrypted USB at home
- Tertiary: Sealed envelope at trusted location
Test Regularly
- Download a fresh Recovery Kit quarterly
- Actually run it against a recent backup - unzip it somewhere, copy a backup next to it, start it and check the restored files. It takes a minute, and it is the only way to know the kit, the key and the backup all still line up.
- Re-download after any change to the profile
Update After Key Rotation
When creating new encryption profile:
- Download new Recovery Kit
- Update all storage locations
- Keep old kit until old backups expire
Troubleshooting
macOS: "You do not have permission to open the document"
The launcher lost its executable bit. Kits generated before v3 all have this. Download the kit again, or run it from a terminal instead:
cd /path/to/the/kit
node dbackup-recover.jsmacOS: "Apple could not verify ... is free of malware"
Gatekeeper quarantines anything downloaded from the internet. The dialog only offers Move to Trash and Done - the approval lives elsewhere:
- Click Done.
- System Settings → Privacy & Security, scroll to Security.
- Open Anyway next to
START-macOS.command, confirm, then Open Anyway again.
macOS 14 and older allow the shortcut of right-clicking the file and choosing Open. Apple removed that in macOS 15. Running node dbackup-recover.js from a terminal avoids the whole thing.
"Decryption failed. Either the key is wrong or the backup is damaged."
The key in this folder does not open this backup. Each encryption profile has its own key, so check you have the kit for the profile the job used - the backup's .meta.json names it under encryption.profileId. Downloading a kit that covers every profile avoids the question entirely. If the key is right, the backup file itself is damaged and needs downloading again.
A kit with several keys reports this as "None of the N keys in this kit open ..." and lists what it tried.
The same cause reads as Authentication failed for entry N on a file backup, which verifies each entry separately.
"No metadata found at ...meta.json"
The .meta.json sidecar holds the IV and authentication tag, so a backup cannot be decrypted without it. Copy it from the backup destination alongside the backup itself - it sits right next to it.
"This backup is part of an incremental chain and N archive(s) it needs are missing"
An incremental snapshot reads files out of the earlier archives of its chain. Copy the whole chain-... folder rather than a single .tar from inside it. The message names the archives it could not find, and --list shows the full set a snapshot depends on.
Decrypting Without Node.js
Only for database-only backups - a file backup needs the archive format, see above.
Python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import gzip, json
key = bytes.fromhex(open('master.key').read().strip())
meta = json.load(open('backup.sql.gz.enc.meta.json'))
iv = bytes.fromhex(meta['encryption']['iv'])
tag = bytes.fromhex(meta['encryption']['authTag'])
encrypted = open('backup.sql.gz.enc', 'rb').read()
# The tag is appended to the ciphertext for AESGCM.decrypt()
plain = AESGCM(key).decrypt(iv, encrypted + tag, None)
if meta.get('compression') == 'GZIP':
plain = gzip.decompress(plain)
open('backup.sql', 'wb').write(plain)Not with the openssl command line
openssl enc cannot verify a GCM authentication tag, so it either refuses these files or produces unverified output. Use a real AES-GCM implementation - the Python snippet above, or the Recovery Kit.
Emergency Checklist
When you need to use Recovery Kit:
- [ ] Locate the Recovery Kit
- [ ] Download the backup, including its
.meta.json- and the whole folder if it is an incremental chain - [ ] Install Node.js if needed
- [ ] Unzip the Recovery Kit
- [ ] Copy the backup into the same folder
- [ ] Start the launcher, or
node dbackup-recover.jsin a terminal there - [ ] Follow the prompts, then check the files under
restored/ - [ ] Restore to database
Next Steps
- Encryption Vault - Manage encryption profiles
- Restore - Normal restore process
- System Backup - Backup DBackup itself