Backup intermediate ⏱ 45 minutes

Restic: Modern Backup with REST Server

Fast, secure, efficient backups with Restic. Setup REST server and automate your backup strategy.

By homelabbing.io • 2025-12-17
#restic#backup#encryption#deduplication#rest-server

Restic is a modern backup program that is fast, secure, and efficient. It uses deduplication, encryption, and supports multiple storage backends. This guide will show you how to set up Restic with a REST server backend for a complete homelab backup solution.

Why Restic?

Restic offers several advantages for homelab backups:

  • Encryption by default: All data is encrypted before leaving your system
  • Deduplication: Saves storage space by only storing unique data blocks
  • Multiple backends: Supports local, SFTP, REST server, S3, B2, Azure, and more
  • Incremental backups: Only changed data is transferred
  • Verification: Built-in integrity checking and verification
  • Cross-platform: Works on Linux, macOS, Windows, and BSD
  • Fast and efficient: Written in Go for excellent performance
  • Simple restore: Easy to restore individual files or entire snapshots

Architecture Overview

In this guide, we’ll set up:

  1. Restic REST Server: A lightweight HTTP server for storing Restic repositories
  2. Restic Client: The backup client running on servers you want to back up
  3. Automated backups: Systemd timers or cron jobs for scheduled backups
  4. Monitoring: Scripts to verify backup success and send notifications

Part 1: Setting Up REST Server

The REST server provides an HTTP backend for Restic repositories. It’s lightweight, secure, and perfect for homelabs.

Create a directory structure for the REST server:

mkdir -p /opt/restic-server/{data,config}
cd /opt/restic-server

Create a docker-compose.yml:

version: '3.8'

services:
  restic-rest-server:
    image: restic/rest-server:latest
    container_name: restic-rest-server
    restart: unless-stopped
    ports:
      - "8000:8000"
    volumes:
      - ./data:/data
      - ./config:/config
    environment:
      - OPTIONS=--append-only --private-repos
    command:
      - --path
      - /data
      - --prometheus
      - --listen
      - :8000
    networks:
      - restic-net

networks:
  restic-net:
    driver: bridge

Start the server:

docker compose up -d

Option B: Native Installation

Install REST server on Debian/Ubuntu:

# Download latest release
RESTIC_REST_VERSION="0.12.1"
wget https://github.com/restic/rest-server/releases/download/v${RESTIC_REST_VERSION}/rest-server_${RESTIC_REST_VERSION}_linux_amd64.tar.gz

# Extract and install
tar -xzf rest-server_${RESTIC_REST_VERSION}_linux_amd64.tar.gz
sudo mv rest-server /usr/local/bin/
sudo chmod +x /usr/local/bin/rest-server

Create a systemd service:

sudo mkdir -p /var/lib/restic-server
sudo useradd -r -s /bin/false -d /var/lib/restic-server restic
sudo chown restic:restic /var/lib/restic-server

Create /etc/systemd/system/restic-rest-server.service:

[Unit]
Description=Restic REST Server
After=network.target

[Service]
Type=simple
User=restic
Group=restic
ExecStart=/usr/local/bin/rest-server 
    --path /var/lib/restic-server     --listen :8000     --append-only     --private-repos     --prometheus
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now restic-rest-server
sudo systemctl status restic-rest-server

Securing the REST Server

Create authentication credentials:

# For Docker setup
cd /opt/restic-server/config

# For native setup
cd /var/lib/restic-server

# Create .htpasswd file (requires apache2-utils)
sudo apt install apache2-utils -y
htpasswd -B -c .htpasswd backup-user

Update the Docker compose file to use authentication:

    volumes:
      - ./data:/data
      - ./config/.htpasswd:/data/.htpasswd:ro
    environment:
      - OPTIONS=--append-only --private-repos --htpasswd-file=/data/.htpasswd

For production use, put the REST server behind a reverse proxy with TLS:

Nginx configuration example:

server {
    listen 443 ssl http2;
    server_name backup.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/backup.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Important for large backups
        client_max_body_size 0;
        proxy_request_buffering off;
    }
}

Part 2: Installing Restic Client

Install Restic on the systems you want to back up.

Installation Methods

Debian/Ubuntu:

sudo apt update
sudo apt install restic -y

From Official Binaries (Latest Version):

