Automating Backups for Your Home Server: Complete Guide

You’ve spent hours setting up your perfect home server with Docker containers, configuration files, and precious data. But what happens when a drive fails, ransomware strikes, or you accidentally delete something critical?

Without automated backups, you’re one mistake away from losing everything.

This guide will show you how to implement rock-solid automated backups for your home server using proven tools and the industry-standard 3-2-1 backup rule.

The 3-2-1 Backup Rule

Before diving into tools, understand this fundamental principle:

  • 3 copies of your data (1 primary + 2 backups)
  • 2 different storage types (e.g., local disk + cloud)
  • 1 copy offsite (cloud storage or remote location)

This strategy protects against hardware failure, accidents, theft, and disasters.

What to Back Up

Not all data is equal. Prioritize:

Critical (Must Back Up)

  • Docker volumes - Database files, application data
  • Configuration files - Docker Compose files, .env files, nginx configs
  • User data - Photos, documents, personal files
  • System configs - SSH keys, network settings (if custom)

Optional (Nice to Have)

  • Docker images - Can be re-pulled from registries
  • Operating system - Can be reinstalled
  • Temporary files - Logs, caches (usually unnecessary)

Never Back Up

  • /tmp folders
  • Cache directories
  • Downloaded media that’s easily replaceable

Restic is a modern, fast, and secure backup tool with built-in encryption and deduplication. It’s my top recommendation for home servers.

Why Restic?

  • ✅ Encrypted by default
  • ✅ Deduplication saves space
  • ✅ Supports multiple backends (local, S3, B2, SFTP, etc.)
  • ✅ Easy to verify backups
  • ✅ Cross-platform (Linux, Mac, Windows)

Installing Restic

# Ubuntu/Debian
sudo apt update
sudo apt install restic

# Or download latest binary
wget https://github.com/restic/restic/releases/download/v0.16.3/restic_0.16.3_linux_amd64.bz2
bunzip2 restic_0.16.3_linux_amd64.bz2
chmod +x restic_0.16.3_linux_amd64
sudo mv restic_0.16.3_linux_amd64 /usr/local/bin/restic

Setting Up Restic

1. Initialize a Repository

# For local backups (external drive)
export RESTIC_REPOSITORY=/mnt/backup-drive/restic-repo
export RESTIC_PASSWORD="your-strong-password-here"

restic init

# For cloud backups (Backblaze B2 example)
export RESTIC_REPOSITORY=b2:bucket-name:repo-path
export B2_ACCOUNT_ID="your-b2-account-id"
export B2_ACCOUNT_KEY="your-b2-app-key"
export RESTIC_PASSWORD="your-strong-password"

restic init

2. Create Your First Backup

# Back up your Docker volumes and configs
restic backup \
  /var/lib/docker/volumes \
  /home/yourusername/docker-compose \
  /home/yourusername/important-data \
  --exclude-caches \
  --tag daily

3. Verify the Backup

# List snapshots
restic snapshots

# Check repository integrity
restic check

Automating Restic with Systemd

Create a backup script at /usr/local/bin/restic-backup.sh:

#!/bin/bash

# Load environment variables
export RESTIC_REPOSITORY=/mnt/backup-drive/restic-repo
export RESTIC_PASSWORD="your-strong-password"

# Backup critical directories
restic backup \
  /var/lib/docker/volumes \
  /home/yourusername/docker-compose \
  /etc/nginx \
  --exclude-caches \
  --tag automated \
  --verbose

# Keep only:
# - Last 7 daily backups
# - Last 4 weekly backups
# - Last 6 monthly backups
restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

# Verify backup health
restic check --read-data-subset=5%

Make it executable:

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

Create Systemd Service at /etc/systemd/system/restic-backup.service:

[Unit]
Description=Restic Backup Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh
User=root

Create Systemd Timer at /etc/systemd/system/restic-backup.timer:

[Unit]
Description=Run Restic Backup Daily at 2 AM

[Timer]
OnCalendar=daily
OnCalendar=02:00
Persistent=true

