A Docker container for automated backups with rclone synchronization.
- Scheduled backups: Runs at a specific time every day (
$WAKEUPTIME) - Volume-based backups: Creates daily tar.gz archives of directories listed in
/config/bns/backup_vols.txt(one per line) - Efficient storage: Backups are uploaded to rclone target and removed from local storage immediately
- Remote retention: Retention policy (
MAXBKP) is applied directly on the rclone target, not locally - Global pre/post scripts: Optional bash scripts executed before and after the entire backup cycle
- Volume-specific pre/post scripts: Optional per-volume scripts executed before and after each individual volume backup
- Flexible configuration: Uses rclone for any cloud storage backend
- Health checks & monitoring: Built-in HTTP endpoints for container orchestration and Prometheus metrics
- Error handling: Retry logic with exponential backoff for transient failures
- Structured logging: Configurable log levels with contextual information
- Backup verification & integrity checks: Each backup is verified with SHA256 checksum, file size verification (remote/local consistency), and archive integrity test (without extraction). Results are logged and surfaced in health state/metrics.
Important change from v1.x: This version uses a copy-based architecture instead of sync-based:
- Create: Backup is created locally in
/backups(temporary) - Upload: Backup is uploaded to rclone target using
rclone copy - Delete local: Local backup is deleted immediately after successful upload
- Remote retention: Old backups are deleted directly from the rclone target based on
MAXBKP - Verify: Each backup is verified for integrity (SHA256, file size verification, archive integrity test)
Benefits: Local storage only needs space for one backup at a time, while the rclone target stores all retained backups.
After each backup, the following integrity checks are performed:
- SHA256 checksum: Calculated for each backup archive and logged.
- File size verification: Compares the size of the uploaded file on the remote with the local file using
rclone lsl. This works with all cloud storage providers and avoids the read-only filesystem issues thatrclone checkcan have. - Archive integrity test: The backup archive is tested using
tar -tzfto verify it can be read and decompressed without actually extracting data (lightweight, fast, minimal storage overhead). - Logging: All verification results (checksum, size verification, archive integrity, backup size) are logged and included in the backup summary.
- Health state: Verification results are surfaced in the health server state and metrics.
If any verification step fails, it is logged as an error, but the backup cycle continues for other volumes.
- Non-root user: Container runs as unprivileged user (UID 1000) for better security
- Pinned versions: Uses specific dated base images and rclone version for reproducibility
- Minimal dependencies: Only installs required packages to reduce attack surface
- Multi-stage build: Efficiently builds rclone from official source
- Graceful shutdown: Handles SIGTERM/SIGINT signals properly without data corruption
Configure rclone outside of this container and mount its configuration file.
| Variable | Required | Default | Description |
|---|---|---|---|
HOSTID |
Optional | hostname | Identifier for this host (used in backup paths) |
WAKEUPTIME |
Optional | - | Daily backup time in HH:MM format (e.g., "09:20"). If not set, runs once and exits |
SKIPFIRSTRUN |
Optional | false | Skip first run if current time is past WAKEUPTIME |
SRC_VOL_BASE |
Optional | /data | Base directory containing volumes to backup |
BKP_BASE_DIR |
Optional | /backups | Temporary local directory for backups (only used during upload) |
MAXBKP |
Optional | 7 | Maximum number of backups to retain on rclone target |
PRESCRIPT |
Optional | /config/bns/backup_pre_script.sh | Path to global pre-backup script |
POSTSCRIPT |
Optional | /config/bns/backup_post_script.sh | Path to global post-backup script |
RCL_TARGET |
Required | - | Rclone remote name |
RCL_PREFIX |
Required | - | Prefix path on rclone target |
RCL_SUFFIX |
Optional | dockervolumes | Suffix path on rclone target |
LOG_LEVEL |
Optional | INFO | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
ENABLE_HEALTH_SERVER |
Optional | true | Enable health check HTTP server |
HEALTH_PORT |
Optional | 8080 | Port for health check server |
Final backup path: $RCL_TARGET:$RCL_PREFIX/$HOSTID/$RCL_SUFFIX/{volume_name}/
The container exposes HTTP endpoints for health monitoring and metrics collection:
/health- Basic health check (returns 200 if healthy, 503 if unhealthy)/ready- Readiness check for Kubernetes/orchestration (returns 200 when ready)/metrics- Prometheus-compatible metrics endpoint
backup_total_count- Total number of backup cycles completedbackup_failure_count- Total number of backup failuresbackup_volumes_success- Number of volumes successfully backed up in last cyclebackup_volumes_failed- Number of volumes that failed in last cyclebackup_last_duration_seconds- Duration of last backup cycle in secondsbackup_last_success_timestamp- Unix timestamp of last successful backupbackup_uptime_seconds- Service uptime in seconds
version: '3.8'
services:
bkpnsync:
image: acaranta/backup_n_sync:latest
ports:
- "8080:8080" # Health check port
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ... rest of configurationversion: '3.8'
services:
bkpnsync:
image: acaranta/backup_n_sync:latest
volumes:
# Configuration files (read-only)
- /srv/backupsconf/bns:/config/bns/:ro
# Rclone configuration must not be readonly
- /srv/backupsconf/rclone/config/rclone:/config/rclone
# Temporary backup directory (only needs space for 1 backup)
- /srv/backups:/backups
# Persistent cache for metrics state (survives container restarts)
- /srv/cache:/var/cache/bkpnsync
# Source data to backup (read-only recommended)
- /srv/dockervolumes:/data:ro
environment:
- SKIPFIRSTRUN=false
- WAKEUPTIME=09:20
- HOSTID=my-server
- SRC_VOL_BASE=/data
- BKP_BASE_DIR=/backups
- MAXBKP=7
- RCL_TARGET=MyCloudStorage
- RCL_PREFIX=Backups
- RCL_SUFFIX=dockervolumes
restart: unless-stoppeddocker run -d \
--name backups-n-sync \
--restart unless-stopped \
-p 8080:8080 \
-v /srv/backupsconf/bns:/config/bns:ro \
-v /srv/backupsconf/rclone/config/rclone:/config/rclone \
-v /srv/backups:/backups \
-v /srv/cache:/var/cache/bkpnsync \
-v /srv/dockervolumes:/data:ro \
-e SKIPFIRSTRUN=false \
-e WAKEUPTIME=09:20 \
-e HOSTID=my-server \
-e SRC_VOL_BASE=/data \
-e BKP_BASE_DIR=/backups \
-e MAXBKP=7 \
-e RCL_TARGET=MyCloudStorage \
-e RCL_PREFIX=Backups \
-e RCL_SUFFIX=dockervolumes \
-e LOG_LEVEL=INFO \
-e ENABLE_HEALTH_SERVER=true \
-e HEALTH_PORT=8080 \
acaranta/backup_n_sync:latestList of volume names to backup (one per line). Lines starting with # are ignored.
volume1
volume2
# volume3 - commented out
volume4
Bash script executed once before the entire backup cycle starts. Useful for global setup tasks.
#!/bin/bash
# Example: global notification
echo "Starting backup cycle" | mail -s "Backup Started" admin@example.comBash script executed once after the entire backup cycle completes. Useful for cleanup or notifications.
#!/bin/bash
# Example: global cleanup or notification
echo "Backup cycle completed" | mail -s "Backup Complete" admin@example.comBehavior:
- If global prescript fails, backup continues anyway (logs warning)
- If global postscript fails, error is logged (logs warning)
Each volume can have its own pre/post scripts located within the volume's directory:
Bash script executed before backing up this specific volume. Useful for database dumps or volume-specific preparation.
#!/bin/bash
# Example: dump PostgreSQL database for this volume
docker exec my-postgres-container pg_dump -U user mydb > /data/myvolume/dump.sqlBash script executed after successfully backing up this specific volume. Useful for cleanup tasks.
#!/bin/bash
# Example: remove temporary dump file
rm -f /data/myvolume/dump.sqlBehavior:
- If volume prescript fails, that volume's backup is skipped (other volumes continue)
- If volume postscript fails, error is logged but process continues (logs warning)
- The
.bkpnsyncdirectory is included in the backup archive
Example structure:
/data/
├── volume1/
│ ├── .bkpnsync/
│ │ ├── prescript.sh
│ │ └── postscript.sh
│ └── ... (volume data)
└── volume2/
└── ... (volume data, no scripts)