A minimal, generic Docker container for running BorgBackup backups.
3.0K
A minimal, generic Docker container for running BorgBackup backups to any remote SSH-accessible Borg repository. Designed for TrueNAS but works anywhere Docker runs.
Why Docker Borg Client?
If you're running a home server, NAS, or any system with important data, you need reliable, automated backups. This container solves my backup problem of TrueNAS to a remote Borg:
Perfect for:
TrueNAS SCALE users can deploy this container using the Custom App feature:
Prepare SSH Keys:
mkdir -p /mnt/pool/borg-backup/ssh
ssh-keygen -t ed25519 -f /mnt/pool/borg-backup/ssh/key -N ""
chmod 700 /mnt/pool/borg-backup/ssh
chmod 600 /mnt/pool/borg-backup/ssh/key
cat /mnt/pool/borg-backup/ssh/key.pub
Deploy Custom App:
Application Name: borg-backup
Image Configuration:
diarmuidk/docker-borg-clientlatestAlwaysContainer User and Group (under Advanced Settings):
User ID: 0
Group ID: 0
Note: This container runs as root (UID/GID 0:0) to ensure reliable access to all backup paths. Backup containers require broad filesystem access by design. Privileged mode is not required.
Environment Variables (Required - add all of these):
BORG_REPO=ssh://[email protected]:22/~/backups
BORG_PASSPHRASE=your-strong-passphrase-here
BACKUP_PATHS=/data/dataset1:/data/dataset2
CRON_SCHEDULE=0 2 * * 0
PRUNE_KEEP_DAILY=7
PRUNE_KEEP_WEEKLY=4
PRUNE_KEEP_MONTHLY=6
AUTO_INIT=true
Note: Set timezone using TrueNAS's built-in Timezone dropdown (under Advanced Settings), not as an environment variable.
Optional - Time Window Configuration (for large initial backups):
BACKUP_WINDOW_START=01:00
BACKUP_WINDOW_END=07:00
BACKUP_RATE_LIMIT_IN_WINDOW=-1
BACKUP_RATE_LIMIT_OUT_WINDOW=0
This configuration runs backups only during 1am-7am at full speed, perfect for large initial backups on limited connections.
Storage:
Add Host Path Volume for SSH keys:
/mnt/pool/borg-backup/ssh/sshAdd Host Path Volume for each dataset to backup:
/mnt/pool/your-dataset/data/dataset1Add ixVolume for Borg cache:
/borg/cacheAdd ixVolume for Borg config:
/borg/configRestart Policy: Unless Stopped
Initialize Repository:
Option A - Automatic (Recommended):
AUTO_INIT=true to environment variablescat /borg/config/repo-key.txt and save to password managerOption B - Manual:
/scripts/init.shMonitor Backups:
Timezone Configuration:
TZ as a manual environment variable in TrueNAS Custom AppsTZ manually will cause deployment errors: Environment variable [TZ] is already definedSSH Key Permissions:
600 (read/write for owner only)700 (read/write/execute for owner only)Testing SSH Connection:
Before deploying, verify SSH key authentication works:
ssh -i /mnt/pool/borg-backup/ssh/key -p <port> [email protected]
If prompted for password, SSH key is not configured correctly on remote server.
Generate SSH keys (if you don't have them):
mkdir -p ssh
ssh-keygen -t ed25519 -f ssh/key -N ""
Add the public key to your backup server:
cat ssh/key.pub
# Copy this and add it to ~/.ssh/authorized_keys on your backup server
Configure environment:
cp .env.example .env
# Edit .env with your settings
Initialize the Borg repository (one-time):
docker compose run --rm borg-backup /scripts/init.sh
Start the backup container:
docker compose up -d
| Variable | Required | Default | Description |
|---|---|---|---|
BORG_REPO | Yes | - | Full SSH URL to repository (e.g., ssh://user@host:22/~/backup) |
BORG_PASSPHRASE | Yes | - | Repository encryption passphrase |
BACKUP_PATHS | Yes | - | Colon-separated paths to back up (e.g., /data/photos:/data/docs) |
BACKUP_EXCLUDES | No | - | Colon-separated paths/patterns to exclude (e.g., /data/photos/cache:/data/docs/tmp) |
BORG_RSH | No | ssh -i /ssh/key -o StrictHostKeyChecking=accept-new | SSH command |
CRON_SCHEDULE | No | - | Cron expression for scheduled backups (e.g., 0 2 * * 0). Omit to run on-demand only. |
RUN_ON_START | No | false | Run backup immediately on container start |
AUTO_INIT | No | false | Automatically initialize repository if it doesn't exist |
PRUNE_KEEP_DAILY | No | 7 | Daily archives to keep |
PRUNE_KEEP_WEEKLY | No | 4 | Weekly archives to keep |
PRUNE_KEEP_MONTHLY | No | 6 | Monthly archives to keep |
TZ | No | UTC | Timezone for cron jobs |
VERIFY_ENABLED | No | false | Enable scheduled repository integrity verification |
VERIFY_REPO_CRON_SCHEDULE | No | - | Repository check schedule (e.g., 0 3 * * 0 for weekly Sunday 03:00) |
VERIFY_ARCHIVES_CRON_SCHEDULE | No | - | Archives check schedule (e.g., 0 3 1 * * for monthly 1st at 03:00) |
VERIFY_LEVEL | No | repository | Manual verification depth: repository, archives, or full |
| Variable | Required | Default | Description |
|---|---|---|---|
NOTIFY_TRUENAS_ENABLED | No | false | Enable TrueNAS API notifications |
NOTIFY_TRUENAS_API_URL | No | - | TrueNAS WebSocket URL (e.g., ws://192.168.1.100 or wss://truenas.local) |
NOTIFY_TRUENAS_API_KEY | No | - | TrueNAS API key (generate in Settings → API Keys) |
NOTIFY_TRUENAS_VERIFY_SSL | No | true | Verify SSL certificates for wss:// (set to false for self-signed) |
NOTIFY_EVENTS | No | backup.failure,prune.failure,verify.failure | Comma-separated list of events to notify |
Available Events: backup.success, backup.failure, prune.success, prune.failure, verify.success, verify.failure, container.startup, container.shutdown
See TrueNAS API Key Setup Guide for detailed instructions.
| Variable | Required | Default | Description |
|---|---|---|---|
BACKUP_WINDOW_START | No | - | Start of backup window in HH:MM format (e.g., 01:00) |
BACKUP_WINDOW_END | No | - | End of backup window in HH:MM format (e.g., 07:00) |
BACKUP_RATE_LIMIT_IN_WINDOW | No | -1 | Rate limit during window in Mbps (-1 = unlimited) |
BACKUP_RATE_LIMIT_OUT_WINDOW | No | -1 | Rate limit outside window in Mbps (0 = stopped, -1 = unlimited) |
Rate Limit Values:
-1 = Unlimited bandwidth (burst speeds)0 = Terminate backup outside window, auto-resume from checkpoint (only valid for BACKUP_RATE_LIMIT_OUT_WINDOW)40 = 40 Mbps)Use Cases:
Large initial backup on limited connection (e.g., 1.5TB on 40 Mbps):
BACKUP_WINDOW_START=01:00
BACKUP_WINDOW_END=07:00
BACKUP_RATE_LIMIT_IN_WINDOW=-1 # Unlimited overnight
BACKUP_RATE_LIMIT_OUT_WINDOW=0 # Terminated and resumed via checkpoint
Continuous backup with daytime throttle:
BACKUP_WINDOW_START=22:00
BACKUP_WINDOW_END=08:00
BACKUP_RATE_LIMIT_IN_WINDOW=-1 # Unlimited overnight
BACKUP_RATE_LIMIT_OUT_WINDOW=5 # 5 Mbps trickle during day
Daytime backup with bandwidth limit:
BACKUP_WINDOW_START=09:00
BACKUP_WINDOW_END=17:00
BACKUP_RATE_LIMIT_IN_WINDOW=20 # 20 Mbps during business hours
BACKUP_RATE_LIMIT_OUT_WINDOW=0 # Terminated outside business hours
How It Works:
BACKUP_RATE_LIMIT_OUT_WINDOW=0:
Requirements:
Scheduled borg check verification ensures your backup repository remains healthy and detects corruption early. When enabled, two verification jobs are configured automatically:
| Variable | Required | Default | Description |
|---|---|---|---|
VERIFY_ENABLED | No | false | Enable scheduled verification |
VERIFY_REPO_CRON_SCHEDULE | No | - | Repository check schedule (e.g., 0 3 * * 0 for weekly) |
VERIFY_ARCHIVES_CRON_SCHEDULE | No | - | Archives check schedule (e.g., 0 3 1 * * for monthly) |
Verification Levels:
| Level | Command | Speed | Use Case |
|---|---|---|---|
repository | --repository-only | Fast | Weekly scheduled checks - verifies repository structure |
archives | --archives-only | Medium | Monthly checks - verifies archive metadata integrity |
full | --verify-data | Very slow | Manual spot-checks only - reads and verifies all data |
Example Configuration:
VERIFY_ENABLED=true
VERIFY_REPO_CRON_SCHEDULE=0 3 * * 0 # Weekly Sunday 3am
VERIFY_ARCHIVES_CRON_SCHEDULE=0 3 1 * * # Monthly 1st at 3am
Behaviour Notes:
full level reads all repository data and is very slow on large repos - use for manual spot-checks onlyManual Verification:
# Quick repository check
docker compose run --rm borg-backup /scripts/verify.sh
# Archives check
docker compose run --rm -e VERIFY_LEVEL=archives borg-backup /scripts/verify.sh
# Full data verification (slow - use for spot checks)
docker compose run --rm -e VERIFY_LEVEL=full borg-backup /scripts/verify.sh
| Container Path | Purpose | Mode |
|---|---|---|
/data | Source directories to back up | read-only |
/ssh | SSH private key | read-only |
/borg/cache | Borg cache (improves performance) | read-write |
/borg/config | Borg config persistence | read-write |
All manual operations can be performed via the container shell in the TrueNAS web UI:
Access Shell: Apps → Installed → borg-backup → Shell
Then run any of the following commands:
/scripts/restore.sh list/scripts/restore.sh info backup-2026-01-18_12-00-00/scripts/restore.sh check/scripts/verify.sh/scripts/backup.sh/scripts/prune.shRestore from backup:
mkdir -p /mnt/pool/borg-restore/mnt/pool/borg-restore/restore/scripts/restore.sh extract backup-2026-01-18_12-00-00 /restore/mnt/pool/borg-restore on your TrueNAS systemdocker compose run --rm borg-backup /scripts/restore.sh list
docker compose run --rm borg-backup /scripts/restore.sh info backup-2026-01-18_12-00-00
# Extract to current directory
docker compose run --rm -v $(pwd)/restore:/restore borg-backup \
/scripts/restore.sh extract backup-2026-01-18_12-00-00 /restore
# Mount archive for browsing
docker compose run --rm -v $(pwd)/mnt:/mnt borg-backup \
/scripts/restore.sh mount backup-2026-01-18_12-00-00 /mnt
docker compose run --rm borg-backup /scripts/restore.sh check
docker compose run --rm borg-backup /scripts/backup.sh
docker compose run --rm borg-backup /scripts/prune.sh
# Default (repository-only) check
docker compose run --rm borg-backup /scripts/verify.sh
# Full data verification (slow)
docker compose run --rm -e VERIFY_LEVEL=full borg-backup /scripts/verify.sh
services:
borg-backup:
image: diarmuidk/docker-borg-client:latest
container_name: borg-backup
environment:
- BORG_REPO=ssh://[email protected]:22/~/backups
- BORG_PASSPHRASE=your-strong-passphrase
- BACKUP_PATHS=/data/photos:/data/documents
- CRON_SCHEDULE=0 2 * * 0
- TZ=Europe/London
volumes:
- ./ssh:/ssh:ro
- /mnt/pool/photos:/data/photos:ro
- /mnt/pool/documents:/data/documents:ro
- borg-cache:/borg/cache
- borg-config:/borg/config
restart: unless-stopped
volumes:
borg-cache:
borg-config:
The CRON_SCHEDULE variable uses standard cron format: minute hour day-of-month month day-of-week
| Schedule | Description |
|---|---|
0 2 * * 0 | Every Sunday at 2am (default) |
0 3 * * * | Every day at 3am |
0 2 * * 1-5 | Weekdays at 2am |
0 */6 * * * | Every 6 hours |
30 1 1 * * | First day of every month at 1:30am |
Docker Borg Client supports sending notifications to TrueNAS SCALE via the TrueNAS WebSocket JSON-RPC API. This allows you to receive alerts through your existing TrueNAS notification channels (email, Slack, etc.).
Requirements: TrueNAS SCALE 25.04 or later
Generate API Key in TrueNAS:
Configure Notifications:
NOTIFY_TRUENAS_ENABLED=true
NOTIFY_TRUENAS_API_URL=ws://192.168.1.100 # Your TrueNAS IP with ws:// protocol
NOTIFY_TRUENAS_API_KEY=1-abc123yourkey
NOTIFY_EVENTS=backup.failure,backup.success
Note: Use ws:// for unencrypted WebSocket connections (recommended for local networks).
Test Notification:
# From container shell
/scripts/notify.sh "backup.success" "INFO" "Test" "This is a test notification"
For detailed setup instructions, see TrueNAS API Key Setup Guide.
backup.success - Backup completed successfullybackup.failure - Backup failedprune.success - Prune completed successfullyprune.failure - Prune failedverify.success - Repository verification completed successfullyverify.failure - Repository verification failed (potential corruption detected)container.startup - Container started (useful for monitoring container health)container.shutdown - Container stopping (useful for tracking restarts/stops)Default: Only failures are notified (backup.failure,prune.failure,verify.failure)
Tip: Add container.startup,container.shutdown to track container lifecycle events
View container logs to monitor backup status:
docker compose logs -f borg-backup
Test SSH connection manually:
docker compose run --rm borg-backup ssh -i /ssh/key user@host
If backup fails due to lock:
docker compose run --rm borg-backup borg break-lock $BORG_REPO
Check repository size:
docker compose run --rm borg-backup borg info $BORG_REPO
Regularly test restores to ensure backups are working:
docker compose run --rm borg-backup /scripts/restore.sh check
borg key export $BORG_REPO /path/to/keyfile~/.ssh/authorized_keys restrictions on the backup server:ro)borg check periodicallyYour source data is safe: All backup source directories are mounted read-only, so the container cannot modify or delete your original files.
Potentially destructive operations (use with caution):
borg break-lock - Only use if you're certain no backup is runningborg prune - Deletes old archives according to retention policy (intended behaviour)borg compact - Irreversibly frees space by removing deleted data/borg/cache or /borg/config - Can corrupt repository metadataRecommendation: Test your restore process regularly to ensure backups are working correctly.
Understanding how Borg encryption works is critical for disaster recovery planning.
Borg uses a two-layer encryption system:
Repository Key: The actual encryption key that encrypts your data
borg initPassphrase: The password you set via BORG_PASSPHRASE
To restore backups from a new machine, you need:
| Component | Where it's stored | Critical? |
|---|---|---|
| Repository access | Remote backup server | ✅ Yes |
| Passphrase | You must save this externally | ✅ Yes |
| Repository ke |
Content type
Image
Digest
sha256:5cfd22cce…
Size
25.7 MB
Last updated
3 months ago
docker pull diarmuidk/docker-borg-client