Modern backup management with restic

Page contents

Why a dedicated backup tool?

Backups processes come in all shapes and sizes, from simple bash scripts to cloning entire disks or entire tools managing the lifecycle. There is nothing wrong with either of these approaches, but using a fully integrated tool like restic combines the reliability and features of an enterprise grade backup system with the simplicity of just a few terminal commands, striking a nice balance for administrators that are looking for a robust backup tool that "just works" - without diving deep into their implementation.

In the case of restic, it provides several features out of the box. It runs natively on linux, windows and mac and supports many different providers to store backups, from local directories to sftp servers or even S3-compatible object storage. I fully encrypts backups by default and uses deduplication to prevent storing files unnecessarily, effectively turning all backups into incremental backups. Stored data is compressed at configurable levels and integrity checks are available out of the box to detect data corruption. Finally, backups can be mounted over the network to easily inspect their contents, and restoring a snapshot is also just a single command away.

restic is available in most default software repositories, for example on debian-like systems:

sudo apt install restic

Since restic works without requiring a server component, this single command is all you need.

Creating a repository

Before any backups can be made, restic needs to initialize a repository (aka storage location). This can be any number of different things, for example a local directory, remote sftp server or S3 object storage bucket.

You can supply the repository identifier from the command line using the -r / --repo flag and be prompted for an encryption password:

restic init --repo /path/to/repo
# or
restic -r sftp:user@host:/path/to/repo init

or load from the environment variables RESTIC_REPOSITORY and RESTIC_PASSWORD:

export RESTIC_REPOSITORY=/path/to/repo
export RESTIC_PASSWORD=supersecret
restic init

If you prefer using S3 storage, exporting your credentials with the default AWS environment variables is enough:

export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret
export RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket-name/folder
export RESTIC_PASSWORD=supersecret
restic init

Make sure to prepend the type of remote storage in front of the repository url, like the sftp: or s3: protocol prefixes in the examples above.

Be careful to remember your repository password or store it in a password manager! Encryption protects unauthorized eyes from accessing your backup data - including you if you lose the password!

Note: all further sections assume you have exposed the RESTIC_REPOSITORY environment variables or manually add your repository through -r / --repo to the commands.

Making backups

Once the repository is set up, making a backup is extremely easy:

restic backup /home/user/Documents

You can also include multiple directories in a backup:

restic backup /etc /home/user/Pictures /var/log

You can exclude single files with --exclude-file or entire directories with --exclude:

restic backup /home/user --exclude /home/user/Downloads --exclude-file /home/users/.bash_history

If you want restic to ignore mount points within the target backup directory, you can supply --one-filesystem:

restic backup /home/user --one-filesystem

Suppose an external drive were mounted at /home/user/mnt, that directory would not be included in the backup.

Finally, using --tag allows you to label backups so you can identify them easier later. A daily background backup command might look like this:

restic backup / --exclude /sys --exclude /proc --exclude /dev --one-file-system --tag daily

This backs up all disk contents, omitting other other mounted drives and system-specific directories. Backups are tagged "daily" so you can later distinguish them from manual backup snapshots.

This backup command needs to be scheduled by an external job manager like cron or systemd timers, since restic does not provide a daemon out of the box.

Inspecting backups

You can list all the snapshots (aka backups) in a repository with

restic snapshots

The output will list all known snapshots:

repository 46a48ae4 opened (repository version 2) successfully, password is correct
ID       Time                Host       Tags       Paths
---------------------------------------------------------------
46a4c248 2025-04-27 17:09:29 bookworm   daily      /var/log
34db447d 2025-04-27 17:09:37 bookworm   daily      /var/log
d1d7ca1c 2025-04-27 17:09:42 bookworm   manual     /var/log
---------------------------------------------------------------
3 snapshots

This is also where you can see the tag coming in handy, clearly separating the daily backups from the manual one in the list. To get a list of files inside a snapshot, note it's ID (first column in the list above) and run restic ls:

restic ls 46a4c248

The command will display all contained files, one per line:

