# Zorruno Docker Backup Scripts Modular backup scripts for Docker Compose servers such as Panda and Beaver. Each server has its own untracked `.env` and `containers.txt`, while all script logic remains common and can be updated through Git. ## Pipeline `backup.sh` runs these stages in order: 1. `stages/10-containers.sh` — stop, archive, pull, start and verify projects. 2. `methods/20-rclone.sh` — copy archives to an rclone destination when enabled. 3. `methods/30-smb.sh` — copy archives to a mounted SMB share when enabled. 4. `stages/90-prune.sh` — retain the newest configured number locally. Every stage can also be run directly. The old `docker-backup.sh` name invokes the container archive stage, while `dockerbackup_prune.sh` invokes the local prune stage. Use the new `backup.sh` for the complete pipeline. ## Requirements - Bash 4 or later - Docker with `docker compose`, or legacy `docker-compose` - GNU `tar` with zstd support - `flock` - `rclone` only when the rclone method is enabled - `rsync` and `mountpoint` only when the SMB method is enabled The account running the scripts must be allowed to control Docker and read all files under `/dockervolumes`. ## Installation on Beaver ```bash sudo git clone https://home.fox.co.nz/gitea/zorruno/zorruno-backupdockerscript.git /backupdockerscripts cd /backupdockerscripts sudo cp .env.example .env sudo cp containers.txt containers.local.txt sudo chmod 600 .env sudo chmod +x backup.sh docker-backup.sh dockerbackup_prune.sh stages/*.sh methods/*.sh ``` Edit `.env`. Beaver's Docker source is already represented by: ```bash SOURCE_BASE_DIR="/dockervolumes" BACKUP_HOSTNAME="beaver" ``` Choose and create a local staging path for `BACKUP_ROOT`. `/dockerbackups` is the default, but it should be on a filesystem with enough free space to hold at least `KEEP_COUNT` copies of every listed project. Edit Beaver's untracked `containers.local.txt`. Each active line can be either a running container name or a directory name beneath `/dockervolumes`. Blank lines and text after `#` are ignored. If several entries resolve to the same Compose project directory, that project is backed up only once. Keeping this host-local file out of Git prevents a pull on Panda or Beaver from replacing its list. ## Configuration Copy `.env.example` to `.env`; `.env` is ignored by Git. Important values: | Variable | Purpose | |---|---| | `SOURCE_BASE_DIR` | Parent of Compose project directories | | `BACKUP_ROOT` | Local archive staging and retention tree | | `CONTAINERS_FILE` | Absolute path, or path relative to this repository | | `BACKUP_HOSTNAME` | Host folder/name embedded in archive filenames | | `BACKUP_METHODS` | Ordered method names, default `rclone smb` | | `KEEP_COUNT` | Local archives retained per Compose project | | `PULL_IMAGES` | Pull images before restarting (`1` or `0`) | ### Rclone ```bash RCLONE_ENABLED=1 RCLONE_REMOTE="gdrive:dockerbackups" ``` Archives are copied beneath `//`. The method uses `rclone copy`, so it does not delete older destination files. ### SMB Mount the SMB share through `/etc/fstab` or a systemd mount unit; do not put SMB credentials in this repository. Then configure: ```bash SMB_ENABLED=1 SMB_MOUNT="/mnt/dockerbackups" SMB_HOST_SUBDIR=1 ``` The script refuses to copy unless `SMB_MOUNT` is an actual mount point. This prevents a failed network mount from silently filling the server's root disk. ## Running Run the complete pipeline: ```bash sudo /backupdockerscripts/backup.sh ``` Preview all stages without stopping containers, copying, or deleting: ```bash sudo /backupdockerscripts/backup.sh --dry-run ``` Run individual parts: ```bash sudo stages/10-containers.sh --dry-run sudo methods/20-rclone.sh --dry-run --force sudo methods/30-smb.sh --dry-run --force sudo stages/90-prune.sh --dry-run ``` `--force` runs a transfer method even when its `*_ENABLED` value is false. It still requires the method's destination to be configured and available. ## Adding another backup method Add an executable script named `methods/NN-name.sh`, for example `methods/40-restic.sh`. It should load `lib/common.sh`, accept `--dry-run`, and return a non-zero status on failure. Add its short name to `.env`: ```bash BACKUP_METHODS="rclone smb restic" ``` The main pipeline discovers the numbered file from the short name and runs it after the earlier methods. A failed method stops the pipeline, so pruning will not run after a failed transfer. ## Archive and restore format Archives are stored as: ```text //...tar.zst ``` Each archive contains the project's top-level directory rather than absolute paths. Example restore into an empty temporary directory: ```bash mkdir -p /tmp/docker-restore tar --zstd -xf backup.tar.zst -C /tmp/docker-restore ``` Inspect and verify restored content before replacing a live project.