Restic: Modern Backup for the Homelab
Restic is the modern choice for homelab backups: encrypted at rest, deduplicated across snapshots, incremental after the first backup, and fast. It backs up to local storage, SSH, S3, Backblaze B2, rclone destinations, and more. The repository format is open and doesn't lock you in.
Core Concepts
Repository: Where restic stores backups. A repository can be on a local disk, a network share, an S3 bucket, Backblaze B2, or any rclone-supported backend. The repository is always encrypted.
Snapshot: A point-in-time backup. Restic creates a snapshot per backup run. Snapshots share data — unchanged files are deduplicated, so the second backup doesn't copy files that haven't changed.
Encryption: Every repository has a password. Without the password, the data is useless. Store your password somewhere secure (separate from the backup).
Deduplication: Restic stores data in content-addressed chunks. Identical files or file regions across snapshots are stored once.
Installation
# Ubuntu/Debian
sudo apt install restic
# macOS
brew install restic
# Binaries
wget https://github.com/restic/restic/releases/latest/download/restic_linux_amd64.bz2
bzip2 -d restic_linux_amd64.bz2
chmod +x restic_linux_amd64
sudo mv restic_linux_amd64 /usr/local/bin/restic
Initialize a Repository
# Local repository
restic init --repo /backup/restic-repo
# Backblaze B2
export B2_ACCOUNT_ID=your-application-key-id
export B2_ACCOUNT_KEY=your-application-key
restic init --repo b2:your-bucket-name:/restic
# S3 (Wasabi, MinIO, AWS)
export AWS_ACCESS_KEY_ID=your-key
export AWS_SECRET_ACCESS_KEY=your-secret
restic init --repo s3:https://s3.wasabisys.com/your-bucket/restic
# Via rclone (supports 40+ backends)
restic init --repo rclone:remote:bucket/restic
You'll be prompted for a repository password. Use a long, random password (e.g., openssl rand -base64 32).
Like what you're reading? Subscribe to HomeLab Starter — free weekly guides in your inbox.
Basic Backup Operations
# Backup a directory
restic -r /backup/restic-repo backup /home/user /etc /var/www
# Backup with exclusions
restic -r /backup/restic-repo backup /home/user \
--exclude '/home/user/.cache' \
--exclude '*.tmp' \
--exclude '*/node_modules'
# List snapshots
restic -r /backup/restic-repo snapshots
# Browse snapshot contents
restic -r /backup/restic-repo ls latest
restic -r /backup/restic-repo ls 1234abcd # specific snapshot by ID
# Restore latest snapshot
restic -r /backup/restic-repo restore latest --target /restore/path
# Restore specific files from latest
restic -r /backup/restic-repo restore latest \
--target /restore \
--include '/home/user/documents'
Environment Variables for Automation
Store credentials in environment variables to avoid password prompts:
# ~/.config/restic/env
export RESTIC_REPOSITORY=b2:my-backup-bucket:/homelab
export RESTIC_PASSWORD=your-repository-password
export B2_ACCOUNT_ID=your-b2-key-id
export B2_ACCOUNT_KEY=your-b2-application-key
source ~/.config/restic/env
restic backup /important/data
For automated scripts, store in /etc/restic/env with appropriate permissions:
chmod 600 /etc/restic/env
Backup Script
#!/bin/bash
# /usr/local/bin/restic-backup.sh
set -euo pipefail
# Load credentials
source /etc/restic/env
# Paths to back up
BACKUP_PATHS=(
/home
/etc
/var/lib/docker/volumes
/srv
)
# Exclusions
EXCLUDES=(
--exclude '/home/*/.cache'
--exclude '*/node_modules'
--exclude '*/.git'
--exclude '*.tmp'
--exclude '*/tmp'
)
echo "$(date): Starting backup..."
restic backup "${BACKUP_PATHS[@]}" "${EXCLUDES[@]}" \
--tag "$(hostname)" \
--verbose
echo "$(date): Backup complete. Pruning old snapshots..."
# Retention policy: keep 7 daily, 4 weekly, 12 monthly, 1 yearly
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 12 \
--keep-yearly 1 \
--prune
echo "$(date): Prune complete."
Systemd Timer for Automation
Create a systemd service and timer for daily automated backups:
# /etc/systemd/system/restic-backup.service
[Unit]
Description=Restic backup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/restic-backup.sh
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run restic backup daily
[Timer]
OnCalendar=02:00
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable restic-backup.timer
sudo systemctl start restic-backup.timer
# Check timer status
systemctl list-timers restic-backup.timer
Verification: Actually Testing Your Backup
A backup you've never tested is a liability. Regularly verify:
# Check repository integrity (no data loss, no corruption)
restic -r /backup/restic-repo check
# Full verification (reads all data, slower but thorough)
restic -r /backup/restic-repo check --read-data
# Test restore to a temporary location
restic -r /backup/restic-repo restore latest \
--target /tmp/restore-test \
--include '/etc/nginx' \
--dry-run
Schedule a monthly restore test of at least one critical file to confirm the backup is actually usable.
Backblaze B2: Cost-Effective Cloud Backup
Backblaze B2 is the most cost-effective cloud storage for backups:
- $0.006/GB/month (vs $0.023/GB for S3)
- Free egress to Cloudflare workers
- 10GB free
- Designed for long-term storage
Setup:
- Create a Backblaze account at backblaze.com
- Create a bucket (private, no encryption override needed — restic encrypts everything)
- Create an Application Key with read/write access to the bucket
- Use key ID and application key in your restic environment
For 100GB of backups: ~$0.60/month.
Restic vs BorgBackup
Both are excellent; choose based on workflow:
| Restic | BorgBackup | |
|---|---|---|
| Backend support | S3, B2, SSH, rclone... | SSH/local only |
| Remote backup | Excellent | Requires BorgBase or SSH |
| Deduplication | ✓ | ✓ |
| Encryption | ✓ | ✓ |
| Mount snapshots | ✓ (FUSE) | ✓ (FUSE) |
| Speed | Fast | Slightly faster for some ops |
| Complexity | Low | Low |
Restic's broader backend support makes it the better choice for cloud backups. BorgBackup is excellent for SSH-based server-to-server replication.
The 3-2-1 Rule Applied
- 3 copies: live data + local backup + cloud backup
- 2 different media: your server's disks + external drive/NAS + B2 cloud
- 1 offsite copy: Backblaze B2
Implementation:
# Local backup (fast, for quick recovery)
restic -r /backup/local backup /data
# Cloud backup (off-site, for disaster recovery)
restic -r b2:my-bucket:/homelab backup /data
Run both in the same backup script. The incremental nature of restic means cloud uploads are fast after the initial backup.