snapshot 46a4c248 of [/var/log] filtered by [] at 2025-04-27 17:09:29.91681622 +0000 UTC):
/var
/var/log
/var/log/README
/var/log/apt
# --- snip ---

You can include permissions, filesize and more by passing the --long flag tot he command:

restic ls 46a4c248 --long

The output becomes significantly more detailed:

snapshot 46a4c248 of [/var/log] filtered by [] at 2025-04-27 17:09:29.91681622 +0000 UTC):
drwxr-xr-x    0    0     0 2024-09-05 04:33:28 /var
drwxr-xr-x    0    0     0 2025-04-27 17:01:29 /var/log
Lrwxrwxrwx    0    0     0 2024-09-05 04:33:48 /var/log/README -> ../../usr/share/doc/systemd/README.logs
drwxr-xr-x    0    0     0 2025-04-27 17:05:50 /var/log/apt

For even more visibility, you can mount an entire snapshot to a directory:

restic mount /mnt

This mounts the entire repository, including all snapshots, at /mnt. You can now manually access and filter the exact backup contents with common utilities like find. The mount command will hang until you stop it by pressing ctrl+c, which automatically unmounts the repository.

Note that mounted repositories are read-only, you cannot use this feature to remove backup contents. This also means you are safe from accidentally corrupting/damaging snapshots by mounting them.

Restoring a backup

Should the need arise to recover from a desaster scenario, restic maintains it's batteries-included approach. Find the ID of your desired backup and run

restic restore snapshot-ID --target /restore/target/path

If desired, you can also decide to restore only specific directories or files:

restic restore snapshot-ID --target /restore/target --include /home/user/Documents/file.txt

If you are not sure how long ago a file was deleted or damaged, you may be able to quickly filter through your most recent backups by comparing their changes, to find one that still contains the desired file:

restic diff 46a4c248 6c0f0765

a list of modified files and summary if changes is printed to the terminal:

comparing snapshot 46a4c248 to 6c0f0765:

M   /var/log/auth.log
M   /var/log/cron.log
M   /var/log/journal/a57af1475f474a5c9af886ce5a0c56a0/system.journal
+   /var/log/new_file!
M   /var/log/syslog

Files:          1 new,    0 removed,    4 changed
Dirs:           0 new,    0 removed
Others:         0 new,    0 removed
Data Blobs:    12 new,   11 removed
Tree Blobs:     5 new,    5 removed
 Added:  4.094 MiB
 Removed: 4.092 MiB

If this doesn't help or you have too many snapshots, you may need to mount the repository and search with system utilities instead.

Backup retention and maintenance

The built-in retention features allows operators to define how many old backups should be kept, and which can be deleted. This works by running restic forget with a list of rules which backups to keep; all others are considered removable. You can test your retention policy safely by using the --dry-run flag:

restic forget --dry-run --keep-within 24h --keep-daily 7 --keep-monthly 12

This policy would keep all backups from the last 24h, one per day for a week and one per month for a year. Removing the --dry-run flag would apply the retention policy, removing references to all snapshots not kept by the defined rules.

Be aware that forgetting snapshots only removes references to them and doesn't delete their data from storage. To do that you need to prune the repository:

restic prune

You can combine forget and prune in a single command as well:

restic forget --keep-daily 30 --prune

Now only the latest backup per day is kept for the last 30 days, all others are forgotten and permanently deleted from the repository.

Integrity checking

Ensuring data is still valid and safe to use is important for any backup solution; having corrupted backups is like having no backups at all. Restic uses internal checksums to ensure data corruption can be detected:

restic check

If any data corruption is found, the command will alert you to it. Data corruption cannot be fixed by restic itself, so it is important to keep safety copies of your backup repository on a separate disk (or better, a different device/service entirely).

If only the restic metadata is damaged, you may be able to fix it by regenerating it:

restic rebuild-index

This only works for limited scenarios, and does not replace a proper safety copy strategy.

More articles

Web security fuzzing with gobuster

Finding accidentally exposed files

Upgrading to the next linux debian release

From bookworm to trixie without the headache

Hardening sudo against privilege ecalation attacks

Preventing privilege escalation through privileged commands