Borg vs Restic: Painless Encrypted Backups You'll Actually Run

Because the best backup is the one that happens

Contents

The only backup I have ever needed in a genuine emergency was the one I almost did not have. A failing SSD, a half-corrupted home directory, and the cold realisation that the “backup” I had been meaning to set up for months did not exist. I got lucky that time. The reason I had no backup was not ignorance — I knew exactly why I needed one. It was friction. A scheme that is fiddly, slow or expensive simply does not get run, and an un-run backup is worth precisely nothing the day the disk dies.

The good news is that two excellent open-source tools — BorgBackup and Restic — have made encrypted, deduplicated, automatable backups genuinely painless. This article walks through both, with real commands, so you can pick one and actually use it. I will tell you which one I reach for and why, and — more importantly — how to wire it up so it runs without you ever thinking about it again.

The 3-2-1 rule, briefly

Advertisement

Before touching tooling, internalise the rule that has saved more data than any single product: 3-2-1. Keep 3 copies of your data, on 2 different types of media, with 1 copy off-site. The production copy counts as one. A local backup on a different disk is your second. An off-site copy — a remote server, an object store, a friend’s NAS — is the third, and it is the one that survives fire, theft and ransomware. Both Borg and Restic are designed to make that off-site copy cheap and safe, because everything is encrypted before it leaves your machine. The server holding your backups never sees a byte of plaintext, which means an off-site target you do not fully trust is still safe to use.

What Borg and Restic are

Both are command-line backup programs that share three crucial properties.

  • Deduplication. Files are split into content-defined chunks, and identical chunks are stored only once. Back up a 10 GB directory daily and the repository grows by the size of what actually changed, not 10 GB a day. Move a large file, rename a directory, restore from an older copy — dedup sees the same chunks and stores nothing new.
  • Compression. Chunks are compressed before storage, shrinking the repository further. Both default to sensible modern algorithms (zstd is the one to choose if you have a choice).
  • Encryption. Data is encrypted client-side with a passphrase or key. Authenticated encryption means the repository is also tamper-evident, not just confidential.

The result is space-efficient, secure backups where each “snapshot” looks like a full backup but costs roughly the size of an incremental one. The main difference between the two tools is where they like to store data, which we will get to.

A worked Borg example

Advertisement

Install Borg from your distribution (sudo apt install borgbackup or sudo dnf install borgbackup). Borg works against a repository, which can be a local path or an SSH target.

1. Initialise the repository with encryption:

1
2
export BORG_REPO=/mnt/backup/borg-repo
borg init --encryption=repokey-blake2 "$BORG_REPO"

repokey stores the encryption key inside the repository itself, protected by your passphrase — convenient, but back the passphrase up somewhere safe and separate, because losing it means losing the backup. For an SSH target, the repo URL looks like ssh://user@host:22/./backups/borg-repo.

2. Create a snapshot. Borg calls them archives; naming them with a timestamp keeps things tidy:

1
2
3
4
borg create --stats --compression zstd \
  "$BORG_REPO::{hostname}-{now:%Y-%m-%d}" \
  /etc /home /var/www \
  --exclude '/home/*/.cache'

The --stats flag prints how much was deduplicated, which is satisfying the first time you see it — the “deduplicated size” line is what your run actually cost in storage.

3. Prune old archives so the repository does not grow forever:

1
2
borg prune --list "$BORG_REPO" \
  --keep-daily=7 --keep-weekly=4 --keep-monthly=6

This retention policy keeps a week of dailies, a month of weeklies and half a year of monthlies, expiring the rest. In recent Borg, follow prune with borg compact "$BORG_REPO" to actually reclaim the freed space on disk — prune only removes the references, compact does the cleanup.

4. Check integrity periodically so you discover corruption before you need a restore:

1
borg check --verify-data "$BORG_REPO"

Restoring is borg extract "$BORG_REPO::archive-name", or borg mount to browse an archive as a normal directory and copy out individual files with a file manager.

A worked Restic example

Install Restic (sudo apt install restic or sudo dnf install restic). Restic’s headline feature is the sheer number of backends it speaks: local, SFTP, S3-compatible object stores, Backblaze B2, Azure, Google Cloud, a dedicated REST server, and more, all built into a single static binary.

1. Initialise, here against an S3-compatible bucket:

1
2
3
4
5
export RESTIC_REPOSITORY="s3:https://s3.eu-central-1.amazonaws.com/my-backup-bucket"
export RESTIC_PASSWORD="a-long-strong-passphrase"
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
restic init

The same RESTIC_REPOSITORY set to /mnt/backup/restic would target a local disk, or sftp:user@host:/srv/restic an SSH server, or rest:https://backup.example.com/ a Restic REST server — the rest of the commands are identical regardless of backend. That uniformity is Restic’s real charm: learn the commands once, point them anywhere.

2. Back up:

1
2
3
restic backup /etc /home /var/www \
  --exclude="/home/*/.cache" \
  --tag nightly

Restic deduplicates against everything already in the repo, so subsequent runs are fast and small.

3. Forget and prune with a retention policy, in one go:

1
2
3
restic forget --tag nightly \
  --keep-daily=7 --keep-weekly=4 --keep-monthly=6 \
  --prune

forget removes the snapshot references; --prune reclaims the now-unreferenced data. Doing both together is the common pattern.

4. Restore a snapshot. List snapshots first, then restore by ID or latest:

1
2
restic snapshots
restic restore latest --target /tmp/restore-test

You can also restic mount /mnt/restic and browse every snapshot as a filesystem, which is the fastest way to grab one accidentally-deleted file.

