Backups with Restic on AWS: Setup, Restore, and Retention

Backing up is easy to put off until the one day you need it. This guide shows a simple, reliable way to push encrypted backups to AWS S3 with restic, how to restore files quickly, and how to keep retention predictable so storage and bills do not creep up. The approach works on a Raspberry Pi or a full server and needs no database or extra services.

Why restic on S3

  • Encryption by default. Backups are encrypted client side with your password before they leave the machine.
  • Incremental forever. Restic stores deduplicated snapshots so daily runs are fast.
  • Portable. A few environment variables and a single binary are enough to use it anywhere.
  • No vendor lock. You can point the same setup at any S3 compatible storage in the future.

Prerequisites

  • An S3 bucket in your preferred region.
  • An IAM user with access only to that bucket.
  • The restic binary on your machine.

Install restic on Debian or Ubuntu:

1
2
3
sudo apt update
sudo apt install restic
restic version

Minimal IAM policy

Create an IAM user and attach a policy that limits access to the one bucket and its objects. Replace YOUR-BUCKET and YOUR-REGION.

1
2
3
4
5
6
7
{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::YOUR-BUCKET" },
    { "Effect": "Allow", "Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:AbortMultipartUpload","s3:ListBucketMultipartUploads"], "Resource": "arn:aws:s3:::YOUR-BUCKET/*" }
  ]
}

Create access keys for that user and store them as secrets on the host.

Environment setup

Restic reads credentials and the repository from environment variables. Add these to /etc/restic.env with root only permissions.

1
2
sudo install -m 600 /dev/null /etc/restic.env
sudo nano /etc/restic.env

Paste:

1
2
3
4
5
6
7
8
# AWS
AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION=YOUR-REGION

# Restic
RESTIC_PASSWORD=make-this-strong-and-unique
RESTIC_REPOSITORY=s3:s3.amazonaws.com/YOUR-BUCKET

Load the file when you run restic:

1
2
3
set -a
. /etc/restic.env
set +a

Tip: if you use a non AWS provider or a custom endpoint, change RESTIC_REPOSITORY to s3:https://YOUR-ENDPOINT/YOUR-BUCKET.

Initialize the repository

Run this once to create the repository structure in S3:

1
restic init

If it succeeds, the bucket now contains a config object and the repo is ready.

First backup

Decide what to include and what to skip. Create exclude rules in /etc/restic-excludes.txt:

*.tmp
*.cache
node_modules
venv
.DS_Store
lost+found

Run a test backup with verbose output:

1
restic backup /home /etc --exclude-file=/etc/restic-excludes.txt --tag $(hostname)-daily

You can back up any path: home directories, config folders, and data mounts. Use tags to mark the snapshot with a host or schedule.

List snapshots:

1
restic snapshots

Verify integrity:

1
restic check

Schedule backups

Use a simple cron job, or systemd timers if you prefer.

Cron example (daily at 01:30):

1
2
3
4
5
6
sudo crontab -e
# environment
SHELL=/bin/bash
BASH_ENV=/etc/restic.env
# job
30 1 * * * set -a; . /etc/restic.env; set +a; restic backup /home /etc --exclude-file=/etc/restic-excludes.txt --tag $(hostname)-daily >> /var/log/restic.log 2>&1

Systemd timer (daily at 01:30):

Create /etc/systemd/system/restic-backup.service:

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

[Service]
Type=oneshot
EnvironmentFile=/etc/restic.env
ExecStart=/usr/bin/restic backup /home /etc --exclude-file=/etc/restic-excludes.txt --tag %H-daily

Create /etc/systemd/system/restic-backup.timer:

1
2
3
4
5
6
7
8
9
[Unit]
Description=Run restic backup daily

[Timer]
OnCalendar=*-*-* 01:30:00
Persistent=true

[Install]
WantedBy=timers.target

Enable:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
systemctl list-timers | grep restic

Retention policy

Restic keeps everything until you tell it what to forget. A common policy is:

  • keep the last 7 daily
  • keep 4 weekly
  • keep 12 monthly

Apply it with pruning to remove unused data:

1
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune --tag $(hostname)-daily

Run this weekly from cron or add a second timer, for example every Sunday at 02:15:

1
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune

You can keep different policies by tag. For example, weekly photos could use a longer window:

1
restic forget --tag photos --keep-weekly 12 --keep-monthly 24 --prune

Check space usage before and after pruning:

1
restic stats

Restoring data

List snapshots and pick the one you want:

1
restic snapshots

Restore a single file or folder to a safe location:

1
2
mkdir -p ~/restores/test
restic restore latest --include /home/user/Documents/todo.txt --target ~/restores/test

Restore a full path from a specific snapshot ID:

1
restic restore 1a2b3c4d --target /mnt/restore

Search within snapshots:

1
restic ls latest /etc | grep nginx

Diff two snapshots to see what changed:

1
restic diff 1a2b3c4d 5e6f7a8b

When you finish a restore, move files back into place using rsync so permissions and timestamps survive:

1
sudo rsync -aHAXv /mnt/restore/home/user/ /home/user/

Cost control tips

  • Lifecycle rules. In the S3 console, set a rule to transition old objects to Glacier Instant Retrieval after 30 days if restores are rare. Do not use Deep Archive unless you are comfortable with hours of retrieval delay.
  • One bucket per policy. If different data sets need different lifecycle rules, use separate buckets.
  • Forget first, then prune. The forget --prune combo reclaims space and keeps the repo tidy.
  • Avoid latest on critical restores. Name a snapshot ID to avoid surprises if a backup runs mid process.

Disaster recovery drill

Once a quarter, simulate a fresh machine:

1
2
3
4
5
6
7
8
sudo apt update && sudo apt install restic
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=...
export RESTIC_PASSWORD=...
export RESTIC_REPOSITORY=s3:s3.amazonaws.com/YOUR-BUCKET
restic snapshots
restic restore latest --target /tmp/restore-test

Check that the data you expect is there. A five minute drill buys peace of mind.

Security notes

  • The RESTIC_PASSWORD is the only way to decrypt. Store it in a password manager and print a sealed copy if needed.
  • Restrict the IAM user to only your bucket. Avoid wildcards across accounts.
  • Rotate access keys periodically and test after rotation.
  • Use restic key list and restic key add if you need a second password for a trusted operator.

Quick commands recap

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# init
restic init

# backup with excludes and tag
restic backup /home /etc --exclude-file=/etc/restic-excludes.txt --tag $(hostname)-daily

# verify
restic check

# list snapshots
restic snapshots

# restore file
restic restore latest --include /home/user/file.txt --target ~/restores/test

# retention
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune

That is a full loop: encrypted backups to S3, simple restores, and a retention policy you can explain. It is small, dependable, and easy to move to another S3 compatible provider later if needed.

Thanks for reading. If you have a clean retention pattern for mixed daily and weekly jobs, share it so others can try it too.


↤ Previous Post