Docker container to automatically backups data to Backblaze B2
  • Shell 96.3%
  • Dockerfile 3.7%
Find a file
OfficerYoda 8136f46586
All checks were successful
build-image / build (push) Successful in 1m1s
chore: Changed default retention to in readme
Changed the default retention in the README.md example compose file form 14d to 30d
2026-06-04 23:17:25 +02:00
.forgejo/workflows ci: forgejo actions workflow for multi-arch image build 2026-05-25 21:06:58 +02:00
examples docs: add provisioner-paired example and examples README 2026-05-26 18:46:05 +02:00
lib feat: optional SERVICE_NAME included in webhook payloads 2026-05-26 21:50:04 +02:00
.dockerignore chore: initial repo scaffolding 2026-05-25 21:05:13 +02:00
.gitignore chore: initial repo scaffolding 2026-05-25 21:05:13 +02:00
backup.sh feat: optional SERVICE_NAME included in webhook payloads 2026-05-26 21:50:04 +02:00
Dockerfile feat: base Dockerfile and entrypoint 2026-05-25 21:05:40 +02:00
entrypoint.sh feat: optional SERVICE_NAME included in webhook payloads 2026-05-26 21:50:04 +02:00
README.md chore: Changed default retention to in readme 2026-06-04 23:17:25 +02:00

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.