Borg versus Restic: which to choose

They overlap heavily, so the decision comes down to a few honest trade-offs.

Choose Borg if storage efficiency is paramount and your backup target is a single server or local disk reachable over SSH. Borg’s deduplication and compression are excellent, and its append-only mode (more on that below) is a strong defence against a compromised client trying to delete history. The catch: Borg essentially wants SSH or a local path. There is no native object-store support, so cloud storage means a helper such as Rclone, or a hosted service like BorgBase.

Choose Restic if you want to back up straight to object storage — S3, B2, Wasabi and the like — without an intermediary, or if you value backend flexibility and a single static binary you can drop on any machine. Restic is wonderfully portable and its multi-backend design is its biggest strength. The trade-off is that for some workloads it has historically used more memory and been a touch less storage-efficient than Borg, though both improve constantly and the gap is small for most homelabs.

In practice: SSH-reachable server, lean towards Borg. Cloud object store as the off-site leg, lean towards Restic. I run Restic to an object store for the off-site copy and Borg over SSH for the fast local one — they coexist happily, and using both means a bug or breaking change in one tool never takes out my entire backup strategy at once. Either one, run consistently, beats the cleverest scheme you never automate.

Ransomware resistance: append-only mode

A backup that a compromised machine can delete is not a backup against ransomware — it is a backup against accidents only. If an attacker gets root on the box being backed up, they get the credentials to the repository, and the obvious next move is to wipe it. Both tools have an answer, and it is worth setting up.

Borg supports an append-only repository natively over SSH: the client can add new archives but cannot delete or modify existing ones, so a compromised client cannot destroy history. Restic achieves the same protection through its REST server’s append-only mode, which accepts new data but refuses deletes and overwrites; the pruning that genuinely removes data is then done out-of-band by a trusted process, not by the backed-up host. Set this on your off-site target and a ransomware incident on the client becomes a restore exercise, not a catastrophe. This is the same defence-in-depth instinct behind verifying container images with Sigstore before they run — assume the running host may be compromised and make the outcome of that compromise survivable.

Automating with systemd timers

A backup you run by hand is a backup you will forget. Wrap your chosen command in a small script, then drive it with a systemd timer. Create /etc/systemd/system/backup.service:

1
2
3
4
5
6
7
[Unit]
Description=Nightly Restic backup

[Service]
Type=oneshot
EnvironmentFile=/etc/restic/backup.env
ExecStart=/usr/local/bin/run-backup.sh

And /etc/systemd/system/backup.timer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Unit]
Description=Run backup nightly

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=900

[Install]
WantedBy=timers.target

Persistent=true runs a missed backup if the machine was asleep at 02:30, and RandomizedDelaySec spreads load if many machines back up to the same target. Enable it with sudo systemctl enable --now backup.timer, and every run lands in the journal (journalctl -u backup.service). Keep credentials and passphrases in the EnvironmentFile, locked down to mode 600 and owned by root. Check systemctl list-timers to confirm the next run is actually scheduled — a timer you forgot to enable is a backup that never runs.

Troubleshooting: what goes wrong

A run hangs or another is already in progress. Both tools take a repository lock. If a previous run was killed mid-flight, the lock can be left behind; borg break-lock "$BORG_REPO" or restic unlock clears a stale lock — but only after you have confirmed no other backup is genuinely running, or you risk repository corruption.

The repository keeps growing despite pruning. With Borg, prune without a subsequent borg compact does not free disk space; add the compact step. With Restic, forget without --prune leaves the data in place; run the prune.

Out-of-memory on a small box. Large repositories and full-table-style backups can be memory-hungry, historically more so with Restic. Back up to a target with adequate RAM, prune aggressively to keep the repository smaller, and split enormous datasets into separate repositories.

Backups are slow over a thin link. The first backup is always the big one — everything is new. Seed it locally and then ship the disk, or accept one slow initial run; subsequent runs only move changed chunks. Don’t mistake a slow first run for a slow tool.

You lost the passphrase. There is no recovery. This is not a bug, it is the encryption working as designed. Store the passphrase and any key file in a password manager and somewhere offline, the day you create the repository.

Knowing when to leave a working setup alone matters as much as knowing how to fix it; the instinct in deciding when home-lab technical debt is worth refactoring versus letting it rot applies here — a boring backup that has run untouched for a year is not a problem to solve, it is the goal.

Testing restores, the part everyone skips

A backup you have never restored is a hypothesis, not a backup. Schedule a recurring restore test — even monthly — that pulls a known file out of the latest snapshot and checks it. For Restic:

1
2
restic restore latest --target /tmp/restore-check --include /etc/hostname
diff /etc/hostname /tmp/restore-check/etc/hostname && echo "restore OK"

For Borg, borg extract a small archive into a scratch directory and compare. Also run borg check or restic check on a schedule to catch silent corruption early. The day you genuinely need a restore is the worst possible time to discover the process does not work.

Verdict: is it worth it, and for whom?

If you have any data you would be upset to lose — and everyone does — then yes, unequivocally. Borg and Restic both deliver encrypted, deduplicated, compressed backups that are cheap to store and quick to run, and either one is painless enough that the friction excuse no longer holds. For a single Linux box or NAS reachable over SSH, Borg is my default for the local copy. For a straight-to-cloud off-site leg, Restic is the cleaner fit. Pick the one that matches your storage, automate it with a systemd timer, put the off-site copy in append-only mode, satisfy 3-2-1, and — above all — test your restores. The best backup remains the one that actually happens, and now you have no excuse not to make it happen automatically tonight.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.