Docker Compose¶
A reference Compose stack that exercises every option exposed by the
image. Trim what you don't need; the only strictly required keys
are RESTIC_REPOSITORY, a password (RESTIC_PASSWORD_FILE or
RESTIC_PASSWORD), RESTIC_TAG, BACKUP_CRON and a backup source
mounted into the container.
Secrets do not belong in committed YAML
Real credentials live in a gitignored .env, a Docker secret file,
or an orchestrator secret store — never inline in this file.
Reference stack¶
# docker-compose.yml — reference stack with all options; trim to taste.
# Required at runtime at minimum: RESTIC_REPOSITORY, a password, RESTIC_TAG, BACKUP_CRON.
services:
restic-backup:
image: marc0janssen/restic-backup-helper:latest
container_name: restic-backup-helper
hostname: backup-node # appears in mail subjects, JSON summaries, webhook payloads
restart: unless-stopped
# Needed for `restic mount` (FUSE) and reading source paths under tight ACLs.
cap_add:
- DAC_READ_SEARCH
- SYS_ADMIN
devices:
- /dev/fuse
env_file:
- restic.env # non-secret defaults; gitignored
environment:
# ─── Restic core ───────────────────────────────────────────────────────────
RESTIC_REPOSITORY: ${RESTIC_REPOSITORY:?set in restic.env or shell}
RESTIC_PASSWORD_FILE: /run/secrets/restic_password
RESTIC_TAG: ${RESTIC_TAG:-daily}
RESTIC_CACHE_DIR: /.cache/restic
# RESTIC_CACERT: /config/ca-bundle.pem # private CA / corp proxy
RESTIC_CHECK_REPOSITORY_STATUS: "ON"
# RESTIC_AUTO_UNLOCK: "ON" # opt-in; one writer only
# ─── Backup job ────────────────────────────────────────────────────────────
BACKUP_CRON: "0 2 * * *"
BACKUP_ROOT_DIR: /data
RESTIC_JOB_ARGS: "--exclude-file /config/exclude_files.txt --one-file-system"
RESTIC_FORGET_ARGS: "--keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 10"
# ─── Optional: scheduled integrity check ───────────────────────────────────
CHECK_CRON: "37 3 * * 0"
# RESTIC_CHECK_ARGS: "--read-data-subset 5%"
# ─── Optional: standalone prune ────────────────────────────────────────────
PRUNE_CRON: "0 4 * * 0"
RESTIC_PRUNE_ARGS: "--max-unused 10%"
# ─── Optional: Rclone replicate ────────────────────────────────────────────
RCLONE_CONFIG: /config/rclone.conf
REPLICATE_JOB_FILE: /config/replicate_jobs.txt
REPLICATE_JOB_ARGS: "--exclude-from /config/exclude_sync.txt"
REPLICATE_CRON: "*/30 * * * *"
REPLICATE_VERBOSE: "ON"
# ─── Mail (msmtp) ──────────────────────────────────────────────────────────
MAILX_RCPT: ops@example.com
MAILX_ON_ERROR: "ON"
# ─── Webhook ───────────────────────────────────────────────────────────────
WEBHOOK_URL: https://hc-ping.com/00000000-0000-0000-0000-000000000000
WEBHOOK_TIMEOUT: "15"
WEBHOOK_ON_ERROR: "OFF"
# ─── Hooks ─────────────────────────────────────────────────────────────────
HOOK_TIMEOUT: "300"
# ─── Log rotation ──────────────────────────────────────────────────────────
ROTATE_LOG_CRON: "0 0 * * 6"
CRON_LOG_MAX_SIZE: "1048576"
MAX_CRON_LOG_ARCHIVES: "5"
# ─── Locale ────────────────────────────────────────────────────────────────
TZ: Europe/Amsterdam
secrets:
- restic_password
volumes:
- /etc/localtime:/etc/localtime:ro
- ./config:/config:ro
- ./config/msmtprc:/etc/msmtprc:ro
- ./hooks:/hooks:ro
- backup-logs:/var/log
- restic-cache:/.cache/restic
- /srv/documents:/data:ro
# - /mnt/restic:/mnt/restic # uncomment for local/NFS repo
# - ./restore:/restore # restic restore --target /restore
# - ~/.ssh:/root/.ssh:ro # sftp: backends only
healthcheck:
test: ["CMD-SHELL", "restic cat config >/dev/null 2>&1 || exit 1"]
interval: 15m
timeout: 30s
start_period: 1m
start_interval: 10s
command: ["tail", "-fn0", "/var/log/cron.log"]
secrets:
restic_password:
file: ./restic.password # gitignored; chmod 600
volumes:
backup-logs:
restic-cache:
Compose profiles¶
The reference scripts/docker-compose.yml
ships two opt-in Compose profiles:
| Profile | Adds | Why |
|---|---|---|
metrics |
node-exporter sidecar bound to 127.0.0.1:9100, scraping the backup-logs volume's textfile_collector/ subdirectory. |
Expose restic_<job>_last_* gauges over HTTP without a host-level node-exporter. |
dev |
mailhog SMTP catcher (port 1025 SMTP, 8025 web UI; both bound to 127.0.0.1). |
Local end-to-end test of MAILX_RCPT subjects/bodies without a real relay. |
docker compose up # only the restic-backup service
docker compose --profile metrics up # + node-exporter sidecar
docker compose --profile dev up # + mailhog SMTP catcher
docker compose --profile metrics --profile dev up # both
The main restic-backup service has no profiles: key, so it is
always brought up regardless of which profile (if any) you pick.
Healthchecks¶
Example anonymized stacks¶
The repo ships two reference stacks under
examples/compose/:
| File | Purpose |
|---|---|
examples/compose/cloud-reference.yml |
Heavily commented cloud-remote reference; every option documented inline. Strip what you don't need. |
examples/compose/multi-job.yml |
Multiple-jobs pattern using YAML anchors for shared config. |
See Multiple backup jobs for the multi-job pattern in detail.
Pulling and updating¶
docker compose pull # fetch the latest tag
docker compose up -d # recreate the container
docker compose logs -f # tail the cron log
latest and develop are moving targets. Pin both helper and
Restic versions in production by setting the image tag to the full
<helper>-<restic> form:
See Image tags.