Restic + Rclone: Offsite Backups That Survive Your Own Mistakes

Encrypted, deduplicated backups to storage you don't fully trust

Contents

The backups I actually worry about are not the ones that protect against a dead disk. A dead disk is boring; redundant storage handles it. The backups that keep me honest are the ones that protect against me — the rm -rf in the wrong directory, the botched migration that corrupts a database, the ransomware that a family member invites in by clicking something. Those failures happen on the live machine and propagate to anything the live machine can reach, which is precisely why the copy that saves you has to live somewhere the mistake cannot follow. Offsite, encrypted, and ideally impossible for a compromised client to delete.

Restic and Rclone together are how I do that, and the combination is more capable than either alone. Restic gives you encrypted, deduplicated, snapshot-style backups. Rclone gives Restic a doorway to essentially every cloud storage provider that exists, including ones Restic cannot natively talk to. This is a worked guide: why the pairing beats going straight to a single provider, the exact commands, how to make the offsite copy resistant to your own worst day, and the failure modes that will actually occur.

Why two tools instead of one

Advertisement

Restic already speaks several backends directly — local paths, SFTP, S3-compatible object stores, Backblaze B2, a few clouds and its own REST server. For a lot of setups that is enough, and you do not need Rclone at all. The reason to add Rclone is reach and flexibility. Rclone talks to more than seventy storage providers, handles the OAuth dances that consumer clouds demand, and can present any of them to Restic through a single uniform interface. If your cheapest offsite option is a provider Restic has never heard of, Rclone bridges the gap.

The mechanism is clean. Restic has an rclone: backend that shells out to Rclone and streams the repository through it. You configure the remote once in Rclone, point Restic at rclone:<remote>:<path>, and Restic behaves exactly as it would against any other backend — same commands, same encryption, same dedup. Restic does the cryptography and the chunking; Rclone does the talking to the provider. The division of labour means you learn Restic’s commands once and can retarget the whole backup at a different cloud by editing one Rclone remote.

Crucially, Restic encrypts before Rclone ever sees the data. The provider on the far end stores authenticated ciphertext and nothing else, so an offsite target you have no reason to trust — a cheap consumer cloud, someone else’s server — is still safe to use. That is the same threat model that makes a self-hosted MinIO bucket a fine backup target even though it is “only” a box in a cupboard: the storage never holds anything readable.

Setting up the Rclone remote

Rclone’s interactive config walks you through adding a remote. Run rclone config, pick your provider, and follow the prompts; for OAuth providers it opens a browser to authorise. The result is a named remote in ~/.config/rclone/rclone.conf. Here is what a configured B2 remote looks like (edit the file directly once you know the shape):

1
2
3
4
[offsite]
type = b2
account = 0011223344556677
key = K001xxxxxxxxxxxxxxxxxxxxxxxxxxx

Test it before you trust it:

1
2
# prove Rclone can reach the remote and list a bucket
rclone lsd offsite:my-backup-bucket

Once rclone lsd works, Restic can use that remote. You do not need to understand the provider’s API — Rclone abstracts it away, and swapping providers later means adding a new remote and changing one environment variable.

Initialising and running the Restic repository

Advertisement

Point Restic at the Rclone remote and initialise the repository. I keep the credentials in an environment file so nothing sensitive lives in shell history:

1
2
3
# /etc/restic/offsite.env  (chmod 600, owned by root)
export RESTIC_REPOSITORY="rclone:offsite:my-backup-bucket/restic"
export RESTIC_PASSWORD_FILE="/etc/restic/passphrase"
1
2
source /etc/restic/offsite.env
restic init

That single restic init creates an encrypted repository inside the bucket. The passphrase in /etc/restic/passphrase is the only thing standing between an attacker and your data — and the only thing standing between you and your data if you lose it. Store it in a password manager and somewhere offline the day you create the repo, because there is no recovery path.

A backup run names what to include and what to skip:

1
2
3
restic backup /etc /home /srv \
  --exclude-file=/etc/restic/excludes.txt \
  --tag nightly

Deduplication means the first run ships everything and every run after it moves only changed chunks, so nightly backups over a home uplink stay small. Restic also compresses by default in current versions, which shrinks the repository further before anything is uploaded.

Retention is handled by forget, which drops old snapshots according to a policy, and --prune, which reclaims the space they held:

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

That keeps a week of dailies, a month of weeklies and a year of monthlies, expiring the rest and freeing the storage in one command.

Restoring is the mirror image of backing up. List what you have with restic snapshots, then restic restore latest --target /tmp/recover pulls a whole snapshot back, or add --include /path to grab a subset. For hunting one deleted file, restic mount /mnt/restic exposes every snapshot as a browsable filesystem you can copy out of with an ordinary file manager, which is the fastest route to a single accidental deletion without a full restore.

Making it survive your worst day

An offsite copy that a compromised client can delete only protects against accidents, not against a determined attacker or ransomware that specifically hunts backups. The credentials to your repository live on the machine being backed up, so root on that machine means the power to wipe the repo. Two defences matter.

