Most backup tools force a choice between the two properties that a serious backup wants simultaneously: strong encryption before the data leaves the machine, and deduplication that keeps a year of history affordable. Restic refuses the choice. Every block is encrypted and authenticated on the client, the repository never sees plaintext, and the same chunk-level deduplication that makes incremental backups cheap works identically on the encrypted data. This article builds the complete setup against an S3-compatible backend: the repository and its all-important password, the backup command in daily form, retention policies that keep the history honest, the restore and verification loops, the backend plumbing, and the scheduling that turns the whole mechanism into a property of the server rather than a calendar entry.
The repository and the encryption model
Restic stores everything in a repository, a self-contained structure of encrypted chunks, keys and snapshots, and the first command creates it against the chosen backend. The S3-compatible form names the endpoint and the bucket:
$ restic -r s3:https://s3.example.com/backups init
enter password for new repository:
created restic repository 1a2b3c4d at s3:https://s3.example.com/backups
The password entered at init is the master key to everything the repository will ever hold, and its handling deserves the paragraph it gets. The encryption is client-side and genuine: the backend, whether a public S3 bucket or the MinIO cluster from this series' storage articles, stores opaque chunks that decrypt only with the password. Lost password means lost repository, permanently, with no recovery path by design, so the password lives in the password manager, on paper, and in the site's recovery procedure, tested by a restore before the repository earns production data. The production pattern stores it in a file referenced by the environment:
export RESTIC_REPOSITORY=s3:https://s3.example.com/backups
export RESTIC_PASSWORD_FILE=/etc/restic/passwd
export AWS_ACCESS_KEY_ID=backup-user
export AWS_SECRET_ACCESS_KEY=the-backend-credential
and the four lines, in a systemd EnvironmentFile or a sourced profile, are the entire configuration surface of the tool, an economy that means the backup's behavior is inspectable in one glance.
The backup command and what a snapshot is
The working command is one line:
$ restic backup /srv/data
and the run's output tells the honest story of incremental backups done right: the first run reads everything, chunks it, encrypts it and uploads the full set, and every subsequent run reads the same tree, hashes each file, and uploads only the chunks that changed. The snapshot that results is not a folder copy but a point-in-time pointer into the content-addressed chunk store, and consecutive snapshots that share ninety percent of their data cost a tenth of the space.
The snapshot list is the history interface:
$ restic snapshots
ID Time Host Tags Paths
1a2b3c4d 2026-10-14 03:00:01 app01 /srv/data
5d6e7f8a 2026-10-13 03:00:01 app01 /srv/data
and the tags deserve their habit early: --tag monthly or --tag pre-upgrade on selected runs turns the list from a chronological blur into a labeled history, and the retention policy in the next section can act on the labels. The diff command completes the inspection vocabulary, restic diff 1a2b3c4d 5d6e7f8a printing the files that changed between two snapshots, the answer to the recurring question of what actually happened to the data between two mornings.
Retention that forgets and prunes cleanly
An unbounded backup history grows forever, and restic's retention model splits the cleanup into two honest halves. The forget command applies a policy that selects which snapshots survive, and the policy language reads like the intent it encodes:
$ restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --prune
keeping the last seven dailies, the last five weeklies and the last twelve monthlies, the standard shape that answers both the recent-accident and the last-quarter questions, and the --prune flag on the same invocation follows the deletion with the garbage collection that actually reclaims the space of the forgotten snapshots' orphaned chunks. The two-step nature matters operationally: forget marks snapshots for deletion, prune rewrites the repository removing the chunks nothing references, and the pair run together in the weekly maintenance window keeps the repository's size proportional to the living history rather than to the total accumulation.
The prune step is the one operation with a performance opinion, rewriting pack files on large repositories, and the runbook's honest schedule is the weekly prune for the standard tier and the monthly, longer-window prune for the multi-terabyte repositories where the rewrite cost is measured in hours. The policy and its numbers belong beside the repository in the version-controlled configuration, and changing the retention is a reviewed change like any other, because the policy is the backup's memory and a careless edit is how monthlies quietly become weeklies.
Restoring, mounting and the verification loop
The restore command writes a snapshot back to disk:
$ restic restore 1a2b3c4d --target /tmp/restore
which decrypts and materializes the full tree at the target, and the restored copy is the only proof of a backup that counts, the restore test that the quarterly backup procedure in this series demands. The subtler and more frequently used readback is the mount:
$ restic mount /mnt/restic
exposing the whole history as a FUSE filesystem, every snapshot a directory under the mount point, files browsable and copyable like any filesystem, and the pattern fits the incident workflow precisely, the single file an engineer needs from last Tuesday gets copied straight out of the mounted snapshot without restoring anything larger than that file.
The verification loop is the third pillar and the one that separates a backup from a hope. The check command verifies the repository's structure, and the deep form reads the stored data:
$ restic check --read-data
which downloads and verifies every chunk's authentication, catching the bit rot and the silent corruption that a backend can inflict on data nobody reads. The schedule is the calendar's discipline: a structural check weekly, a data-reading check monthly or quarterly, and the check's exit status feeding monitoring the way every other health signal in this series does, because a repository that verifies clean is a repository whose restores will work, and that is the entire property a backup exists to have.
Backend options and the S3-compatible plumbing
The S3 family covers the backend world because the S3 API became the storage lingua franca, and restic speaks it natively against every implementation the series has built. The public object stores, the S3 service itself and its regional siblings, work with the access key pair and the bucket, and the endpoint form adapts with the URL scheme, s3:https:// for the explicit endpoints and the short form for the default providers. The self-hosted side is the MinIO deployment from the earlier article, and the same backend serves the backup fleet with the same credentials model, the internal endpoint replacing the public one line for line:
$ restic -r s3:https://minio.internal:9000/backups backup /srv/data
The remaining backend families cover the niche cases: the SFTP backend for the remote host with SSH and a directory, the local backend for the attached disk, the rest-server backend for the dedicated backup host running the tool's own protocol, and the rclone backend, restic's bridge to the entire cloud-storage ecosystem through the rclone tool's driver list. The choice among them is a policy about custody and cost rather than a technical fork, and the S3-compatible family is the default recommendation because it is the one that the whole industry, public and private, has converged on.
Scheduling, monitoring and the closing discipline
The systemd timer pattern from across this series carries the schedule, and the backup's unit pair is the standard three-file shape: the service running the backup command with the environment file, the timer triggering it nightly, and the second timer pair running the weekly check. The monitoring story rides the exit codes and the last-snapshot age, a script reading restic snapshots --latest 1 and comparing the timestamp against the wall clock, and the alert that fires when the newest snapshot is older than the schedule allows catches the failure mode that makes backups a genre, the tool that stopped running and nobody noticed.
The closing discipline is the article's own summary. One password, guarded like the master credential it is. One repository, on a backend whose durability the site trusts. One command, run by a timer, checked by a deeper timer, restored from on a quarterly rehearsal. A retention policy in the configuration, reviewed like code. The result is a backup system whose security is mathematical rather than procedural, whose cost is proportional to change rather than to time, and whose restores are the only backup metric that ever mattered, tested, proven and one command away.
Exclusions, caching and the details that shape real runs
The backup of a real tree needs a policy about what it skips, and the exclude file carries it, one pattern per line, versioned with the rest of the configuration:
$ restic backup /srv --exclude-file=/etc/restic/excludes
The patterns speak the standard glob vocabulary, and the recurring entries deserve their runbook paragraph. Cache directories that regenerate on every boot, the node_modules trees and build outputs that the deployment pipeline can reconstruct, the socket and lock files that a live application holds open meaninglessly, and the multi-gigabyte scratch spaces whose contents are, by design, reconstructible: each entry is a decision that the restore will reconstruct the data another way, and the file's comments name the reason beside each pattern. The exclusion review is part of the quarterly restore rehearsal, because the restore test that pulls back everything except the excluded cache validates both halves of the policy in one exercise.
The local cache completes the performance story: restic keeps an index cache under the user's cache directory, and a warm cache turns the backup run's snapshot-diff phase from a backend round-trip into a local lookup. The cache is safe to delete, the tool rebuilds it, and the one tuning knob on constrained machines limits its size through the standard environment variable, the small detail that makes the difference on the long-running backup host whose cache grew with the repository.
Migrating repositories and the two-repository posture
Backends change, the storage gets expensive, the provider gets retired, and restic's copy command moves a repository's full contents to a new home without decrypting anything:
$ restic -r s3:https://old.example.com/backups copy -r s3:https://new.example.com/backups
which streams every snapshot and chunk to the destination repository, and the copy composes with the source's retention policy, the migration window carrying the history the policy kept rather than the raw accumulation. The two-repository posture that the command enables is the backup architecture's honest answer to concentration risk: the primary repository on the primary backend, the second on a different backend or a different provider, both encrypted with the same client-side guarantee, and the copy running on a schedule or after every significant change. The second repository's restore test closes its own verification loop, because a mirror that has never been restored from is a mirror whose restore path is a theory.
The closing measurement
A backup system's report card fits on one line: the last snapshot's age, the repository's verified-clean status, the last restore test's date, and the repository's size against the curve the retention policy predicts. The restic setup this article built answers all four questions with one tool and one configuration surface, and the nightly run that posts clean answers to all four is the system doing the only job a backup has, sleeping quietly until the day it is the most important machine in the company, and working on that day because every one of its properties was tested while it was quiet.