Self-Hosted Backup Strategy for Homelab 2026: The Complete 3-2-1 Guide with Restic, Kopia & Duplicati
Reading time: ~18 minutes Audience: Homelab owners who have never tested a restore — and everyone who has data they cannot afford to lose
Introduction: The Most Common Homelab Regret
Go to any r/homelab or r/selfhosted thread titled “What do you wish you had done sooner?” and the top-voted answer is always the same: backups. Not VLAN segmentation. Not Kubernetes. Not 10 GbE networking. Backups.
The pattern is painfully consistent. A self-hoster spends months building a beautiful homelab — Proxmox hypervisor, Docker Compose stacks for Nextcloud, Jellyfin, Home Assistant, Pi-hole, Vaultwarden. Everything hums. Then one morning the boot SSD fails. Or a bad Docker volume mount overwrites a database. Or ransomware encrypts the media share. And there is no backup. Months of configuration, family photos, and carefully curated media libraries — gone.
The goal of this guide is simple: make sure that is never you. By the end, you will have a production-ready 3-2-1 backup strategy running in Docker Compose, covering your Docker volumes, Proxmox VMs, databases, and configuration files — with automated scheduling, encrypted offsite copies, and actual restore testing.
Already running Proxmox? See our Proxmox Beginner Guide if you need to set up your hypervisor first. New to Docker? Start with Nginx Proxy Manager Docker Compose for the compose fundamentals.
Why Every Homelab Needs a Backup Strategy (Now, Not Later)
Before we talk tools, let us talk about what failure actually looks like in a homelab:
| Failure Scenario | What You Lose | Recovery Without Backup |
|---|---|---|
| Boot SSD corruption | All VM configs, Docker volumes, OS | Rebuild from scratch (days to weeks) |
| RAID controller failure | Media library, documents | Re-rip/re-download (months) |
Accidental rm -rf /mnt/data |
Everything on that mount | Zero — it is gone |
| Ransomware encrypts NFS share | All files accessible to compromised container | Pay ransom or lose everything |
| Failed Docker update destroys volume | Application data, databases | Rebuild app, lose all state |
| Proxmox node hardware failure | All VMs on that node | Rebuild every VM manually |
The common thread: without backups, every one of these scenarios requires a full rebuild. With a proper 3-2-1 backup strategy, recovery takes hours — not weeks.
The Hidden Cost of NOT Backing Up
It is easy to think “I don’t have anything worth backing up — I can re-download my media and rebuild my configs.” Let us quantify that:
- Configuration files: A typical homelab has 20–40 Docker Compose files, each with environment variables, volume mounts, and network configurations tested over weeks. Rebuilding them from scratch takes 10–20 hours.
- Databases: Your Nextcloud database contains file metadata, shares, calendars, and contacts. Your Vaultwarden database holds every password. Rebuilding without a backup means starting over.
- Media libraries: Even if you can re-download, a 4 TB media library takes weeks on a typical residential connection. And many items may no longer be available.
- Family photos and documents: These are irreplaceable. A backup is the only insurance policy.
Understanding the 3-2-1 Backup Rule for Homelabs
The 3-2-1 rule is the gold standard of backup strategy, and it is deceptively simple:
| Layer | Rule | What It Means for Your Homelab |
|---|---|---|
| 3 | Three copies of your data | Primary data + local backup + offsite backup |
| 2 | Two different storage media | Don’t put both backups on the same NAS or same disk type |
| 1 | One offsite copy | Geographically separate — cloud, VPS, or a friend’s house |
Why Each Layer Matters
Three copies protects against single-point-of-failure. If your primary data lives on one server and your backup lives on another — and both are the only copies — a fire or flood that takes both eliminates your data forever. Three copies gives you a buffer.
Two different media protects against correlated failures. If your primary data and backup both live on the same NAS with the same RAID array, a RAID controller failure or filesystem corruption can destroy both simultaneously. Different media means: primary on SSD, backup on HDD; or primary on NAS, backup on external USB drive.
One offsite copy protects against physical disasters. Fire, flood, theft, lightning strike — anything that destroys your physical location. An offsite copy in the cloud, on a VPS in another city, or even at a family member’s house ensures your data survives a worst-case scenario.
Common Mistakes That Break the 3-2-1 Rule
- Same-disk “backup”: Copying files to another folder on the same drive is not a backup. If the drive fails, both copies die.
- Live mirroring without versioning: A real-time mirror (RAID 1, rsync mirror, ZFS replication) is not a backup — it is redundancy. If ransomware encrypts the primary, it encrypts the mirror too. You need versioned, point-in-time snapshots.
- Never testing restores: A backup you have never restored is Schrödinger’s backup — it might work, or it might be a collection of corrupted files. You do not know until you test.
- No encryption on offsite copies: If your offsite backup lives on a cloud provider or a VPS, and it is not encrypted, anyone with access to that storage can read your data. Always encrypt before it leaves your network.
What to Back Up in a Homelab
Not everything in your homelab needs the same backup frequency or retention. Here is the practical checklist:
Backup Priority Checklist
| Priority | Data Type | Examples | Frequency | Retention |
|---|---|---|---|---|
| 🔴 Critical | Databases, passwords | Vaultwarden DB, Nextcloud DB, config files | Daily | 90 days |
| 🔴 Critical | Docker Compose files | docker-compose.yml, .env files |
Daily (git) | Forever |
| 🟡 Important | Docker volumes | Nextcloud data, Home Assistant config, Immich uploads | Daily | 60 days |
| 🟡 Important | VM disk images | Proxmox VM backups (PBS) | Weekly | 30 days |
| 🟢 Nice-to-have | Media libraries | Jellyfin/Plex media | Weekly | 30–60 days |
| 🟢 Nice-to-have | ISO images, templates | Proxmox ISOs, Docker images | Monthly | Keep latest |
What NOT to Back Up
- Docker images: These can be re-pulled from registries. Backing them up wastes space.
- Transient caches:
/tmp, browser caches, thumbnail caches. - Downloadable media: If you can re-download it quickly and it is not personal, skip it.
Pro tip: Store your Docker Compose files in a git repository. Push to Forgejo or GitHub after every change. This gives you infinite version history for free and is your first line of defense against misconfiguration.
The Big Three Self-Hosted Backup Tools: Restic vs Kopia vs Duplicati
The homelab backup tool landscape in 2026 has three clear leaders. Each excels in different scenarios. Here is the objective comparison:
Feature Comparison Matrix
| Feature | Restic | Kopia | Duplicati |
|---|---|---|---|
| First release | 2015 | 2022 | 2014 |
| Maturity | 🔵 Very mature | 🟡 Maturing fast | 🔵 Very mature |
| Deduplication | ✅ Excellent (content-defined chunking) | ✅ Excellent (content-defined chunking) | ⚠️ Good (block-level) |
| Compression | ✅ LZ4, ZSTD | ✅ ZSTD, S2 | ✅ ZIP, 7z |
| Encryption | ✅ AES-256-GCM, ChaCha20-Poly1305 | ✅ AES-256-GCM, ChaCha20-Poly1305 | ✅ AES-256 |
| S3-compatible | ✅ Native | ✅ Native | ✅ Native |
| Web UI | ❌ CLI only | ✅ Built-in web UI | ✅ Built-in web UI |
| Docker-native | ✅ Official image | ✅ Official image | ✅ LinuxServer image |
| Resource usage | 🟢 Low (~50 MB RAM) | 🟡 Medium (~200 MB RAM) | 🔴 Higher (~300 MB RAM) |
| Snapshot browsing | CLI mount | GUI file browser | GUI file browser |
| Retention policies | ✅ Flexible | ✅ Advanced | ✅ Basic |
| Compression ratio | ~2:1 typical | ~2:1 typical | ~1.5:1 typical |
| Repository repair | ✅ restic repair |
✅ Built-in maintenance | ⚠️ Recreate database |
| Learning curve | 🔴 Steep (CLI) | 🟡 Moderate (GUI) | 🟢 Easy (GUI) |
Restic — The Command-Line Powerhouse
Restic is the tool of choice for technical users who want maximum control, efficiency, and reliability. It is written in Go, uses content-defined chunking for excellent deduplication, and supports virtually every storage backend.
Best for: Technical users comfortable with CLI, automation via cron, S3/B2 offsite backups, large datasets where deduplication matters.
Docker Compose snippet (scheduled backup with prune):
# docker-compose.yml — Restic scheduled backup
version: "3.8"
services:
restic-backup:
image: restic/restic:latest
container_name: restic-backup
environment:
- RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket-name
- RESTIC_PASSWORD=${RESTIC_PASSWORD}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
volumes:
- /opt/docker:/data:ro # Docker volumes to back up
- /etc/restic:/restic-config # Exclude files, policy config
entrypoint: ["/bin/sh", "-c"]
command:
- |
restic backup /data \
--exclude-file=/restic-config/excludes.txt \
--tag docker-volumes \
&& restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 3 --prune \
&& restic check
restart: unless-stopped
Kopia — The Modern GUI-Friendly Option
Kopia is the newest entrant and has rapidly gained traction because of its polished web UI, advanced snapshot policies, and multi-repository support. If you want a GUI to browse snapshots and restore individual files without remembering CLI flags, Kopia is the answer.
Best for: Users who want a web UI, complex retention policies per dataset, graphical snapshot browsing, multi-repo management.
Docker Compose snippet (Kopia server mode with web UI):
# docker-compose.yml — Kopia server with web UI
version: "3.8"
services:
kopia:
image: kopia/kopia:latest
container_name: kopia-server
hostname: kopia
environment:
- KOPIA_PASSWORD=${KOPIA_PASSWORD}
- USER=kopia
ports:
- "51515:51515"
volumes:
- ./kopia-config:/app/config
- ./kopia-cache:/app/cache
- /opt/docker:/data:ro
- /mnt/backup-nas:/backup-local
command:
- server
- start
- --insecure
- --address=0.0.0.0:51515
- --server-username=kopia
- --server-password=${KOPIA_PASSWORD}
restart: unless-stopped
Duplicati — The Beginner’s Choice
Duplicati is the easiest to set up: a single Docker container with a web UI, a setup wizard, and support for dozens of backends out of the box. It is the “install in 5 minutes and forget about it” option.
Best for: Beginners, quick setup, diverse backend support, users who want a familiar GUI wizard.
Docker Compose snippet (LinuxServer Duplicati):
# docker-compose.yml — Duplicati with web UI
version: "3.8"
services:
duplicati:
image: lscr.io/linuxserver/duplicati:latest
container_name: duplicati
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Jakarta
- CLI_ARGS=
volumes:
- ./duplicati-config:/config
- /opt/docker:/source:ro
- /mnt/backup-nas:/backup
ports:
- "8200:8200"
restart: unless-stopped
Which one should you choose? If you are comfortable with CLI, pick Restic. If you want a GUI without sacrificing performance, pick Kopia. If you are new and want the easiest path, start with Duplicati and consider migrating to Restic or Kopia as your needs grow.
Building Your 3-2-1 Homelab Backup Stack
Now let us assemble the complete stack, layer by layer.
Layer 1 — Primary Data (Your Production Environment)
This is where your data lives:
- Docker host: /opt/docker with all Compose files and volumes
- Proxmox host: VM disk images on local-lvm or ZFS
- NAS: Media library, document shares, ISO storage
Layer 2 — Local Backup (On-Site, Different Media)
Your first backup copy should live on different physical hardware:
| Option | Cost | Capacity | Complexity |
|---|---|---|---|
| External USB HDD (8–20 TB) | $150–$400 | High | Low |
| Dedicated backup NAS (used) | $200–$500 | High | Medium |
| Proxmox Backup Server (PBS) | $0 (software) + HW | Configurable | Medium |
| Old PC with TrueNAS | $0–$200 | High | Medium |
| Raspberry Pi + SATA HAT + HDD | $80–$200 | 1–8 TB | Medium |
NFS mount for NAS backup target (add to /etc/fstab):
# /etc/fstab — Mount NAS share for backup target
192.168.50.100:/mnt/tank/backups /mnt/backup-nas nfs rw,hard,intr,noatime 0 0
Layer 3 — Offsite Backup (Geographically Separate)
Your third copy must be physically separate from your homelab. Here are the best options for self-hosters in 2026:
| Provider | Type | Free Tier | Paid From | Best For |
|---|---|---|---|---|
| Backblaze B2 | S3-compatible object storage | 10 GB | $6/TB/month | Restic/Kopia S3 target |
| Cloudflare R2 | S3-compatible object storage | 10 GB | $0.015/GB/month | Zero egress fees |
| Hetzner StorageBox | SFTP/rsync/Borg | — | €3.81/month for 1 TB | Simple rsync target |
| BuyVM + Slab | VPS + attached storage | — | $5/month for 256 GB | Self-hosted offsite node |
| Hetzner CX22 VPS | VPS with 1 TB block storage | — | ~€6/month | Self-hosted backup server |
Restic S3 repository configuration (Backblaze B2 example):
# Set up a new Restic repository on Backblaze B2
export RESTIC_REPOSITORY="s3:s3.us-west-004.backblazeb2.com/homelab-backups"
export RESTIC_PASSWORD="your-strong-password-here"
export AWS_ACCESS_KEY_ID="your-b2-key-id"
export AWS_SECRET_ACCESS_KEY="your-b2-application-key"
restic init
Rsync to Hetzner StorageBox script:
#!/bin/bash
# rsync-backup.sh — Backup docker volumes to Hetzner StorageBox via rsync
STORAGEBOX="[email protected]"
REMOTE_PATH="/home/backups/docker"
LOCAL_PATH="/opt/docker"
LOG_FILE="/var/log/backup-rsync.log"
echo "[$(date)] Starting rsync backup to StorageBox..." >> "$LOG_FILE"
rsync -avz --delete \
--exclude="*.log" \
--exclude="cache/" \
"$LOCAL_PATH/" "$STORAGEBOX:$REMOTE_PATH/" \
>> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
echo "[$(date)] Backup completed successfully." >> "$LOG_FILE"
else
echo "[$(date)] Backup failed with exit code $?" >> "$LOG_FILE"
# Send notification (ntfy, Discord, email — see monitoring section)
fi
Proxmox-Specific Backup Strategy
If you run Proxmox as your hypervisor, you have two additional backup paths:
Proxmox Backup Server (PBS)
PBS is a dedicated backup appliance (free, open-source) that provides incremental, deduplicated VM and container backups with a web UI. It is purpose-built for Proxmox and handles dirty-bitmap incremental backups — meaning after the first full backup, subsequent backups only transfer changed blocks.
PBS Docker Compose (for running PBS as a container on a backup node):
# docker-compose.yml — Proxmox Backup Server
version: "3.8"
services:
pbs:
image: ayufan/proxmox-backup-server:latest
container_name: pbs
hostname: pbs
network_mode: host
privileged: true
volumes:
- ./pbs-config:/etc/proxmox-backup
- ./pbs-datastore:/backup-datastore
- ./pbs-logs:/var/log/proxmox-backup
restart: unless-stopped
VM Backup Schedule Recommendations
| VM Type | Backup Method | Frequency | Retention |
|---|---|---|---|
| Critical VMs (firewall, DNS) | PBS + Restic to offsite | Daily | 30 days |
| Application VMs (Nextcloud, Vaultwarden) | PBS | Daily | 30 days |
| Development VMs | PBS | Weekly | 14 days |
| Media server VMs | PBS | Weekly | 14 days |
Testing Your Backups (The Step Everyone Skips)
A backup you have never restored is not a backup — it is a hope. Every backup tool can produce corrupted output if disk errors, memory faults, or software bugs intervene.
The Quarterly Backup Fire Drill
Once every three months, run this checklist:
- Pick a random backup snapshot — do not pick the most recent one, pick one from 30 days ago. This tests your retention policies and ensures older snapshots are not silently corrupted.
- Restore to a test directory — never restore over production data.
- Verify file integrity — compare checksums with the original if possible.
- Start the restored application — spin up a Docker container from the restored config and verify it works.
- Document the result — a simple log entry: “2026-06-07: restored Nextcloud backup from 2026-05-07. All files verified. Database started successfully.”
Restic restore test script:
#!/bin/bash
# test-restore.sh — Restore a random snapshot to /tmp and verify
SNAPSHOT=$(restic snapshots --json | jq -r '.[-5].id') # 5th newest
RESTORE_DIR="/tmp/restic-restore-test-$(date +%Y%m%d)"
echo "Testing restore of snapshot: $SNAPSHOT"
mkdir -p "$RESTORE_DIR"
restic restore "$SNAPSHOT" --target "$RESTORE_DIR"
if [ $? -eq 0 ]; then
echo "✅ Restore successful. Files in: $RESTORE_DIR"
echo "📊 File count: $(find "$RESTORE_DIR" -type f | wc -l)"
echo "📊 Total size: $(du -sh "$RESTORE_DIR" | cut -f1)"
else
echo "❌ Restore FAILED. Check restic logs immediately."
fi
Disaster Recovery Scenarios
Let us walk through five real disaster scenarios and how your 3-2-1 strategy handles each:
| Scenario | RTO (Recovery Time) | RPO (Data Loss) | Recovery Path |
|---|---|---|---|
| Primary server SSD failure | 2–4 hours | 0–24 hours | Restore Docker volumes from local NAS backup. Rebuild OS from Ansible/Terraform. |
| Ransomware encrypts everything | 4–8 hours | 0–24 hours | Wipe infected systems. Restore from air-gapped or versioned backup. Offsite copy must be immutable or pull-only. |
| NAS hardware failure | 1–2 days (if replacing HW) | 0 hours | All primary data on Docker host unaffected. Restore NAS from offsite backup or PBS. |
| Offsite provider goes down | 0 hours (no data loss) | N/A | Set up new offsite target. Push fresh backup. Meanwhile, local backup still protects you. |
| Accidental deletion (30 days ago) | 1–2 hours | 0 (if versioned) | Browse versioned snapshots. Restore the specific file or directory from before the deletion. |
RTO (Recovery Time Objective): How long it takes to recover. RPO (Recovery Point Objective): How much data you can afford to lose (measured in time).
Security & Encryption Best Practices
Backups contain your most sensitive data — passwords, personal documents, family photos. Every backup copy, especially offsite copies, must be encrypted.
Encryption Checklist
| Layer | Requirement | Tool |
|---|---|---|
| At rest (local) | Encrypt backup target disk | LUKS, ZFS native encryption |
| In transit | Encrypt network traffic | TLS (Restic/Kopia), SSH (rsync), WireGuard/Tailscale |
| At rest (offsite) | Encrypt backup data before it leaves | Restic/Kopia built-in encryption |
| Key management | Store encryption keys separately from data | Password manager, offline paper backup |
| Key backup | Ensure keys are recoverable | Printed QR code of encryption key in a safe deposit box or with a trusted person |
Immutable Backups for Ransomware Protection
Restic supports append-only repositories when using the REST server backend. Kopia supports object lock with S3-compatible storage. This means even if an attacker compromises your backup server, they cannot delete or modify existing snapshots — they can only add new ones, and only until the lock expires.
Cost Comparison: Building a Backup Stack on a Budget
You can build a working 3-2-1 backup strategy at almost any budget level:
| Tier | Monthly Cost | What You Get | Safety Level |
|---|---|---|---|
| $0 | Free | Local backup to spare USB HDD. Manual offsite rotation to a drive stored at work/family. | 🟡 Low (manual, no automation) |
| $5 | ~$5/month | Hetzner StorageBox 1 TB + local USB HDD. Automated rsync or Restic. | 🟢 Good for configs + databases |
| $15 | ~$15/month | Backblaze B2 2 TB + local backup + PBS. Fully automated 3-2-1. | 🟢 Excellent for most homelabs |
| $50 | ~$50/month | Dedicated backup VPS + cloud storage + local NAS. Multi-site automated. | 🔵 Enterprise-grade redundancy |
The sweet spot for most homelabs: $5–$15/month. A Hetzner StorageBox (€3.81 for 1 TB) for offsite, a spare USB HDD for local backup, and Restic (free) for automation gives you a fully automated 3-2-1 setup for under $5/month.
Maintenance & Monitoring
A backup strategy is not “set and forget.” It requires monitoring to catch failures before you need a restore.
Backup Health Dashboard with Uptime Kuma
Monitor each backup job with Uptime Kuma push monitors. If a job does not report in within its expected window, you get an alert:
#!/bin/bash
# backup-health-check.sh — Run after each backup job
BACKUP_NAME="docker-restic-daily"
KUMA_PUSH_URL="https://uptime.yourdomain.com/api/push/abc123?status=up&msg=OK"
# ... backup commands here ...
if [ $? -eq 0 ]; then
curl -s "$KUMA_PUSH_URL&msg=Backup+${BACKUP_NAME}+completed+successfully"
else
curl -s "${KUMA_PUSH_URL}&status=down&msg=Backup+${BACKUP_NAME}+FAILED"
fi
Full monitoring setup: See our Uptime Kuma Docker Compose guide for the complete deployment and notification configuration.
Monthly Backup Health Check Routine
- [ ] Review backup logs for errors and warnings
- [ ] Check disk usage trends (are backups growing unexpectedly?)
- [ ] Verify retention policies are pruning old snapshots
- [ ] Run a spot restore test on one random file
- [ ] Verify offsite copy is reachable and up to date
- [ ] Rotate encryption key backup if keys have changed
Which Backup Tool Should You Choose? Decision Matrix
| Your Profile | Recommended Tool | Why |
|---|---|---|
| “I just want it to work — I’m new” | Duplicati | Web UI wizard, 5-minute setup, broad backend support |
| “I live in the terminal” | Restic | Fastest, most mature, best S3 support, excellent dedup |
| “I want a GUI + power” | Kopia | Web UI with advanced policies, snapshot browsing, multi-repo |
| “I only backup Proxmox VMs” | Proxmox Backup Server | Purpose-built, dirty-bitmap incremental, web UI |
| “I need versioned file-level backup with dedup” | Restic or BorgBackup | Both excellent; Restic has better cloud/S3 support |
| “I backup to NAS only, no cloud” | Kopia (server mode) | Web UI, local repository, snapshot policies |
| “I want zero-knowledge cloud backup” | Restic | Client-side encryption, all cloud providers supported |
The Beginner Path
Start with Duplicati (easiest setup, web UI wizard). Once you understand backup concepts — snapshots, retention, deduplication — migrate to Kopia or Restic for better performance and reliability.
The Power User Path
Start with Restic from day one. The CLI learning curve is worth it for the performance, reliability, and flexibility. Use the shell scripts in this guide as templates.
Conclusion: Start With ONE Backup Today
The most important backup is the one you actually run. Do not let analysis paralysis stop you from taking the first step. Here is a concrete 15-minute action plan:
- Right now: Copy your Docker Compose files to a git repository and push. This is zero-cost and protects your most valuable configuration data immediately.
- Today: Plug in a spare external HDD and run a manual restic backup of
/opt/docker. One command:restic init --repo /mnt/backup && restic backup /opt/docker. - This week: Set up the Docker Compose configuration from this guide (Restic, Kopia, or Duplicati — pick one). Schedule it via cron or the tool’s built-in scheduler.
- This month: Add an offsite target. A Hetzner StorageBox costs €3.81/month and gives you a true 3-2-1 strategy.
- This quarter: Run your first restore test. Pick a random snapshot and restore it to
/tmp. Verify the files are intact.
Your future self — the one who accidentally deletes the wrong directory, survives a hardware failure, or faces a ransomware attack — will thank you.
Related Articles
- Proxmox Beginner Guide 2026 — Set up your hypervisor the right way
- Best NAS OS for Homelab 2026 — Choose the right storage foundation
- Uptime Kuma Docker Compose Setup — Monitor your backup jobs
- Nextcloud Docker Compose Setup — Back up your self-hosted cloud
- Cloudflare Tunnel for Homelab — Securely access backup dashboards remotely
- Cheap VPS for Self-Hosting — Host an offsite backup node on a budget
- Best VPS for Homelab — Best VPS providers for offsite backups
- Portainer Setup Guide — Manage backup containers with Portainer
- Homelab Security Monitoring — Protect backups from ransomware
- Home Assistant Docker Compose — Back up your smart home config
- Traefik vs NPM vs Caddy — Reverse proxy for backup web UIs