Filesystem layout¶
Every path the container cares about and what you typically mount over the
top of it. Paths marked VOLUME are declared in the Dockerfile and get
automatically created if you do not mount them; the rest are conventions.
Container paths at a glance¶
| Path | Purpose | Typical mount | Notes |
|---|---|---|---|
/data |
Declared VOLUME; typical backup source when BACKUP_ROOT_DIR=/data. |
-v /srv/documents:/data:ro |
Use :ro so hooks cannot mutate sources. |
/config |
Recommended mount for rclone.conf, exclude/include files, msmtprc, replicate job file. |
-v ./config:/config |
Bind-mount; some backends update rclone.conf (token refresh) so it may need write access. |
/hooks |
Optional mount for /hooks/{pre,post}-<job>.sh. |
-v ./hooks:/hooks:ro |
Hooks must be executable inside the container. |
/restore |
Convention for restic restore --target /restore and /bin/snapshot-export --output. |
-v ./restore:/restore |
Refuses non-empty target unless --force (restore wrapper). |
/fusemount |
Default --target for /bin/mount-snapshot (FUSE). Container-internal by design — keeps the FUSE mount separate from /bin/restore output and host bind-mounts. |
n/a (no host bind-mount needed; browse via docker exec ... cat / tar streams — docker cp does not see FUSE mounts) |
Refuses non-empty target unless --force; opt in to host visibility with --allow-other + bind: propagation: rshared on a separate /fusemount bind-mount. |
/mnt/restic |
Default RESTIC_REPOSITORY location for local disk / NFS. |
-v restic-repo:/mnt/restic or NFS_TARGET=… |
Mount target of NFS_TARGET when set. |
/var/log |
Cron log, per-run JSON summaries, Prometheus textfiles. | -v backup-logs:/var/log |
Persist if you scrape last-*.json or compressed cron_log_*.tar.gz. |
/.cache/restic |
Restic cache directory. | -v restic-cache:/.cache/restic |
Persist to speed up subsequent backups; safe to throw away. |
/etc/msmtprc |
msmtp SMTP relay config; sendmail symlink → msmtp. | -v ./config/msmtprc:/etc/msmtprc:ro |
Required only when MAILX_RCPT is set. |
/run/secrets/restic_password |
Conventional Docker secret mount. | secrets: in Compose |
Point RESTIC_PASSWORD_FILE here. |
/var/log/textfile_collector |
Recommended METRICS_DIR target. |
-v ./metrics:/var/log/textfile_collector |
Mount when scraping Prometheus textfiles. |
/var/spool/cron/crontabs/root |
Rendered crontab written by /entry.sh. |
tmpfs if read-only root | Required writable; needs tmpfs: /var/spool/cron with read_only: true. |
/tmp, /run, /var/run |
scratch dirs (lock files, restic temp). | tmpfs if read-only root | Required writable. |
Logs written by the workers¶
Each worker maintains a small set of *-last.log files under /var/log,
plus a structured last-<job>.json summary and (when METRICS_DIR is set)
a restic_<job>.prom Prometheus textfile.
/var/log/
├── cron.log # everything cron-related
├── cron_log_<timestamp>.tar.gz # rotated archives (rotate_log)
│
├── backup-last.log # /bin/backup, per-run log
├── backup-error-last.log # snapshot of backup-last.log on failure
├── backup-mail-last.log # mail body used by the backup mail
├── last-backup.json # structured summary, JSON
│
├── check-last.log
├── check-error-last.log
├── check-mail-last.log
├── last-check.json
│
├── prune-last.log
├── prune-error-last.log
├── prune-mail-last.log
├── last-prune.json
│
├── replicate-last.log
├── replicate-error-last.log
├── replicate-mail-last.log
├── last-replicate.json
│
├── restore-last.log # /bin/restore, per-run log
├── restore-error-last.log
├── restore-mail-last.log
├── last-restore.json
│
├── snapshot-export-last.log # /bin/snapshot-export, per-run log
├── snapshot-export-error-last.log
├── snapshot-export-mail-last.log
├── last-snapshot-export.json
│
├── forget-preview-last.log # /bin/forget-preview, per-run log
├── forget-preview-error-last.log
├── forget-preview-mail-last.log
├── last-forget-preview.json
│
├── mount-snapshot-last.log # /bin/mount-snapshot, per-session log
├── mount-snapshot-error-last.log
├── mount-snapshot-mail-last.log
├── last-mount-snapshot.json
│
└── textfile_collector/ # only when METRICS_DIR is set
├── restic_backup.prom
├── restic_check.prom
├── restic_prune.prom
├── restic_replicate.prom
├── restic_restore.prom
├── restic_snapshot_export.prom
├── restic_forget_preview.prom
└── restic_mount_snapshot.prom
*-last.log files are overwritten every run (no rolling). last-*.json
files are written via *.tmp + mv so an external scrape never sees a
partial document. Compressed archives cron_log_<timestamp>.tar.gz are
created by /bin/rotate_log; tune retention via MAX_CRON_LOG_ARCHIVES.
Lock files¶
/bin/locked_run writes one /var/run/<name>.lock per worker. They are
not safe to mount as volumes (they need to be local to the container's
PID namespace) and are intentionally created in tmpfs when you run with
read_only: true.
Read-only root recipe¶
When tightening with read_only: true, you need tmpfs / volume mounts for
exactly the paths the workers touch. Minimal recipe:
read_only: true
tmpfs:
- /tmp
- /run
- /var/run
- /var/spool/cron # crond writes the rendered crontab here
volumes:
- backup-logs:/var/log # persists last-*.json + archives
- restic-cache:/.cache/restic # speeds up subsequent backups
See Hardening for the full discussion of
trade-offs (losing last-*.json on restart if you tmpfs /var/log, etc.).