Encrypted, Deduplicated Backups on Linux with restic and AI
How to set up restic for encrypted, deduplicated, snapshot-style Linux backups, automate them with systemd, and use AI to design a restore plan you can actually trust.
- #linux
- #ai
- #backups
- #restic
- #encryption
- #systemd
Every admin has a backup story that ends badly. Mine: a perfectly healthy nightly rsync job that had been faithfully mirroring a corrupted database for three weeks, so every copy was equally useless. The backup ran. The restore was worthless. The lesson stuck: a backup you’ve never restored is a hypothesis, not a backup.
restic is the tool I reach for now when I want backups that are encrypted by default, deduplicated so they don’t balloon, and snapshot-based so I can roll back to a specific point in time. It’s a single Go binary, it speaks to local disks, SFTP, S3, B2, and more, and it does the things that are genuinely hard — dedup, encryption, integrity verification — without me hand-rolling them. Here’s how I set it up, and where an AI copilot helps me design the part that actually matters: the restore.
Why restic over a plain rsync mirror
rsync is wonderful and I still use it for mirroring. But a mirror is not a backup history. restic gives you three things a naive rsync job doesn’t:
- Content-addressed deduplication. Identical chunks are stored once across all snapshots, so keeping 30 daily snapshots of a mostly-static filesystem costs a fraction of 30 full copies.
- Encryption by default. The repository is encrypted with a key derived from your password. The backup destination — even a third-party bucket — never sees your plaintext.
- Real snapshots with verification. Each backup is a point-in-time snapshot you can list, diff, mount, and check for integrity.
That last point is the one people skip and regret.
Initializing a repository
Pick a destination and initialize. I’ll use a local path for clarity, but the same commands work with s3:, sftp:, b2:, etc.
export RESTIC_REPOSITORY="/srv/backups/restic"
export RESTIC_PASSWORD_FILE="/etc/restic/password" # 0400 root-only
sudo install -m 0700 -d /srv/backups/restic
sudo restic init
Store the password somewhere you will still have access to it after the machine you’re backing up is gone. This is the single most important sentence in this article: if you lose the restic password, the repository is unrecoverable by design. Encryption with no escrow means a lost key equals lost data. Put the password in a password manager and a sealed offline copy — not only on the host being backed up.
A real backup command
sudo restic backup \
--exclude-caches \
--exclude '/var/cache' \
--exclude '/var/lib/restic' \
--tag nightly \
/etc /home /srv /var/lib
--exclude-caches honors CACHEDIR.TAG markers so you don’t waste space backing up regenerable caches. Tagging snapshots makes retention policy and filtering far easier later.
Retention that doesn’t eat your disk
Backups without a forget/prune policy grow forever. restic’s policy engine is expressive:
sudo restic forget --prune \
--keep-daily 7 \
--keep-weekly 5 \
--keep-monthly 12 \
--keep-yearly 3 \
--tag nightly
forget removes snapshot references; --prune actually reclaims the now-unreferenced data. Run prune on a schedule, not every night, since it’s the heavier operation.
Automating with a systemd timer
Cron works, but a systemd service plus timer gives you logging, failure tracking, and dependency ordering for free.
# /etc/systemd/system/restic-backup.service
[Unit]
Description=restic nightly backup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/bin/restic backup --exclude-caches --tag nightly /etc /home /srv
ExecStartPost=/usr/bin/restic forget --prune --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --tag nightly
Nice=10
IOSchedulingClass=idle
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run restic backup nightly
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=900
Persistent=true
[Install]
WantedBy=timers.target
Persistent=true means a missed run (laptop asleep, host down) fires on next boot. RandomizedDelaySec spreads load if you’re backing up a fleet to one destination.
The part that matters: restore design with AI
Here’s where I genuinely lean on an AI copilot — not for the backup, but for the restore plan, because that’s the part you only exercise under stress. I describe my setup and ask it to design and pressure-test the recovery.
Prompt: I run restic nightly to an SFTP repo, retention 7 daily / 5 weekly / 12 monthly. Design a restore runbook for two scenarios: (1) a single accidentally-deleted directory, (2) total host loss, restoring onto a fresh machine. List the exact commands, what I need to have stored off-host, and the verification step for each. Flag anything that fails silently.
Response (excerpt): Scenario 1 —
restic snapshots --tag nightlyto find the snapshot, thenrestic restore <id> --target /tmp/recover --include /srv/app/config; verify with a diff against expectations. Scenario 2 requires the repository URL, the password, and SFTP credentials stored off the host — without all three the encrypted repo is unrecoverable. Bootstrap: install restic, export RESTIC_REPOSITORY + password,restic snapshotsto confirm access, thenrestic restore latest --target /. Silent-failure risk: a snapshot can succeed while a file was mid-write; schedule app-consistent dumps (e.g.pg_dump) before the restic run, and runrestic check --read-data-subset=10%weekly to catch repo corruption your nightly backup won’t reveal.
That response caught the two things people miss: that the password and credentials must live off the machine being backed up, and that restic check is a separate, essential job because a successful backup tells you nothing about repository integrity. The AI drafted the runbook; I then actually ran a test restore into a throwaway target to prove it. AI designs the plan, the human verifies it by restoring for real — a runbook you’ve never executed is just more hypothesis.
Verify, or it isn’t a backup
Two verification habits make the difference:
# Structural integrity of the repo (cheap, run often)
restic check
# Actually re-read a sample of the data from the backend (catches bit-rot)
restic check --read-data-subset=10%
# The only test that counts: restore something and look at it
restic restore latest --target /tmp/restore-test --include /etc/hostname
If you do nothing else, schedule a periodic real restore of a small file and eyeball it. Everything else is theory.
The takeaway
restic gives Linux admins encrypted, deduplicated, snapshot-based backups from a single binary, and systemd timers make the scheduling robust. But the tooling is the easy 80%. The hard 20% — the part that determines whether a 3am outage ends in a clean restore or a useless mirror of corrupted data — is the restore plan, the off-host key escrow, and the verification discipline. AI is excellent at drafting that runbook and flagging the silent-failure traps, but it can’t restore for you. Run the test restore yourself, confirm the password lives somewhere the host’s death can’t take with it, and keep restic check on its own schedule.
For how this fits into a broader strategy, see Linux backup and restore done right and encrypting Linux disks with LUKS for protecting the data at rest. To bootstrap the restore runbook, the Linux patch and package automation prompt pairs well with a recovery-focused session.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.