RESTIC_VERSION="0.16.3"
wget https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_amd64.bz2
bzip2 -d restic_${RESTIC_VERSION}_linux_amd64.bz2
sudo mv restic_${RESTIC_VERSION}_linux_amd64 /usr/local/bin/restic
sudo chmod +x /usr/local/bin/restic

Verify installation:

restic version

Part 3: Initializing a Restic Repository

Create a repository on the REST server:

# Set environment variables
export RESTIC_REPOSITORY=rest:http://backup-user:YOUR-PASSWORD@YOUR-SERVER-IP:8000/hostname
export RESTIC_PASSWORD="your-encryption-password"

# Initialize the repository
restic init

For better security, store credentials in a file:

# Create password file
echo "your-encryption-password" > ~/.restic-password
chmod 600 ~/.restic-password

# Create repository configuration
cat > ~/.restic-env << 'EOF'
export RESTIC_REPOSITORY="rest:http://backup-user:YOUR-PASSWORD@YOUR-SERVER-IP:8000/hostname"
export RESTIC_PASSWORD_FILE="$HOME/.restic-password"
EOF

chmod 600 ~/.restic-env

Load credentials:

source ~/.restic-env
restic init

Part 4: Creating Backups

Basic Backup Commands

Backup a directory:

restic backup /home/user/documents

Backup multiple directories:

restic backup /home /etc /var/lib/docker/volumes

Backup with exclusions:

restic backup /home   --exclude="*.tmp"   --exclude="/home/*/.cache"   --exclude="/home/*/Downloads"   --exclude-file=/root/.restic-exclude

Create an exclude file /root/.restic-exclude:

*.log
*.tmp
*~
.DS_Store
.cache/
node_modules/
__pycache__/
*.pyc
.git/

Advanced Backup Options

Backup with tags:

restic backup /var/lib/docker/volumes --tag docker --tag production

Dry run (test without uploading):

restic backup /home --dry-run

Verbose output:

restic backup /home --verbose

Limit bandwidth:

restic backup /home --limit-upload 10240  # 10 MB/s

Part 5: Managing Snapshots

Listing Snapshots

View all snapshots:

restic snapshots

View snapshots for specific path:

restic snapshots --path /home

View snapshots with specific tag:

restic snapshots --tag docker

Snapshot Information

Get detailed snapshot info:

restic snapshots --json | jq '.'

Show files in a snapshot:

restic ls SNAPSHOT-ID

Compare two snapshots:

restic diff SNAPSHOT-ID1 SNAPSHOT-ID2

Part 6: Restoring Data

Restore Entire Snapshot

Restore to original location:

restic restore SNAPSHOT-ID --target /

Restore to different location:

restic restore SNAPSHOT-ID --target /tmp/restore

Restore latest snapshot:

restic restore latest --target /tmp/restore

Restore Specific Files

Restore specific path from latest snapshot:

restic restore latest --target /tmp/restore --path /home/user/important.txt

Restore with include pattern:

restic restore latest --target /tmp/restore --include "*.conf"

Mount Repository for Browse and Restore

Mount the repository as a filesystem:

mkdir /mnt/restic
restic mount /mnt/restic

Now you can browse snapshots:

ls /mnt/restic/snapshots/
cd /mnt/restic/snapshots/latest/home/user/
cp important-file.txt /home/user/

Unmount when done:

umount /mnt/restic

Part 7: Retention Policies and Pruning

Forget Old Snapshots

Restic uses a forget command to mark snapshots for deletion:

# Keep last 7 daily, 4 weekly, 12 monthly snapshots
restic forget   --keep-daily 7   --keep-weekly 4   --keep-monthly 12   --keep-yearly 3

More retention options:

restic forget   --keep-last 5   --keep-hourly 24   --keep-daily 7   --keep-weekly 4   --keep-monthly 12   --keep-yearly 3   --keep-tag important

Prune to Reclaim Space

Forgetting snapshots doesn’t free space immediately. Run prune:

restic prune

Combined forget and prune:

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

Part 8: Repository Maintenance

Check Repository Integrity

Basic check:

restic check

Read all data (thorough check):

restic check --read-data

Check subset of data (faster):

restic check --read-data-subset=10%

Rebuild Index

If the repository index is corrupted:

restic rebuild-index

Repository Statistics

View repository stats:

restic stats

Stats in different modes:

restic stats --mode raw-data
restic stats --mode restore-size
restic stats --mode files-by-contents

Part 9: Automation with Systemd

