|
| 1 | +# Backup Manager |
| 2 | + |
| 3 | +A self-hosted web UI for scheduling and managing database backups in Docker environments. |
| 4 | + |
| 5 | +Connect your Docker hosts, discover running databases automatically, and set up scheduled backups - without touching a config file. |
| 6 | + |
| 7 | +**Tech stack:** Java 21 · Spring Boot 3 · H2 · React + TypeScript · shadcn/ui · Docker |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Features |
| 12 | + |
| 13 | +- 🐳 **Docker-native** - local socket or SSH tunnel to remote hosts |
| 14 | +- 🔍 **Auto-discovery** - detects PostgreSQL/MySQL/MariaDB in running containers |
| 15 | +- 🗓 **Flexible scheduling** - cron expressions or fixed-delay intervals (1h step) |
| 16 | +- 🗂 **Retention policy** - keep the last N backups, old files deleted automatically |
| 17 | +- 💾 **Disk space pre-flight** - checks free space before dump; fails fast if insufficient |
| 18 | +- ☁️ **S3 upload** - optional upload to S3-compatible storage after each backup |
| 19 | +- 📧 **Email notifications** - SMTP alerts on success and/or failure |
| 20 | +- 🔁 **Container resurrection** - re-resolves container IDs by names after `docker-compose down/up` |
| 21 | +- 💓 **Heartbeat** - periodic pings to UptimeRobot, Betterstack, etc. |
| 22 | +- 📜 **Backup history** - full log with status, duration, and file size |
| 23 | +- 🔐 **Authentication** - built-in login with session-based auth and remember me (30 days) |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Quick Start |
| 28 | + |
| 29 | +```yaml |
| 30 | +# docker-compose.yml |
| 31 | +services: |
| 32 | + backup-manager: |
| 33 | + image: nomad4tech/backup-manager:latest |
| 34 | + container_name: backup-manager |
| 35 | + ports: |
| 36 | + - "8080:8080" |
| 37 | + volumes: |
| 38 | + - /var/run/docker.sock:/var/run/docker.sock |
| 39 | + - ./data:/app/data # settings & task config (required) |
| 40 | + - ./backups:/app/backups # backup files (required) |
| 41 | + environment: |
| 42 | + - SPRING_PROFILES_ACTIVE=docker |
| 43 | + restart: unless-stopped |
| 44 | +``` |
| 45 | +
|
| 46 | +```bash |
| 47 | +docker compose up -d |
| 48 | +``` |
| 49 | + |
| 50 | +Open [http://localhost:8080](http://localhost:8080) - the local Docker socket is detected automatically. |
| 51 | + |
| 52 | +Default credentials: **admin/admin** - change them immediately in **Settings -> Account**. |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## Remote Docker Hosts (SSH) |
| 57 | + |
| 58 | +Go to **Docker Sockets → Add Socket**, enter the host and SSH credentials. Backup Manager establishes an SSH tunnel and proxies the Docker socket transparently. |
| 59 | + |
| 60 | +`socat` is managed automatically: if port `2375` is free on the remote host, Backup Manager starts socat via SSH and stops it on disconnect. If Docker is already exposed on that port by other means, no setup is needed. Install `socat` on the remote host only if Backup Manager needs to start it itself. |
| 61 | + |
| 62 | +> **Note:** SSH password is stored in plain text. For production, prefer private key authentication - specify the key path instead of a password. |
| 63 | +
|
| 64 | +--- |
| 65 | + |
| 66 | +## How It Works |
| 67 | + |
| 68 | +Backup Manager runs `pg_dump` / `mysqldump` **inside the database container** via Docker exec API. Output streams directly to disk - never buffered in memory, so large databases don't cause memory pressure. |
| 69 | + |
| 70 | +No credentials are stored in config files. PostgreSQL uses `$POSTGRES_USER`, MySQL uses `$MYSQL_ROOT_PASSWORD` - both resolved inside the container at runtime. |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Supported Databases |
| 75 | + |
| 76 | +| Database | Backup tool | |
| 77 | +|-----------|------------------------------| |
| 78 | +| PostgreSQL | `pg_dump` | |
| 79 | +| MySQL | `mysqldump` | |
| 80 | +| MariaDB | `mysqldump` / `mariadb-dump` | |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## Environment Variables |
| 85 | + |
| 86 | +| Variable | Default | Description | |
| 87 | +|----------|---------|-------------| |
| 88 | +| `BACKUP_MANAGER_BACKUP_BASE_DIRECTORY` | `./backups` | Backup storage root | |
| 89 | +| `BACKUP_MANAGER_BACKUP_MAX_CONCURRENT` | `3` | Max parallel backup jobs | |
| 90 | +| `BACKUP_MANAGER_BACKUP_MIN_FREE_SPACE_BYTES` | `536870912` | Min free space before dump (bytes) | |
| 91 | +| `BACKUP_MANAGER_BACKUP_DEFAULT_TIMEOUT` | `3600` | Max seconds per dump before it's interrupted | |
| 92 | +| `BACKUP_MANAGER_CORS_ALLOWED_ORIGINS` | `*` | Restrict CORS origins in production | |
| 93 | + |
| 94 | +--- |
| 95 | + |
| 96 | +## Known Limitations |
| 97 | + |
| 98 | +- **No HTTPS** - run behind reverse proxy (Nginx + Let's Encrypt, Caddy, or Cloudflare Tunnel) in production; don't expose application port directly to the internet |
| 99 | +- **No progress indicator** - large backups show `RUNNING` until complete |
| 100 | +- **SSH transfers are slow** - all dump data travels through the tunnel; schedule large remote backups off-peak |
| 101 | +- **Windows not tested** - socket path is hardcoded to `/var/run/docker.sock` |
| 102 | + |
| 103 | +--- |
| 104 | + |
| 105 | +## Roadmap |
| 106 | + |
| 107 | +- [ ] Restore from backup via UI |
| 108 | +- [ ] Authentication / access control |
| 109 | +- [ ] Progress indicator |
| 110 | +- [ ] MongoDB support |
| 111 | +- [ ] Telegram notifications |
| 112 | +- [ ] Backup encryption |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +## Contributing |
| 117 | + |
| 118 | +```bash |
| 119 | +# Backend |
| 120 | +./mvnw spring-boot:run -Dspring-boot.run.profiles=dev |
| 121 | + |
| 122 | +# Frontend |
| 123 | +cd frontend && npm install && npm run dev |
| 124 | +``` |
| 125 | + |
| 126 | +Issues and PRs are welcome. Please open an issue before submitting a PR. |
| 127 | + |
| 128 | +--- |
| 129 | + |
| 130 | +MIT License |
0 commit comments