A self-hosted web application to schedule, monitor, and restore Docker volume backups with rsync and rclone backends.
Built with Flask, Vue.js 3, SQLite, and Socket.IO.
- Web dashboard with real-time status via WebSocket
- Analytics with Chart.js (timeline, distribution, performance, anomaly detection)
- Per-job retention policy (configurable number of versions to keep)
- Dual backend: rsync (default) + rclone (S3, GDrive, WebDAV, SMB, SFTP)
- Compression via zstd (tar.zst archives) or direct rsync mirror
- Notifications: Telegram, WhatsApp (WAHA), Email weekly report
- Restore browser: navigate archives, search files, one-click restore
- 6 languages: FR, EN, DE, IT, ES, PT with browser auto-detection
- 5 themes: Dark, Light, OLED, Neon, Ember
- Scheduler: APScheduler with cron expressions per job
- Prometheus metrics endpoint at
/metrics - PWA-ready
git clone https://github.com/great-horn/backup.git
cd backup
cp .env.example .env
docker compose -f docker-compose.standalone.yml up -d --buildOpen http://localhost:9895 in your browser.
Two demo jobs (disabled) are created on first run. Follow the guide below to configure your first real backup job.
Edit docker-compose.standalone.yml to expose the directories you want to back up:
volumes:
- ./data:/app/logs
- /path/to/myapp:/data/myapp # your source directory
- /path/to/another:/data/another # add as many as needed
- /tmp/restore:/tmp/restoreDirectories are mounted under
/data/inside the container. Add:ro(read-only) if you don't need restore capability back to the source.
For backing up to a server running rsyncd (port 873):
# Create the password file
echo "your_rsync_password" > rsync.secret
chmod 600 rsync.secretUncomment the rsync volume in docker-compose.standalone.yml:
- ./rsync.secret:/app/rsync.secret:roConfigure the rsync host in .env:
RSYNC_HOST=192.168.0.100
RSYNC_USER=backup
RSYNC_MODULE=backup
rclone is a universal backend that supports 40+ storage providers.
Step 1 — Get an obscured password (needed for most remotes):
docker exec backup rclone obscure 'yourpassword'
# outputs something like: jJ89bJX_FgueJ8rC0Yjom7VsnQocRqq...Step 2 — Create rclone.conf in the project directory:
SMB / CIFS (NAS, Windows share)
[mynas]
type = smb
host = 192.168.0.100
user = myuser
pass = <obscured_password>SFTP
[myserver]
type = sftp
host = 192.168.0.100
user = myuser
pass = <obscured_password>S3 (AWS, MinIO, Backblaze B2)
[mys3]
type = s3
provider = AWS
access_key_id = AKIAXXXXXXXXXXXXXXXX
secret_access_key = <obscured_key>
region = eu-west-1Google Drive
[gdrive]
type = drive
client_id = your_client_id
client_secret = <obscured_secret>
token = {"access_token":"...","token_type":"Bearer","refresh_token":"...","expiry":"..."}Run
rclone configon your local machine first to generate the token via OAuth flow, then copy the resulting config.
See the full list of providers at rclone.org/overview.
Step 3 — Secure the file and mount it:
chmod 600 rclone.confUncomment the rclone volume in docker-compose.standalone.yml:
- ./rclone.conf:/app/rclone.conf:roStep 4 — Verify the connection:
docker compose -f docker-compose.standalone.yml up -d
docker exec backup rclone --config /app/rclone.conf lsd mynas:You should see the available shares or buckets listed.
docker compose -f docker-compose.standalone.yml up -dOpen the web UI → Settings → New Job and fill in:
| Field | Example |
|---|---|
| Name | myapp |
| Source path | /data/myapp |
| Destination path | /backups/myapp (rsync) or ShareName/path (rclone) |
| Mode | Compression (tar+zstd) or Direct (rsync mirror) |
| Backend | rsync or rclone |
| Remote name | (rclone only) mynas — must match the [name] in rclone.conf |
| Remote path | (rclone only) ShareName/backups/myapp |
| Retention | Number of versions to keep (default: 7) |
| Schedule | Cron expression, e.g. 0 3 * * * for 3 AM daily |
Click Save, then hit the play button to run a test backup.
All settings are managed via environment variables. See .env.example for the full list.
| Variable | Description | Default |
|---|---|---|
PORT |
Web UI port | 9895 |
TZ |
Timezone | Europe/Zurich |
RSYNC_HOST |
rsync daemon host | 192.168.0.100 |
RSYNC_USER |
rsync daemon user | backup |
RSYNC_MODULE |
rsync module name | backup |
TELEGRAM_BOT_TOKEN |
Telegram bot token | (disabled) |
TELEGRAM_CHAT_ID |
Telegram chat ID | (disabled) |
SMTP_HOST |
SMTP server for email reports | (disabled) |
backup/
├── run.py # Entry point
├── backup.sh # Backup execution (rsync/rclone + zstd + retry)
├── web/
│ ├── app.py # Flask + SocketIO + routes
│ ├── db.py # SQLite schema, seeds, migrations
│ ├── jobs.py # CRUD job configs
│ ├── scheduler.py # APScheduler management
│ ├── analytics.py # Stats, metrics, Prometheus
│ ├── restore.py # Browse + restore archives
│ ├── notifications.py# Telegram, WhatsApp, Email
│ ├── utils.py # Shared utilities
│ └── static/ # Vue.js 3 SPA frontend
├── shared/ # Shared CSS/JS (themes, layout, components)
└── Dockerfile
- Single container: Flask + APScheduler + backup.sh
- SQLite in WAL mode for job configs, backup history, and metrics
- backup.sh handles execution with retry logic (3 attempts, 30s delay)
- Vue.js 3 SPA with Socket.IO for real-time updates
| Mode | Description |
|---|---|
| Compression | rsync to temp → tar+zstd → push archive (default) |
| Direct | rsync mirror with --delete (for large media) |
| Endpoint | Description |
|---|---|
GET /run?job=<name> |
Start a backup job |
GET /kill?job=<name> |
Stop a running job |
GET /api/jobs |
List all job configs |
POST /api/jobs |
Create a new job |
PUT /api/jobs/<name> |
Update a job |
DELETE /api/jobs/<name> |
Delete a job |
GET /api/stats |
Backup statistics |
GET /api/logs |
Backup history |
GET /api/restore/list |
Available backups |
GET /api/restore/search?q= |
Search across archives |
GET /metrics |
Prometheus metrics |
| Page | URL | Description |
|---|---|---|
| Dashboard | / |
Job grid with real-time status |
| Analytics | /analytics |
Charts, anomalies, storage |
| Logs | /logs |
Backup history with filters |
| Settings | /settings |
Job CRUD, schedules |
| Restore | /restore |
Browse and restore files |
Built with Flask, Vue.js 3, Chart.js, Socket.IO, and APScheduler.

