Back up a directory with restic
Back up a directory to a local disk or S3-compatible storage with restic: init a repo, exclude files, restore, prune old snapshots and schedule runs.
Updated
in short
Create a repository with restic init, keep the password in a file referenced by RESTIC_PASSWORD_FILE, run restic backup on a schedule, and trim old snapshots with restic forget --prune.
restic stores encrypted, deduplicated snapshots in a repository. The repository can be a local directory, an SFTP server, or an S3-compatible bucket, and every command takes the same flags whichever backend you use.
This guide backs up one directory, restores from it, sets a retention policy, verifies the repository, and runs the whole thing from cron or a systemd timer.
Tools used
Before you start
- Linux, macOS, BSD or Windows
- A target: a mounted disk, or an S3-compatible bucket with an access key and secret key
- Somewhere safe to keep a copy of the repository password, such as a password manager
Steps
Step 1: Install restic
Install it from your package manager. Distribution packages can lag behind; the official binaries from the GitHub releases page can update themselves with
restic self-update.sh# macOS or Linux with Homebrew brew install restic # Debian / Ubuntu sudo apt-get install restic # Fedora sudo dnf install restic # Arch Linux sudo pacman -S resticshrestic versionStep 2: Store the repository password in a file
Every restic command needs the repository password. Instead of typing it, put it in a file readable only by you and point
RESTIC_PASSWORD_FILEat it.RESTIC_REPOSITORYsets the repository so you can drop-rfrom every command.If you lose this password, the data in the repository cannot be recovered. Keep a second copy somewhere other than the machine you are backing up.
shmkdir -p ~/.config/restic head -c 32 /dev/urandom | base64 > ~/.config/restic/password chmod 600 ~/.config/restic/passwordshexport RESTIC_PASSWORD_FILE=~/.config/restic/password # Local disk export RESTIC_REPOSITORY=/mnt/backup/restic-repo # Or an S3-compatible bucket export RESTIC_REPOSITORY=s3:https://s3.example.com/my-bucket/restic export AWS_ACCESS_KEY_ID=<your-access-key-id> export AWS_SECRET_ACCESS_KEY=<your-secret-access-key>Step 3: Initialize the repository
restic initcreates the repository structure and encryption keys atRESTIC_REPOSITORY. Run it once per repository. For Amazon S3 itself, use the region endpoint, for examples3:s3.us-east-1.amazonaws.com/bucket_name. Other S3-compatible services takes3:https://server:port/bucket_name; if the service needs a region, setAWS_DEFAULT_REGION.shrestic initoutputcreated restic repository 085b3c76b9 at /mnt/backup/restic-repo Please note that knowledge of your password is required to access the repository. Losing your password means that your data is irrecoverably lost.
Step 4: Run a backup with excludes
--excludetakes a pattern and can be repeated.--exclude-filereads one pattern per line, with#comments.--exclude-cachesskips the contents of any directory that contains aCACHEDIR.TAGfile. Patterns are matched against full paths, must match whole path components, and support**for any number of directories.~is not expanded inside an exclude file; use$HOME.Add
--dry-run -vvfirst to see what would be stored without writing anything.shcat > ~/.config/restic/excludes.txt <<'EOF' # build output and dependencies node_modules $HOME/projects/**/target *.tmp EOFshrestic backup ~/projects \ --exclude-file ~/.config/restic/excludes.txt \ --exclude-caches \ --tag dailyStep 5: List snapshots and restore
restic snapshotslists every snapshot with its ID, time, host, tags and paths.restic restoretakes a snapshot ID orlatestand writes files under--target.--includerestricts the restore to matching paths. Restore into an empty directory first, check the result, then copy files back.shrestic snapshotssh# whole snapshot restic restore latest --target /tmp/restore # a single directory from a specific snapshot restic restore 79766175 --target /tmp/restore --include /home/me/projects/sitesh# find where a file lives in a snapshot restic ls latest | grep report.odtStep 6: Apply a retention policy with
forget --pruneforgetremoves snapshots that fall outside the policy;--prunethen deletes the data no remaining snapshot references. Without--prunethe repository does not shrink. The policy is applied per group of host and paths, so one machine's policy does not delete another's snapshots. Run with--dry-runfirst to see which snapshots would go.shrestic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --dry-runshrestic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --pruneStep 7: Check the repository
restic checkverifies the repository structure. It does not read the stored file contents unless you ask:--read-datareads everything, and--read-data-subsetreads a part, either a fraction like1/5or a random percentage like5%. Reading a small random subset after each backup spreads the cost over time.shrestic checkshrestic check --read-data-subset=5%Step 8: Schedule it with cron or a systemd timer
Put the variables in one file, without
export, so systemd and a shell script can both read it. Make it readable only by its owner, since it holds credentials.For cron, wrap the commands in a script that loads the file with
set -a, then add a crontab entry. For systemd, use a oneshot service plus a timer;Persistent=trueruns a missed backup at the next boot.sh# /etc/restic/env (chmod 600) RESTIC_REPOSITORY=s3:https://s3.example.com/my-bucket/restic RESTIC_PASSWORD_FILE=/etc/restic/password AWS_ACCESS_KEY_ID=<your-access-key-id> AWS_SECRET_ACCESS_KEY=<your-secret-access-key>sh#!/bin/sh # /usr/local/bin/restic-backup set -e set -a; . /etc/restic/env; set +a restic backup /home/me/projects --exclude-file /etc/restic/excludes.txt --exclude-caches restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --prune restic check --read-data-subset=5%sh# crontab -e: every night at 03:00 0 3 * * * /usr/local/bin/restic-backup >> /var/log/restic-backup.log 2>&1ini# /etc/systemd/system/restic-backup.service [Unit] Description=restic backup Wants=network-online.target After=network-online.target [Service] Type=oneshot EnvironmentFile=/etc/restic/env ExecStart=/usr/bin/restic backup /home/me/projects --exclude-file /etc/restic/excludes.txt --exclude-caches ExecStartPost=/usr/bin/restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 --pruneini# /etc/systemd/system/restic-backup.timer [Unit] Description=Nightly restic backup [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true RandomizedDelaySec=15m [Install] WantedBy=timers.targetshsudo systemctl daemon-reload sudo systemctl enable --now restic-backup.timer systemctl list-timers restic-backup.timer journalctl -u restic-backup.service
Troubleshooting
wrong password or no key found: the password file does not match this repository. CheckRESTIC_PASSWORD_FILEandRESTIC_REPOSITORY.repository is already locked: another restic process is running, or one crashed. If none is running,restic unlockremoves stale locks.- Exit code 3 from
backup: some source files could not be read. A snapshot was still saved; read the log for the paths. - Repository size does not drop after
forget: you ran it without--prune. Runrestic prune. - Cron job fails but the manual run works: cron has a minimal environment. Load the variables in the script and use full paths.
- systemd: the binary path differs by install method. Use the output of
command -v resticinExecStart.
Tips
--password-command(orRESTIC_PASSWORD_COMMAND) reads the password from a command, such as a password manager CLI.restic backup --tagadds tags;restic forget --keep-tagkeeps tagged snapshots regardless of the other rules.- Since restic 0.17, exit codes 10, 11 and 12 mean missing repository, lock failure and wrong password.
FAQ
- Is the data encrypted on S3?
- Yes. restic encrypts file contents and metadata before upload, so the storage provider only sees encrypted blobs. The key is protected by your repository password.
- How often should I run prune?
- `forget --prune` rewrites part of the repository and takes longer than a backup. Running it daily is fine for small repositories; for large ones, back up daily and prune weekly.
- Can two machines share one repository?
- Yes. Snapshots record the host name, and retention policies are applied per host and path by default, so each machine's snapshots are handled separately.