DEV Community

Elder Fernandes
Elder Fernandes

Posted on Originally published at selfhoststack-8z4.pages.dev

Bulletproof Self-Hosted Backups: Restic, Kopia & Automated Offsite Snapshots to S3/Hetzner

Bulletproof Self-Hosted Backups: Restic, Kopia & Automated Offsite Snapshots

The number one fear stopping engineering teams from self-hosting is disaster recovery: "What happens if the VPS SSD dies at 3 AM or an accidental DROP DATABASE occurs?"

Relying solely on cloud provider disk snapshots is not enough — they don't guarantee database consistency, they are often vendor-locked, and restoring a single corrupted table requires spinning up an entire duplicate server.

Here is an automated, battle-tested backup and disaster recovery architecture using open-source tools: PostgreSQL consistent dumps + Restic encrypted deduplication + Hetzner Storage Box / S3 + Healthchecks.io dead-man switches.


The 3-2-1-1-0 Backup Rule for Self-Hosters

  • 3 Copies of Data: Live production database, local daily snapshot, offsite encrypted repository.
  • 2 Different Media: Local NVMe disk and Remote Object Storage.
  • 1 Offsite Copy: Geographically separated datacenter (e.g., VPS in Frankfurt, backups in Helsinki or S3).
  • 1 Immutable / Append-Only Copy: Protected against ransomware or compromised server credentials.
  • 0 Errors: Verified through automated daily restore drills.

Recommended Self-Hosted Backup Tools Comparison

Tool Deduplication Encryption GUI Web UI Storage Targets Best For
Restic Chunk-based AES-256 / ChaCha20 CLI / Resticker S3, SFTP, B2, Local Automated headless servers & cron jobs
Kopia Fast dynamic chunking End-to-end Yes (KopiaUI / Web) S3, Azure, GCP, SFTP, WebDAV Teams needing both CLI and Web GUI
BorgBackup Extremely mature High-grade Vorta (Desktop) SSH / BorgBase Linux-to-Linux SSH repositories
pgBackRest Postgres Block-level Optional CLI S3, Azure, GCS, POSIX Large-scale PostgreSQL PITR (>500GB)

Full Category Guide: SelfHostStack Backup & Disaster Recovery Alternatives


Production Automation: The 15-Minute Restic Backup Script

Save this script as /opt/scripts/backup.sh on your server:

#!/usr/bin/env bash
set -euo pipefail

# Configuration
export RESTIC_REPOSITORY="s3:https://<endpoint>/<bucket-name>/restic-repo"
export AWS_ACCESS_KEY_ID="<your-s3-key>"
export AWS_SECRET_ACCESS_KEY="<your-s3-secret>"
export RESTIC_PASSWORD="<strong-repo-encryption-password>"
HC_PING_URL="https://hc-ping.com/<your-uuid-token>"

# Signal Start to Healthchecks.io
curl -fsS -m 10 --retry 3 "${HC_PING_URL}/start" || true

TEMP_DIR="/tmp/db-backups"
mkdir -p "$TEMP_DIR"

echo "[1/4] Dumping PostgreSQL databases consistently..."
docker exec -t postgres_container pg_dumpall -U postgres | gzip > "$TEMP_DIR/all_databases.sql.gz"

echo "[2/4] Initializing Restic repo if needed..."
restic snapshots > /dev/null 2>&1 || restic init

echo "[3/4] Running encrypted deduplicated backup..."
restic backup \
  --tag "production" \
  --tag "daily-cron" \
  --exclude="/var/lib/docker/overlay2" \
  "$TEMP_DIR" \
  /opt/docker-stacks \
  /etc/caddy

echo "[4/4] Pruning old snapshots according to retention policy..."
restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 12 \
  --prune

# Cleanup temporary dump
rm -rf "$TEMP_DIR"

# Signal Success to Healthchecks.io
curl -fsS -m 10 --retry 3 "${HC_PING_URL}"

echo "Backup and maintenance completed successfully!"
Enter fullscreen mode Exit fullscreen mode

How to Test and Restore (The 5-Minute Drill)

Never trust a backup you haven't restored. Run this quarterly:

# List all snapshots
restic snapshots

# Restore the latest snapshot to /tmp/restore-test
restic restore latest --target /tmp/restore-test

# Verify integrity of the database dump
gunzip -t /tmp/restore-test/tmp/db-backups/all_databases.sql.gz && echo "Database dump is 100% valid!"
Enter fullscreen mode Exit fullscreen mode

Cost Analysis: Cloud Backup Costs

Strategy Storage Monthly Cost
AWS RDS Automated Backups (Retention 30d) 200 GB ~$38.00/mo
Hetzner Storage Box BX11 (RAID, ZFS, Snapshots) 1,000 GB (1 TB) €3.81/mo
Cloudflare R2 (Zero Egress Fees) 200 GB ~$2.70/mo
Backblaze B2 200 GB ~$1.20/mo

Using Restic with Hetzner Storage Box or Cloudflare R2 reduces your backup budget by over 85% while giving you instant multi-region disaster recovery.


Hardware & Storage Recommendations

  • Storage: Hetzner Storage Box (BX11/BX21) via SFTP / WebDAV or S3-compatible R2.
  • Compute VPS: Hetzner Cloud CX22 / CPX21 (€3.79 - €7.05/mo).
  • Review all cloud server benchmarks on our VPS Hosting Guide.

Explore verified Docker Compose templates, self-hosted alternatives, and full cost comparisons on SelfHostStack.

Top comments (0)