First, use the provider’s immutability. Backblaze B2 and S3-compatible stores support object lock / WORM retention, so objects cannot be deleted or overwritten until a retention date passes even by someone holding valid keys. Turn that on at the bucket and a ransomware run that tries to delete your history simply fails. This is the same immutable-storage idea that makes object locking on a local S3 endpoint worthwhile, and it is the strongest single thing you can add.

Second, separate the pruning privilege. The backed-up host should have credentials that can write and read but not delete. A separate, trusted machine — one an attacker on your main host cannot reach — runs the forget --prune that genuinely removes data. Restic’s own append-only story is cleanest through its REST server, but at the Rclone/provider layer you get the same outcome by scoping the host’s application key to write-only and doing destructive maintenance from elsewhere. The principle is to make deletion something your everyday backup identity cannot do.

Automating it and never thinking about it again

Wrap the run in a script and drive it with a systemd timer so it happens without you. The service:

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

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

The timer:

1
2
3
4
5
6
7
[Timer]
OnCalendar=*-*-* 03:20:00
Persistent=true
RandomizedDelaySec=1200

[Install]
WantedBy=timers.target

Persistent=true catches up a run the machine slept through, and the randomised delay stops several machines hammering the provider at the same second. Enable with systemctl enable --now restic-offsite.timer and check systemctl list-timers to confirm it is actually scheduled — an unscheduled timer is a backup that silently never runs. Every run lands in the journal for later inspection.

None of this counts as done until the offsite copy is one leg of a wider plan. On its own it is a single remote copy; combined with a local copy and your production data it satisfies the 3-2-1 rule properly implemented, and it is only trustworthy once you have proven a restore works, which is a discipline of its own worth rehearsing deliberately.

Troubleshooting: what actually goes wrong

restic: command not found inside the timer, but it works in your shell. systemd services run with a minimal PATH. Use the absolute path to both restic and rclone in the script, or set Environment=PATH=... in the unit. This catches almost everyone the first night.

Rclone authorisation expired. OAuth tokens for consumer clouds expire and need refreshing; a backup that ran for months suddenly fails with an auth error. Re-run rclone config reconnect offsite: to refresh the token. For business-key providers like B2 this does not happen, which is one reason I prefer key-based remotes for unattended backups.

A run aborts with a stale lock. If a previous backup was killed mid-flight, Restic leaves a lock in the repository and later runs refuse to start. Confirm nothing is genuinely running, then restic unlock. Do not unlock blindly while another backup might be live, or you risk corrupting the repository.

The first backup is agonisingly slow. The initial run uploads everything, which over a domestic upload link can take days for a large dataset. This is simply how the first run behaves, and every run after it is incremental and quick. If it is truly impractical, seed the repository to a local disk first and ship or sync it up, then continue incrementally.

Uploads are rate-limited or the provider throttles you. Rclone can pace itself; --bwlimit on the Rclone side (passed via Restic’s -o rclone.args) keeps a backup from saturating your uplink and keeps the provider happy. Throttling looks like a hang, so check your uplink usage before assuming the process has crashed.

Pruning is slow and memory-hungry. prune rewrites repository index and pack files and can be heavy on large repositories. Run it less often than you back up (weekly prune, nightly backup is a common split), and give the machine doing it enough RAM. Recent Restic prune is far lighter than it once was, but a huge repo still wants headroom.

Operations are slow or throw odd errors after a while. Restic keeps a metadata cache under ~/.cache/restic to avoid re-downloading index data every run. On a constrained host it can grow, and a corrupted cache produces confusing failures. restic cache --cleanup prunes stale cache directories, and deleting the cache entirely is safe — Restic rebuilds it from the repository on the next run.

restic check reports errors. Run restic check on a schedule so corruption is found early. If it flags problems, restic check --read-data verifies actual pack contents and restic repair can rebuild a damaged index. Discovering corruption during a real restore is the nightmare this scheduled check exists to prevent.

Verdict: is it worth it, and for whom?

If you keep anything you would grieve to lose, an encrypted offsite copy is the backup that matters most, and Restic plus Rclone is the most flexible way I know to build one. Restic’s encryption and dedup mean the storage stays cheap and the provider stays blind; Rclone means you can point that backup at whichever cloud is cheapest this year and change your mind later by editing one remote. Add provider-side immutability, scope the host’s key so it cannot delete, automate it on a timer, and you have an offsite backup that survives a dead disk, a fat-fingered command and a ransomware infection alike.

The pairing is more than most single-laptop users need — if Restic already talks to your chosen provider natively, skip Rclone and save a moving part. Where it earns its place is reach and future-proofing: a homelabber backing up several machines who wants provider independence and refuses to be locked to one cloud’s pricing. Get the passphrase safely stored, prove a restore works before you rely on it, and this is the offsite leg I would build again without hesitation.

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.