How to set up encrypted backups you can actually restore
Most people have a backup. Fewer have a backup they have ever restored from. I have watched a friend find out at the worst possible moment that their external drive had been full for eight months, and that the “backup” was a folder of half-copied files. Encryption makes this worse in one specific way: if you lose the key or the password, the backup is not just stale, it is unreadable to everyone, including you.
This tutorial is for anyone who keeps personal or small business data on a laptop or a home server and wants an offsite, encrypted copy that they have proven works. It assumes you are comfortable pasting commands into a terminal. I use restic with Backblaze B2 because it is simple, open source and cheap, but the habits here (separate key storage, a scheduled job, a restore test) apply to any tool.
By the end you will have an encrypted repository in the cloud, a scheduled nightly backup, a retention policy, and a written restore drill that you have run at least once.
what you need
- a computer to back up: Windows, macOS or Linux all work. restic is a single binary
- restic: free and open source, installed from your package manager (
winget install restic.restic,brew install restic,apt install restic) or from the restic documentation download page - a Backblaze B2 account: B2 storage has been priced at roughly $6 to $7 per TB per month, with a free tier for the first 10 GB. check the current numbers on the Backblaze B2 pricing page before you commit, since prices change
- a password manager or a printed sheet: somewhere that is not the computer you are backing up
- a USB stick: for the offline copy of your repository password
- about 45 minutes for the first run, plus however long your first upload takes. my 180 GB first backup took most of a night on a 300 Mbps line
Budget for a typical laptop with 200 GB of data: about $1.20 to $1.40 a month. B2 also charges for download (egress) during a restore, so read the current terms first.
step by step
1. decide what you are backing up
Write the list before you touch a tool. Back up things you cannot re-download: documents, photos, password manager exports, SSH keys, config files, project folders. Skip things you can rebuild: the OS, installed apps, package caches, node_modules.
Action: make a plain text file called include.txt with one path per line, and exclude.txt with patterns.
# include.txt
/home/xavier/Documents
/home/xavier/Pictures
/home/xavier/.ssh
/home/xavier/projects
# exclude.txt
node_modules
.cache
*.tmp
Downloads
Expected output: two small text files. Nothing runs yet.
If it breaks: if you are unsure whether a folder matters, include it. Storage is cheap and a missing file is not.
2. create a bucket and a restricted application key
Log in to Backblaze, create a private bucket (names are global, so add something unique), and leave Backblaze’s own server-side encryption on if offered. Then create an application key scoped to that one bucket only, not your master key.
This matters for a privacy reason. If the laptop is compromised, the attacker gets a key that can touch one bucket, not your whole account. Some operators also use a key without delete permission plus a separate maintenance key, so ransomware on the client cannot wipe history.
Expected output: a keyID and an applicationKey. The applicationKey is shown once.
If it breaks: if you lost the applicationKey, delete that key and make a new one. You cannot retrieve it later.
3. store credentials outside the backup target
Put the B2 credentials in environment variables for the session, and the repository password in a file with tight permissions.
export B2_ACCOUNT_ID="your-keyID"
export B2_ACCOUNT_KEY="your-applicationKey"
export RESTIC_REPOSITORY="b2:my-unique-bucket-name:laptop"
export RESTIC_PASSWORD_FILE="$HOME/.config/restic/pass"
mkdir -p ~/.config/restic
openssl rand -base64 32 > ~/.config/restic/pass
chmod 600 ~/.config/restic/pass
On Windows PowerShell, use $env:B2_ACCOUNT_ID = "..." and create the password file under your user profile, then restrict it with icacls.
Expected output: no output, just a password file. Print it once with cat so you can copy it in the next step.
If it breaks: if openssl is missing on Windows, generate a passphrase in your password manager and paste it into the file.
4. save the repository password in two places, right now
This is the step people skip. restic encrypts the repository with a key derived from that password. There is no reset and no recovery. The restic docs on repositories are direct about this: lose the password and the data is gone.
Action: copy the password into your password manager, and also onto the USB stick (or paper) that lives somewhere physically separate, like a drawer at a relative’s home. Do this before the first backup, not after.
Expected output: the same string in three places: the file, the password manager, the offline copy.
If it breaks: if your password manager is itself backed up by this tool, that is circular. The offline copy is the one that breaks the loop.
5. initialise the repository
restic init
Expected output:
created restic repository a1b2c3d4e5 at b2:my-unique-bucket-name:laptop
Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.
If it breaks: a 401 or “authorization failed” error usually means the key is scoped to a different bucket than the one in RESTIC_REPOSITORY, or you pasted the master key ID with an application key. Recheck both values with no trailing spaces.
6. run the first backup
restic backup \
--files-from ~/.config/restic/include.txt \
--exclude-file ~/.config/restic/exclude.txt \
--verbose
Expected output: a scrolling list of files, then a summary like snapshot 3f9a1c2b saved with the file count and bytes added.
If it breaks: if it stalls or dies on a flaky connection, just rerun it. restic resumes from the chunks already uploaded. If it complains about permission denied on certain files, note them, since a backup that silently skips your .ssh folder is not the backup you think it is.
7. schedule it and set retention
A backup you run by hand is a backup you will forget. On Linux, use a systemd timer or cron. On Windows, Task Scheduler. On macOS, launchd.
A cron example that runs at 02:30 nightly, then prunes old snapshots:
30 2 * * * . $HOME/.config/restic/env && restic backup --files-from $HOME/.config/restic/include.txt --exclude-file $HOME/.config/restic/exclude.txt --quiet >> $HOME/restic.log 2>&1
0 4 * * 0 . $HOME/.config/restic/env && restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune >> $HOME/restic.log 2>&1
Put the exports from step 3 into that env file (mode 600) so the job has credentials. The retention line keeps 7 daily, 4 weekly and 12 monthly snapshots, which is enough to undo a mistake you notice a few months late.
Expected output: a log file that grows by a few lines each night.
If it breaks: cron has a minimal environment, which is the number one cause of “it works in my terminal but never runs”. Use absolute paths, including to restic itself.
8. verify the repository is intact
restic check
restic check --read-data-subset=10%
The first command checks the repository structure. The second downloads and verifies a random 10% of the actual data blobs, which catches corruption that a structure check misses. The restic documentation on checking integrity covers the subset options.
Expected output: no errors were found.
If it breaks: if you see errors about missing pack files, run restic repair index first and check again. If data blobs are damaged, the affected snapshots need to be identified and possibly rebuilt from the source machine.
9. do a real restore to a different location
This is the step that turns a copy into a backup.
restic snapshots
restic restore latest --target ~/restore-test --include /home/xavier/Documents
Then open a few files. Open a spreadsheet, a photo, a PDF. Compare a checksum on one:
sha256sum ~/Documents/tax-2025.pdf ~/restore-test/home/xavier/Documents/tax-2025.pdf
Expected output: matching hashes and files that open.
If it breaks: if the restore fails with a wrong password error, your password file does not match what you saved in step 4. Fix this today, while you still have both.
10. rehearse the worst case
The restore in step 9 used your working laptop, with credentials already loaded. The real disaster is a dead laptop. On a second machine, or a fresh VM, or a live USB session, install restic, fetch the password from your offline copy, create a new B2 application key (or use a read-only one you kept in the password manager), and restore.
Write a half-page runbook in plain text: which bucket, which repo path, where the password lives, the exact restore commands. Store it with the offline copy.
Expected output: a restore from nothing, using only what is in your runbook.
If it breaks: whatever you had to improvise goes into the runbook. That is the value of the drill.
common pitfalls
- storing the only copy of the repository password on the machine being backed up
- never restoring. the first restore should not be during an emergency, when you are stressed and the source is gone
- backing up to a drive that is always plugged in and writable. ransomware and accidental deletion reach it too. an offsite target with a restricted key is safer
- ignoring the log. a cron job failing quietly for three months looks identical to a working one, until you look
- excluding too broadly. a wide exclude pattern like
*.dbcan silently drop a password vault or a local database you cared about. review what a snapshot actually contains withrestic ls latest
It also helps to think about what a backup does to your deletion habits. Data you “deleted” may still sit in old snapshots, which is a feature for recovery and a liability for privacy. I wrote about that tension in what actually gets deleted when you delete it, and it applies to your own retention policy too. Set the forget rules deliberately.
scaling this
From 1 machine to 10 machines (a household, a small office): give each machine its own repository path and its own restricted key, so one compromised laptop cannot read or delete the others. Keep one shared inventory of where each password is stored. Automate the monthly restic check and send yourself the result.
From 10 to 100: manual runbooks stop working. You need configuration management (Ansible or similar) to deploy the same script and timer everywhere, a central place that records last-successful-backup per host, and alerts when a host has been silent for 48 hours. Consider a healthchecks-style dead man’s switch, where each job pings a URL on success and you get an alert when the ping stops.
From 100 to 1000: you are running a backup service, not a backup script. Pruning a large repository can take hours and needs planning, and B2 transaction costs and egress deserve a proper cost model. At this scale many teams move to a dedicated backup product or self-hosted object storage, and to separate credentials for backup, restore and maintenance with real audit logging. The principle survives the change of tools: the backup is proven only by a restore, and the keys live somewhere the failure cannot reach.
If you already run infrastructure for a hosted service and want to think about where backups sit relative to your servers, the cloudf.one blog covers the hosting side of that question.
where to go next
- how to lock down a windows laptop for privacy: the disk encryption and account hygiene that sit underneath a good backup
- how to secure a family member’s devices without being their IT department: the same restore drill, applied to a relative’s laptop
- the blog index: everything else we have published on privacy and operations
Written by Xavier Fok
disclosure: this article may contain affiliate links. if you buy through them we may earn a commission at no extra cost to you. verdicts are independent of payouts. last reviewed by Xavier Fok on 2026-09-30.