Create a systemd service and timer for automated backups.

Create Backup Script

Create /usr/local/bin/restic-backup.sh:

#!/bin/bash

# Exit on error
set -e

# Load environment
source /root/.restic-env

# Set log file
LOGFILE="/var/log/restic-backup.log"

# Backup function
backup() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Starting backup" >> "$LOGFILE"

    restic backup         /home         /etc         /var/lib/docker/volumes         /opt         --exclude-file=/root/.restic-exclude         --tag automated         >> "$LOGFILE" 2>&1

    echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup completed" >> "$LOGFILE"
}

# Forget old snapshots
forget() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Forgetting old snapshots" >> "$LOGFILE"

    restic forget         --keep-daily 7         --keep-weekly 4         --keep-monthly 12         --keep-yearly 3         --prune         >> "$LOGFILE" 2>&1

    echo "$(date '+%Y-%m-%d %H:%M:%S') - Forget completed" >> "$LOGFILE"
}

# Check repository (weekly)
check() {
    if [ "$(date +%u)" -eq 7 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Checking repository" >> "$LOGFILE"
        restic check >> "$LOGFILE" 2>&1
        echo "$(date '+%Y-%m-%d %H:%M:%S') - Check completed" >> "$LOGFILE"
    fi
}

# Run backup
backup

# Run forget on Sundays
if [ "$(date +%u)" -eq 7 ]; then
    forget
fi

# Run check
check

echo "$(date '+%Y-%m-%d %H:%M:%S') - All tasks completed" >> "$LOGFILE"

Make it executable:

sudo chmod +x /usr/local/bin/restic-backup.sh

Create Systemd Service

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

[Unit]
Description=Restic Backup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh
User=root
Group=root
Nice=19
IOSchedulingClass=idle

Create Systemd Timer

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

[Unit]
Description=Restic Backup Timer
Requires=restic-backup.service

[Timer]
OnCalendar=daily
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=30min

[Install]
WantedBy=timers.target

Enable and start the timer:

sudo systemctl daemon-reload
sudo systemctl enable restic-backup.timer
sudo systemctl start restic-backup.timer
sudo systemctl list-timers

Test the backup manually:

sudo systemctl start restic-backup.service
journalctl -u restic-backup.service -f

Part 10: Cloud Storage Integration

Backblaze B2

Restic natively supports Backblaze B2:

# Install B2 CLI (optional, for management)
sudo pip3 install b2

# Set B2 credentials
export B2_ACCOUNT_ID="your-account-id"
export B2_ACCOUNT_KEY="your-application-key"
export RESTIC_REPOSITORY="b2:bucket-name:path/to/repo"
export RESTIC_PASSWORD="your-encryption-password"

# Initialize repository
restic init

Amazon S3

export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export RESTIC_REPOSITORY="s3:s3.amazonaws.com/bucket-name/path"
export RESTIC_PASSWORD="your-encryption-password"

restic init

Wasabi S3-Compatible Storage

export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export RESTIC_REPOSITORY="s3:s3.us-west-1.wasabisys.com/bucket-name/path"
export RESTIC_PASSWORD="your-encryption-password"

restic init

SFTP Backend

export RESTIC_REPOSITORY="sftp:user@host:/backup/path"
export RESTIC_PASSWORD="your-encryption-password"

restic init

Part 11: Monitoring and Notifications

Healthchecks.io Integration

Add health check pings to your backup script:

#!/bin/bash

HEALTHCHECK_URL="https://hc-ping.com/your-uuid-here"

# Start signal
curl -fsS -m 10 --retry 5 "$HEALTHCHECK_URL/start" > /dev/null

# Your backup commands here
source /root/.restic-env
restic backup /home /etc /var/lib/docker/volumes

# Success or failure
if [ $? -eq 0 ]; then
    curl -fsS -m 10 --retry 5 "$HEALTHCHECK_URL" > /dev/null
else
    curl -fsS -m 10 --retry 5 "$HEALTHCHECK_URL/fail" > /dev/null
fi

Email Notifications

Install mailutils:

sudo apt install mailutils -y

Enhanced backup script with email:

#!/bin/bash

EMAIL="[email protected]"
HOSTNAME=$(hostname)

# Run backup
if /usr/local/bin/restic-backup.sh; then
    echo "Backup completed successfully on $HOSTNAME at $(date)" |         mail -s "✓ Backup Success: $HOSTNAME" "$EMAIL"
else
    echo "Backup FAILED on $HOSTNAME at $(date). Check logs at /var/log/restic-backup.log" |         mail -s "✗ Backup FAILED: $HOSTNAME" "$EMAIL"
fi

Prometheus Metrics

The REST server provides Prometheus metrics at /metrics. Configure Prometheus to scrape:

scrape_configs:
  - job_name: 'restic-rest-server'
    static_configs:
      - targets: ['YOUR-SERVER-IP:8000']

Part 12: Security Best Practices

Encryption

  1. Use strong repository passwords: Minimum 20 characters, random
  2. Separate encryption from REST auth: Repository password encrypts data, REST password controls access
  3. Store passwords securely: Use password managers, not plain text files

Access Control

  1. Use append-only mode: Prevents attackers from deleting backups
  2. Separate repositories per host: Limits blast radius of compromise
  3. Use htpasswd authentication: Different credentials per client
  4. Enable private repos mode: Prevents repository enumeration

Network Security

  1. Use TLS/HTTPS: Always encrypt data in transit
  2. Firewall REST server: Only allow connections from backup clients
  3. Use VPN or Tailscale: Additional network layer security
  4. Regular security updates: Keep Restic and REST server updated

Backup Verification

Create a verification script /usr/local/bin/restic-verify.sh:

#!/bin/bash

source /root/.restic-env

# Check repository integrity
echo "Checking repository integrity..."
restic check

# Verify latest snapshot can be restored
echo "Testing restore of latest snapshot..."
mkdir -p /tmp/restic-test
restic restore latest --target /tmp/restic-test --path /etc/hostname

if [ -f /tmp/restic-test/etc/hostname ]; then
    echo "✓ Restore test successful"
    rm -rf /tmp/restic-test
    exit 0
else
    echo "✗ Restore test failed!"
    exit 1
fi

Run monthly with cron:

0 3 1 * * /usr/local/bin/restic-verify.sh >> /var/log/restic-verify.log 2>&1

Part 13: Multi-Repository Strategy

For critical data, use multiple repositories with different backends:

# Local repository
export RESTIC_REPOSITORY_LOCAL="rest:http://user:pass@local-nas:8000/hostname"

# Cloud repository
export RESTIC_REPOSITORY_CLOUD="b2:backup-bucket:hostname"

# Backup to both
restic -r $RESTIC_REPOSITORY_LOCAL backup /home /etc
restic -r $RESTIC_REPOSITORY_CLOUD backup /home /etc

Automated multi-repo backup script:

#!/bin/bash

REPOS=(
    "rest:http://user:pass@nas:8000/hostname"
    "sftp:user@offsite:/backups/hostname"
)

for repo in "${REPOS[@]}"; do
    echo "Backing up to $repo"
    RESTIC_REPOSITORY="$repo" RESTIC_PASSWORD_FILE=/root/.restic-password         restic backup /home /etc /var/lib/docker/volumes
done

Part 14: Troubleshooting

Common Issues

Lock conflicts:

# List locks
restic list locks

# Remove stale lock
restic unlock

Slow backups:

# Check statistics
restic stats --mode raw-data

# Limit concurrent connections
restic backup /home --limit-upload 5120

Repository corruption:

# Check and repair
restic check --read-data
restic rebuild-index
restic prune

Out of space:

# Check repository size
restic stats

# Aggressive pruning
restic forget --keep-last 3 --prune

Debugging

Enable verbose output:

restic backup /home --verbose=2

Check REST server logs:

# Docker
docker logs restic-rest-server

# Native
journalctl -u restic-rest-server -f

Conclusion

You now have a complete, secure backup solution using Restic and REST server. This setup provides:

  • Encrypted, deduplicated backups
  • Flexible retention policies
  • Multiple backend support (local, cloud, SFTP)
  • Automated scheduled backups
  • Monitoring and notifications
  • Easy restore procedures

Next Steps

  1. Test your restores regularly: Backups are useless if you can’t restore
  2. Monitor backup success: Set up alerts for failed backups
  3. Document your setup: Keep notes on your configuration
  4. Plan for disasters: Have a documented recovery procedure
  5. Keep multiple copies: Follow the 3-2-1 backup rule

Additional Resources

Remember: The best backup is the one you test. Schedule regular restore tests to ensure your backup strategy works when you need it most.