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

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:

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
ZSTD_EXTRA_OPTS Options passed to zstd, default -T0 -12
KEEP_COUNT Local archives retained per Compose project
PULL_IMAGES Pull images before restarting (1 or 0)

Rclone

RCLONE_ENABLED=1
RCLONE_REMOTE="gdrive:dockerbackups"

Archives are copied beneath <remote>/<BACKUP_HOSTNAME>/. The method uses rclone copy, so it does not delete older destination files. Set RCLONE_HOST_SUBDIR=0 when RCLONE_REMOTE already names the final host-specific destination; otherwise the host name is appended automatically.

SMB

Mount the SMB share through /etc/fstab or a systemd mount unit; do not put SMB credentials in this repository. Then configure:

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:

sudo /backupdockerscripts/backup.sh

Preview all stages without stopping containers, copying, or deleting:

sudo /backupdockerscripts/backup.sh --dry-run

Run individual parts:

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:

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:

<BACKUP_ROOT>/<project>/<host>.<project>.<date_time>.tar.zst

Each archive contains the project's top-level directory rather than absolute paths. Example restore into an empty temporary directory:

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.

S
Description
No description provided
Readme
131 KiB
0 Stars 1 Watchers 0 Forks
Languages
Shell 100%