
In containerized homelabs and production Docker environments, traditional backup strategies frequently fall short. Simple file archiving scripts (such as tar -czf) duplicate identical data repeatedly, consume massive disk bandwidth, and often produce corrupted backups when copying live database files directly from volume directories. Furthermore, storing unencrypted archives on local disks violates the fundamental 3-2-1 backup principle, leaving infrastructure vulnerable to hardware failure and ransomware.
BorgBackup (or simply Borg) solves these foundational challenges through authenticated, client-side encryption (AES-256 or ChaCha20-Poly1305) and content-defined chunking deduplication. Only newly created or altered file blocks are stored across backup iterations, routinely shrinking multi-gigabyte daily snapshots into megabytes of physical storage. Borgmatic acts as the declarative orchestration engine for Borg: it reads a unified YAML configuration, coordinates pre-backup database dumps, manages archive creation, prunes aged snapshots, executes data integrity checks, and reports health statuses to monitoring dashboards.
In this technical guide, we will build an automated, containerized backup pipeline using Docker Compose, Borgmatic, and an S3-compatible cloud storage replication backend (such as AWS S3, MinIO, or Backblaze B2 via Rclone).
Architecture: Automated Deduplicated Backup Pipeline
A reliable backup pipeline must execute atomically. Backups should begin with live database dumps, proceed with filesystem volume archiving and deduplication, verify archive integrity, and finally replicate encrypted repository segments offsite to remote object storage.
+-----------------------------------------------------------------------------+
| Local Docker Host |
| |
| +---------------------------+ +-----------------------------------+ |
| | Production Workloads | | Borgmatic Container (Scheduled) | |
| | - PostgreSQL / MariaDB | <=== | - Pre-backup Hooks (DB Dumps) | |
| | - Application Volumes | | - Deduplicated Encryption Engine | |
| +-------------+-------------+ +-----------------+-----------------+ |
| | | |
| | Stream Dumps & Read Volumes | |
| +---------------------------------------+ |
| | |
| v |
| +-------------------------------------------+ |
| | Local Borg Repository (/mnt/backups/borg) | |
| | - Authenticated Chunk-Level Deduplication | |
| | - Pruning Policy (Retention Management) | |
| | - Archive Integrity & Verification Checks | |
| +---------------------+---------------------+ |
| | |
| | Post-backup Hook |
| | (Rclone Sync) |
| v |
+----------------------------------------------------+------------------------+
|
| Encrypted Blocks (TLS)
v
+-------------------------------+
| Offsite S3 Cloud Storage |
| (MinIO, Backblaze B2, AWS S3) |
+-------------------------------+
Key Architecture Advantages
- Content-Defined Chunking: Files are sliced into dynamic chunks based on byte patterns rather than fixed offsets. Inserting a single byte at the beginning of a multi-gigabyte file does not invalidate subsequent chunk hashes, maximizing deduplication efficiency.
- Zero-Downtime Database Dumps: Borgmatic streams database dumps (via
pg_dumpormysqldump) directly into Borg archives in-flight, eliminating intermediate disk I/O and preventing dirty reads. - Cryptographic Client-Side Isolation: Backups are encrypted before leaving the local host. Even if the offsite S3 bucket is compromised, an attacker without the repository passphrase holds only opaque, authenticated ciphertext blocks.
Step 1: Directory Setup & Storage Layout
We will configure persistent host directories for Borgmatic configurations, SSH/Rclone keys, local cache files, and the primary local Borg repository:
sudo mkdir -p /opt/borgmatic/{config,borg-cache,borg-repo,rclone-config}
sudo mkdir -p /var/docker-data # Example application data directory
cd /opt/borgmatic
Create a secure environment file (.env) to hold repository credentials, encryption passphrases, and monitoring webhook tokens:
cat <<EOF > .env
# Borg Repository Encryption Passphrase
BORG_PASSPHRASE=$(openssl rand -base64 32)
# Monitoring Webhook (Healthchecks.io or Uptime Kuma)
HEALTHCHECKS_URL=https://hc-ping.com/your-uuid-here
# Database Credentials
POSTGRES_USER=appuser
POSTGRES_PASSWORD=supersecretpassword
POSTGRES_DB=appdb
EOF
sudo chmod 600 .env
Step 2: Production Docker Compose Definition
Create the docker-compose.yml file. We deploy an active Borgmatic container alongside an example PostgreSQL 16 database to demonstrate automated database dumping and filesystem volume replication:
services:
borgmatic:
image: b3vis/borgmatic:latest
container_name: borgmatic-runner
restart: unless-stopped
environment:
- BORG_PASSPHRASE=${BORG_PASSPHRASE}
- TZ=Etc/UTC
- BORG_CACHE_DIR=/root/.cache/borg
volumes:
# Borgmatic configuration file
- /opt/borgmatic/config:/etc/borgmatic.d:ro
# Local Borg repository
- /opt/borgmatic/borg-repo:/mnt/repository
# Borg chunk cache
- /opt/borgmatic/borg-cache:/root/.cache/borg
# Host Docker volumes to back up
- /var/docker-data:/mnt/source/docker-data:ro
# Rclone config for offsite S3 sync
- /opt/borgmatic/rclone-config:/root/.config/rclone
# Read-only access to host docker socket for container inspect/hooks
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- backup-net
# Example production database to protect
database:
image: docker.io/library/postgres:16-alpine
container_name: production-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pg-data:/var/lib/postgresql/data
networks:
- backup-net
volumes:
pg-data:
networks:
backup-net:
driver: bridge
Step 3: Declarative Borgmatic Configuration (config.yaml)
Create the declarative configuration file at /opt/borgmatic/config/config.yaml. This file instructs Borgmatic where to find repositories, which paths to include or exclude, how to execute database dumps, which retention tiers to keep, and how to verify integrity:
# Repository definitions
repositories:
- path: /mnt/repository
label: local-nvme-repo
# Source directories to include
source_directories:
- /mnt/source/docker-data
# Exclude temporary and transient files
exclude_patterns:
- '*.tmp'
- '*.log'
- '*/cache/*'
- '*/node_modules/*'
# Encryption and compression algorithms
storage:
encryption: repokey-blake2
compression: zstd,3
checkpoint_interval: 1800
extra_borg_options:
create: --stats
# Retention policy (Pruning)
retention:
keep_hourly: 24
keep_daily: 7
keep_weekly: 4
keep_monthly: 6
keep_yearly: 1
prefix: '{hostname}-'
# Repository consistency verification
consistency:
checks:
- repository
- archives
check_last: 3
prefix: '{hostname}-'
# Database Hooks
hooks:
postgresql_databases:
- name: appdb
hostname: production-postgres
port: 5432
username: appuser
password: supersecretpassword
format: custom
# Monitoring and offsite replication hooks
before_backup:
- echo "Starting scheduled Borgmatic backup cycle..."
after_backup:
- echo "Backup and pruning completed. Synchronizing to S3..."
- rclone sync /mnt/repository s3-remote:homelab-borg-backups/$(hostname) --fast-list --transfers 4
on_error:
- echo "Borgmatic backup encountered a failure!"
- curl -fsS -m 10 --retry 3 "${HEALTHCHECKS_URL}/fail" || true
after_everything:
- curl -fsS -m 10 --retry 3 "${HEALTHCHECKS_URL}" || true
Configuration Deep-Dive
repokey-blake2: Utilizes BLAKE2b for cryptographic MAC hashing paired with authenticated AES-256 payload encryption, offering superior CPU performance over legacy SHA-256.compression: zstd,3: Zstandard level 3 provides high compression ratios with exceptional decompression throughput, outperforming gzip while minimizing CPU load.postgresql_databaseshook: Streams binary-compressedpg_dumpdata directly into the Borg archive without writing an unencrypted intermediate SQL dump to disk.rclone sync: Once the local archive is confirmed and verified, Rclone mirrors the immutable segment files to S3 object storage.
Step 4: Configuring Rclone for S3 Cloud Storage
Create the Rclone configuration file at /opt/borgmatic/rclone-config/rclone.conf to connect to your remote S3-compatible provider (MinIO, Backblaze B2, Cloudflare R2, or AWS S3):
[s3-remote]
type = s3
provider = Other
env_auth = false
access_key_id = YOUR_S3_ACCESS_KEY
secret_access_key = YOUR_S3_SECRET_KEY
endpoint = https://s3.us-east-005.backblazeb2.com
acl = private
Ensure file permissions are restricted to the container root user:
sudo chmod 600 /opt/borgmatic/rclone-config/rclone.conf
Step 5: Initializing the Repository & Executing the First Run
Start the Docker Compose stack:
docker compose up -d
Before Borgmatic can create archives, the target repository must be cryptographically initialized. Execute the init command inside the Borgmatic container:
docker compose exec borgmatic borgmatic init --encryption repokey-blake2
Trigger an immediate manual backup run with verbose output to verify database connectivity, filesystem scanning, and S3 replication:
docker compose exec borgmatic borgmatic create --verbosity 1 --stats
The resulting output will display comprehensive deduplication statistics:
------------------------------------------------------------------------------
Archive name: myhost-2026-10-03T06:20:15
Archive fingerprint: d98f3b9c8e10471b69203a95e7c85a5332f1a6f...
Time (start): Sat, 2026-10-03 06:20:15
Time (end): Sat, 2026-10-03 06:20:24
Duration: 9.12 seconds
Number of files: 14,820
Original size: 4.85 GB
Compressed size: 1.42 GB
Deduplicated size: 1.41 GB
------------------------------------------------------------------------------
Subsequent runs on largely unchanged data will complete in seconds, with the Deduplicated size metric reflecting only the incremental modified bytes.
Step 6: Disaster Recovery & Granular Restoration
A backup is meaningless unless it can be reliably restored under disaster scenarios.
1. Listing Existing Archives
Inspect all available restore points in the repository:
docker compose exec borgmatic borgmatic list
2. Extracting Files or Entire Directories
To extract specific files from an archive into a recovery staging directory:
mkdir -p /opt/borgmatic/restore
cd /opt/borgmatic/restore
docker compose exec -w /mnt/restore borgmatic \
borgmatic extract --archive myhost-2026-10-03T06:20:15 \
--path mnt/source/docker-data/nginx/nginx.conf
3. Restoring the PostgreSQL Database Dump
Extract the PostgreSQL database dump from the archive and pipe it back into the running database container:
docker compose exec -w /mnt/restore borgmatic \
borgmatic extract --archive myhost-2026-10-03T06:20:15 \
--path root/.borgmatic/postgresql_databases/appdb
# Restore using pg_restore
docker compose exec -T database pg_restore \
-U appuser -d appdb --clean --if-exists < /opt/borgmatic/restore/root/.borgmatic/postgresql_databases/appdb
Troubleshooting Common Operational Issues
Issue 1: Repository Lock Contention
Symptom: Borgmatic commands fail immediately with Failed to create/acquire the lock /mnt/repository/lock.exclusive.
Root Cause: An earlier backup job was forcibly terminated (e.g., due to an abrupt host reboot or container restart) leaving a stale lockfile in place.
Resolution: Verify no active backup processes are running, then release the lock:
docker compose exec borgmatic borg break-lock /mnt/repository
Issue 2: Database Connection Refused During Pre-Backup Hook
Symptom: Borgmatic aborts with pg_dump: error: could not connect to server: Connection refused.
Root Cause: The database container is not reachable over the specified Docker bridge network or hostname.
Resolution: Ensure both the borgmatic service and the target database reside within the same user-defined bridge network (e.g., backup-net), and verify that the hostname directive in config.yaml matches the database’s container service name.
Issue 3: Rclone S3 Synchronization Exceeds Bandwidth Limits
Symptom: Offsite cloud synchronization saturates upload bandwidth, causing packet loss and latency spikes across the local network.
Resolution: In config.yaml, add Rclone’s --bwlimit flag to throttle network throughput during offsite transfers:
after_backup:
- rclone sync /mnt/repository s3-remote:homelab-borg-backups/$(hostname) --bwlimit 15M --fast-list
Conclusion & Best Practices
Automating your backup strategy with Borgmatic and BorgBackup transforms disaster recovery from an error-prone manual chore into a deterministic, cryptographically secure background process. With content-defined chunking deduplication, full daily snapshots require only a fraction of physical disk space while maintaining granular historical retention.
To ensure total operational resilience, adhere to these key practices: regularly schedule automated disaster recovery drills by restoring files to an isolated environment, keep your repository encryption key exported and stored in an offline password manager, and always connect monitoring pings (such as Healthchecks.io) to receive instant notifications if a backup cycle fails.
Hi, I’m Mark, the author of Clever IT Solutions: Mastering Technology for Success. I am passionate about empowering individuals to navigate the ever-changing world of information technology. With years of experience in the industry, I have honed my skills and knowledge to share with you. At Clever IT Solutions, we are dedicated to teaching you how to tackle any IT challenge, helping you stay ahead in today’s digital world. From troubleshooting common issues to mastering complex technologies, I am here to guide you every step of the way. Join me on this journey as we unlock the secrets to IT success.