[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

# Check status
sudo systemctl list-timers --all | grep restic

Restoring from Restic

# List all snapshots
restic snapshots

# Restore specific snapshot
restic restore <snapshot-id> --target /restore/path

# Restore specific files
restic restore latest --target /tmp/restore --include /var/lib/docker/volumes/nextcloud

Method 2: BorgBackup (Advanced Users)

Borg is similar to Restic but with a different approach. It’s extremely efficient for large datasets.

Installing Borg

sudo apt install borgbackup

Setting Up Borg

# Initialize repository
borg init --encryption=repokey /mnt/backup/borg-repo

# Create backup
borg create \
  /mnt/backup/borg-repo::backup-$(date +%Y%m%d-%H%M) \
  /var/lib/docker/volumes \
  /home/yourusername/docker-compose \
  --stats --progress

# List backups
borg list /mnt/backup/borg-repo

# Prune old backups
borg prune \
  /mnt/backup/borg-repo \
  --keep-daily=7 \
  --keep-weekly=4 \
  --keep-monthly=6

Borg Backup Script

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

#!/bin/bash

export BORG_REPO=/mnt/backup/borg-repo
export BORG_PASSPHRASE="your-strong-passphrase"

# Backup
borg create \
  ::backup-$(date +%Y%m%d-%H%M) \
  /var/lib/docker/volumes \
  /home/yourusername/docker-compose \
  --stats --compression lz4

# Prune old backups
borg prune \
  --keep-daily=7 \
  --keep-weekly=4 \
  --keep-monthly=6

# Check repository health
borg check

Automate with cron or systemd timers (same approach as Restic).

Method 3: Docker Volume Backups with Duplicati

Duplicati offers a web-based GUI for backups — perfect if you prefer clicking over command-line.

Setting Up Duplicati

# docker-compose.yml
version: '3'
services:
  duplicati:
    image: linuxserver/duplicati
    container_name: duplicati
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
    volumes:
      - ./duplicati/config:/config
      - /var/lib/docker/volumes:/source/docker-volumes:ro
      - /home/yourusername:/source/home:ro
      - /mnt/backup:/backups
    ports:
      - 8200:8200
    restart: unless-stopped

Deploy:

docker-compose up -d

Access at http://your-server:8200 and configure backups through the web UI.

Cloud Backup Destinations

  • Cost: $0.005/GB/month storage, $0.01/GB download
  • Free tier: 10 GB storage, 1 GB daily download
  • Works with: Restic, Borg, Duplicati

AWS S3 (Glacier)

  • Cost: $0.004/GB/month (Glacier Deep Archive)
  • Good for: Long-term archival
  • Works with: Restic, Duplicati

Storj (Decentralized)

  • Cost: $0.004/GB/month
  • Privacy-focused: Encrypted and distributed
  • Free tier: 25 GB storage, 25 GB bandwidth/month

Backup Best Practices

1. Test Your Backups Regularly

# Restic: Restore to temporary location monthly
restic restore latest --target /tmp/test-restore

# Verify files are intact
ls -lh /tmp/test-restore

2. Monitor Backup Success

Use a monitoring service to alert on failed backups:

# Add to backup script
if restic backup ...; then
  curl -fsS --retry 3 https://hc-ping.com/your-check-uuid
else
  curl -fsS --retry 3 https://hc-ping.com/your-check-uuid/fail
fi

Services like Healthchecks.io offer free monitoring.

3. Encrypt Everything

  • Use strong passwords/passphrases
  • Store backup passwords in a password manager
  • Never store passwords in plain text scripts (use environment variables)

4. Document Your Process

Keep a recovery document with:

  • Backup tool used
  • Repository locations
  • Password location (password manager entry name)
  • Restore commands

Full Automation Example (Production-Ready)

Here’s a complete solution using Restic + Backblaze B2 + Healthchecks monitoring:

/usr/local/bin/production-backup.sh:

#!/bin/bash
set -euo pipefail

# Load secrets from secure location
source /root/.backup-secrets

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

# Pre-backup hook
curl -m 10 --retry 5 "${HEALTHCHECK_URL}/start"

# Run backup
restic backup \
  /var/lib/docker/volumes \
  /home/yourusername/docker-compose \
  /etc/nginx \
  --exclude-caches \
  --tag automated

# Prune old backups
restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

# Verify repository health (5% sample)
restic check --read-data-subset=5%

# Success ping
curl -m 10 --retry 5 "${HEALTHCHECK_URL}"

/root/.backup-secrets:

export RESTIC_REPOSITORY=b2:my-bucket:server-backups
export RESTIC_PASSWORD="super-strong-password"
export B2_ACCOUNT_ID="account-id-here"
export B2_ACCOUNT_KEY="app-key-here"
chmod 600 /root/.backup-secrets

Troubleshooting Common Issues

Backup Takes Too Long

  • Enable compression: restic backup --compression max
  • Exclude unnecessary paths
  • Use local backup first, then sync to cloud

Running Out of Space

  • Check deduplication is working: restic stats
  • Adjust retention policy (fewer daily/weekly backups)
  • Prune more aggressively

Failed to Connect to Repository

  • Check network connectivity
  • Verify credentials are correct
  • Test with restic snapshots manually

Conclusion

Automated backups are non-negotiable for anyone running a home server. Whether you choose Restic for its simplicity, Borg for performance, or Duplicati for its GUI, the important thing is to set it up and test it regularly.

Action plan:

  1. Choose a backup tool (start with Restic)
  2. Set up local backups first
  3. Add cloud backups for offsite protection
  4. Automate with systemd or cron
  5. Set up monitoring alerts
  6. Test a restore within 30 days

Remember: Backups you haven’t tested are just wishful thinking.


Related Guides: