- Shell 96.3%
- Dockerfile 3.7%
|
All checks were successful
build-image / build (push) Successful in 1m1s
Changed the default retention in the README.md example compose file form 14d to 30d |
||
|---|---|---|
| .forgejo/workflows | ||
| examples | ||
| lib | ||
| .dockerignore | ||
| .gitignore | ||
| backup.sh | ||
| Dockerfile | ||
| entrypoint.sh | ||
| README.md | ||
automatic-backups
Generic Docker backup container: cron-driven, archives a mounted directory
(or runs a docker exec dump first), uploads to Backblaze B2, prunes old
archives, posts JSON webhooks on success/failure.
Quick start
services:
backups:
image: forgejo.officeryoda.dev/officeryoda/automatic-backups:latest
restart: unless-stopped
environment:
TZ: Europe/Berlin
BACKUP_CRON: "0 3 * * *"
RETENTION_DAYS: "30"
B2_ACCOUNT_ID: ${B2_ACCOUNT_ID}
B2_APPLICATION_KEY: ${B2_APPLICATION_KEY}
B2_BUCKET: officeryoda-backups-forgejo
volumes:
- /srv/myapp/data:/backup:ro
If you used the provisioner,
just env_file: ./<service>.b2.env instead — it sets B2_BUCKET,
B2_ACCOUNT_ID, and B2_APPLICATION_KEY for you. See examples/ for full
compose files including the pre-backup hook.
Configuration
Required
| Variable | Description |
|---|---|
BACKUP_CRON |
5-field cron expression. |
RETENTION_DAYS |
Positive integer; archives older than this are pruned from B2. |
B2_ACCOUNT_ID |
B2 application key ID. |
B2_APPLICATION_KEY |
B2 application key secret. |
B2_BUCKET |
Target B2 bucket name. |
Optional
| Variable | Default | Description |
|---|---|---|
TZ |
UTC |
Container timezone. |
BACKUP_NAME_TEMPLATE |
backup.%Y-%m-%d_%H-%M |
strftime template for archive base name. |
BACKUP_FORMAT |
tar.zst |
One of: zip tar tar.gz tar.xz tar.bz2 tar.zst. |
BACKUP_SOURCE_DIR |
/backup |
Directory to back up. |
BACKUP_ALL |
true |
Include everything under BACKUP_SOURCE_DIR except auto-excludes. Set to false to use INCLUDE_PATTERNS instead. |
INCLUDE_PATTERNS |
(empty) | Newline/comma-separated rclone globs. Required when BACKUP_ALL=false. |
EXCLUDE_PATTERNS |
(empty) | Newline/comma-separated rclone globs. Always applied. |
B2_PATH |
(empty) | Sub-path inside the bucket. |
PRE_BACKUP_CONTAINER |
(empty) | Container name for the optional docker exec hook. |
PRE_BACKUP_CMD |
(empty) | Shell command run inside PRE_BACKUP_CONTAINER. |
PRE_BACKUP_USER |
(empty) | -u user for docker exec. |
SERVICE_NAME |
(empty) | Identifier included in webhook payloads as service_name (omitted from JSON when unset). |
WEBHOOK_URL_SUCCESS |
(empty) | URL POSTed on success. |
WEBHOOK_URL_FAILURE |
(empty) | URL POSTed on failure. |
When BACKUP_ALL=true, these are auto-excluded at any depth: .env,
.env.*, docker-compose.y[a]ml, compose.y[a]ml, *.override.y[a]ml.
Pre-backup hook
For services with built-in dump tooling, mount /var/run/docker.sock and a
shared volume, then set PRE_BACKUP_CONTAINER + PRE_BACKUP_CMD. The
container runs docker exec [-u $PRE_BACKUP_USER] $PRE_BACKUP_CONTAINER sh -c "$PRE_BACKUP_CMD" before archiving. See examples/docker-compose.forgejo.yml.
Run a backup manually
To trigger a backup outside the cron schedule, exec into the running container:
docker exec -it <container-name> /usr/local/bin/backup.sh
This reuses the container's environment and runs the same pipeline (pre-backup hook, archive, upload, prune, webhooks) cron would. Avoid triggering manually if a cron run is currently active — concurrent runs can corrupt the pre-backup dump file and double the upload cost.
Webhooks
Success:
{"status":"success","timestamp":"...","host":"...","service_name":"forgejo","filename":"...","size_bytes":12345678,"size_human":"11.8MB","format":"tar.zst","remote_path":"b2:bucket/path","duration_seconds":42}
Failure:
{"status":"failure","timestamp":"...","host":"...","service_name":"forgejo","format":"tar.zst","remote_path":"b2:bucket/path","stage":"upload","exit_code":1}
service_name only appears when SERVICE_NAME is set; it's omitted from
the JSON otherwise. A failed POST is logged, never fatal.
CI / image
Image: forgejo.officeryoda.dev/officeryoda/automatic-backups:latest (also
tagged :sha-<short> and :vX.Y.Z for tagged releases). Built multi-arch
(linux/amd64, linux/arm64). The repo needs a PACKAGES_TOKEN secret
with write:package scope.