| home.excludes | feat: externalize includes and excludes | |
| home.includes | feat: externalize includes and excludes | |
| install | feat: default to include stacks in backup with opt out | |
| README.md | Include a list of installed packages into the backup | |
| restic-backup | Include a list of installed packages into the backup | |
| restic-helper | Initial commit. | |
| sys.excludes | Include a list of installed packages into the backup | |
| sys.includes | Include a list of installed packages into the backup | |
Quick Start
Clone the repository, then run the installer as root from the repo directory:
sudo ./install
The installer will prompt for your storage box hostname, username, SSH port, and an optional healthchecks.io URL, then handle every setup step automatically.
For day-to-day operations use restic-helper:
restic-helper run # trigger a backup now
restic-helper status # show timer and service status
restic-helper logs # show recent backup logs
restic-helper snapshots # list all snapshots
restic-helper restore latest --target /tmp/restore # restore latest snapshot
This tutorial will guide you through setting up automated, encrypted backups using restic to a Hetzner Storage Box on Debian 13.
Prerequisites
- Debian 13 server
- Hetzner Storage Box with SSH/SFTP access
- Root access to the server
- Account at https://healthchecks.io (optional)
1. Install Required Packages
apt update
apt install restic openssh-client curl
2. Generate SSH Key for Restic
Create a dedicated SSH key pair for restic backups:
ssh-keygen -t ed25519 -f /root/.ssh/id_restic -C "restic-backup"
When prompted, leave the passphrase empty (press Enter twice).
Convert the public key to RFC4716 format (required by Hetzner for port 22):
ssh-keygen -e -f /root/.ssh/id_restic.pub > /root/.ssh/id_restic_rfc.pub
3. Configure SSH for Storage Box
Create SSH config entry for easier access:
cat > /root/.ssh/config << 'EOF'
Host storagebox
HostName u000000-sub0.your-storagebox.de
User u000000-sub0
Port 23
IdentityFile /root/.ssh/id_restic
IdentitiesOnly yes
Compression yes
EOF
Replace u000000-sub0 with your actual Storage Box username and u000000-sub0.your-storagebox.de with your Storage Box hostname.
Set correct permissions:
chmod 600 /root/.ssh/config
4. Upload SSH Key to Storage Box
Upload your SSH public key to the Storage Box:
ssh-copy-id -p 23 -s -i /root/.ssh/id_restic u000000-sub0@u000000-sub0.your-storagebox.de
Replace the username and hostname with your actual values.
Test the connection:
ssh storagebox
You should connect without being asked for a password. Type exit to disconnect.
5. Configure Restic Repository
Create the repository configuration file:
echo "sftp:storagebox:/home/" > /root/.restic-repo
chmod 600 /root/.restic-repo
6. Set Up Systemd Credentials
Create a secure directory for credentials:
mkdir -p /etc/credstore.encrypted
chmod 700 /etc/credstore.encrypted
Generate a strong password and encrypt it with systemd-creds:
openssl rand -base64 32 | \
tee >(systemd-creds encrypt --name=restic-password - \
/etc/credstore.encrypted/restic-password)
Set correct permissions:
chmod 600 /etc/credstore.encrypted/restic-password
7. Initialize Restic Repository
Initialize the restic repository on the Storage Box:
export RESTIC_REPOSITORY=$(cat /root/.restic-repo)
restic init --password-command "systemd-creds decrypt /etc/credstore.encrypted/restic-password -"
You should see a message confirming the repository was created.
8. Create Backup Configuration Directory
Create the directory for backup configuration files and install the defaults:
mkdir -p /etc/backup
cp sys.includes /etc/backup/sys.includes
cp sys.excludes /etc/backup/sys.excludes
cp home.includes /etc/backup/home.includes
cp home.excludes /etc/backup/home.excludes
The .includes files list paths to back up (one per line). The .excludes files list paths or patterns to skip. Edit these to customise what gets backed up without touching the script itself.
Optionally, configure healthchecks.io monitoring by saving your ping URL:
echo "https://hc-ping.com/your-uuid-here" > /etc/backup/healthcheck.url
9. Install Backup Script
cp restic-backup /usr/local/sbin/restic-backup
chmod 750 /usr/local/sbin/restic-backup
The script backs up:
/etc,/root,/srv,/usr/local,/var/spool, plus the distro package database (/var/lib/dpkgon Debian/Ubuntu,/var/lib/rpmon Fedora) — taggedsys/home(or paths in/etc/backup/home.includes) with exclusions from/etc/backup/home.excludes— taggedhome- Each Docker stack that has a
.backup.conffile in its directory — tagged with the stack name
Per-stack backup behaviour is controlled by .backup.conf files in each stack directory under /srv/stacks/. See Per-Stack Configuration below.
10. Install Restic Helper Script
cp restic-helper /usr/local/sbin/restic-helper
chmod 750 /usr/local/sbin/restic-helper
This script uses systemd-run to inject the encrypted credentials, so it works correctly both interactively and from scripts.
11. Create Systemd Service
Create the systemd service unit:
cat > /etc/systemd/system/restic-backup.service << 'EOF'
[Unit]
Description=Backup to Hetzner Storage Box
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=root
Environment=HOME=/root
LoadCredentialEncrypted=restic-password:/etc/credstore.encrypted/restic-password
ExecStart=/usr/local/sbin/restic-backup
# Security Hardening
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/srv /var/lib/docker /var/log /var/backups
# Timeout (important for large backups)
TimeoutStartSec=3h
# Don't restart on failure
Restart=no
EOF
12. Create Systemd Timer
Create the timer for automated daily backups:
cat > /etc/systemd/system/restic-backup.timer << 'EOF'
[Unit]
Description=Daily backup to Hetzner Storage Box
Requires=restic-backup.service
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
# Random delay of 0-30 minutes
RandomizedDelaySec=30min
[Install]
WantedBy=timers.target
EOF
13. Enable and Start the Timer
Reload systemd, enable and start the timer:
systemctl daemon-reload
systemctl enable restic-backup.timer
systemctl start restic-backup.timer
Check the timer status:
systemctl status restic-backup.timer
systemctl list-timers restic-backup.timer
14. Test the Backup
Run a manual backup to test the setup:
systemctl start restic-backup.service
Monitor the backup progress:
journalctl -fu restic-backup.service
15. Verify Backups
List all snapshots:
/usr/local/sbin/restic-helper snapshots
List snapshots with a specific tag:
/usr/local/sbin/restic-helper snapshots --tag immich
Browse the latest snapshot:
/usr/local/sbin/restic-helper ls latest
Search for specific files:
/usr/local/sbin/restic-helper find docker-compose.yml
16. Restore from Backup
Restore the latest snapshot to a target directory:
/usr/local/sbin/restic-helper restore latest --target /tmp/restore
Restore a specific snapshot:
/usr/local/sbin/restic-helper restore <snapshot-id> --target /tmp/restore
Restore specific paths only:
/usr/local/sbin/restic-helper restore latest --tag immich --target /tmp/restore --include /srv/stacks/immich
Per-Stack Configuration
Every directory under /srv/stacks/ is backed up automatically. Place a .backup.conf file in a stack directory to opt out or customise behaviour. Without a .backup.conf the stack is backed up live with no extra paths or excludes.
mode=live # back up while stack is running (default)
mode=stop # stop the stack before backup, restart it after
mode=skip # exclude this stack from backups entirely
extra_paths=/var/lib/docker/volumes/mystack_* # additional paths to include
excludes=/srv/stacks/mystack/large-cache-dir # space-separated paths to exclude
Example — opt a stack out of backups:
mode=skip
Example — stop the stack for a consistent snapshot and include its volumes:
mode=stop
extra_paths=/var/lib/docker/volumes/mystack_db_data
Maintenance
Check Repository Integrity
/usr/local/sbin/restic-helper check
View Backup Logs
restic-helper logs # recent logs
restic-helper follow # follow live
Adjust Backup Retention
Edit the retention policy in /usr/local/sbin/restic-backup:
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--keep-yearly 2 \
--prune
restic-helper reference
| Command | Description |
|---|---|
restic-helper run |
Trigger a backup now via systemd |
restic-helper status |
Show timer and service status |
restic-helper logs |
Show recent backup logs |
restic-helper follow |
Follow backup logs live |
restic-helper snapshots [--tag TAG] |
List snapshots |
restic-helper ls latest |
Browse the latest snapshot |
restic-helper find <file> |
Find a file across snapshots |
restic-helper check |
Check repository integrity |
restic-helper restore <snapshot> --target <dir> |
Restore a snapshot |