compose-backup: One-Command Backup for Docker Compose Stacks
If you’re running multiple Docker Compose services — Nextcloud, Traefik, Gitea, Home Assistant, whatever — you probably have a patchwork of backup scripts. Or worse, no backups at all.
compose-backup fixes that. One command, and every Compose project on your server gets backed up: configs, .env files, override files, and Docker volumes — all compressed into a clean .tar.gz archive you can actually restore from.
Why You Need This
Here’s what usually happens with self-hosted backups:
- You set up a service
- You tell yourself you’ll “set up backups later”
- You add three more services
- Your disk dies
- You spend a weekend rebuilding everything from memory
compose-backup eliminates this cycle. Run it once, add it to cron, and forget about it.
Installation
curl -fsSL https://raw.githubusercontent.com/bird/compose-backup/main/compose-backup.sh -o /usr/local/bin/compose-backup
chmod +x /usr/local/bin/compose-backup
That’s it. It’s a single Bash script with no dependencies beyond Docker.
Basic Usage
Just run it:
compose-backup
The tool automatically scans common directories (~/docker, /opt/stacks, /srv, etc.) for docker-compose.yml or compose.yml files, then backs up each project it finds.
What Gets Backed Up
For each Compose project, compose-backup saves:
- docker-compose.yml (and any override files)
- .env files
- Config directories (config/, certs/, nginx/, traefik/, ssl/)
- Named Docker volumes (exported as tar archives)
- Metadata (hostname, Docker version, timestamps)
Everything lands in a single compressed archive:
Specifying Paths
If your stacks aren’t in standard locations:
compose-backup /opt/my-stacks /home/user/services
Excluding Large Volumes
Some volumes are huge (databases, media libraries). Skip them:
compose-backup --exclude postgres_data --exclude media_files
Backing Up Specific Projects
Only care about certain stacks?
compose-backup --only nextcloud --only traefik
Config-Only Backups
If you handle volume backups separately (like with restic or borgbackup):
compose-backup --no-volumes
Dry Run
See what would be backed up without doing anything:
compose-backup --dry-run
Output:
Restoring from Backup
List your backups:
compose-backup --list
Restore the most recent one:
compose-backup --restore latest
Or restore a specific backup:
compose-backup --restore ~/compose-backups/compose-backup-2026-02-16_030000.tar.gz
The tool extracts everything to a restore directory. From there, copy configs back to your compose directories and restore volumes:
docker run --rm -v nextcloud_data:/dest -v /path/to/restore/nextcloud/volumes:/backup alpine tar xf /backup/nextcloud_data.tar -C /dest
Automating with Cron
Run compose-backup --schedule to get a ready-to-paste crontab line:
# Daily at 3am, keep 7 days
0 3 * * * /usr/local/bin/compose-backup && find ~/compose-backups -name '*.tar.gz' -mtime +7 -delete
Add it with crontab -e and you’re done.
Backup Structure
Here’s what a backup looks like inside:
Clean, organized, and self-documenting.
Pairing with selfhost-doctor
If you’re using selfhost-doctor (our one-command server health check), you now have a solid self-hosting toolkit:
- selfhost-doctor tells you what’s wrong
- compose-backup makes sure you can recover
Both are single Bash scripts, zero dependencies, and cron-friendly.
Tips
- Test your restores. A backup you’ve never restored from isn’t a backup — it’s a hope.
- Store archives off-server. Use
rsync,rclone, or even a simplescpto push archives to another machine or cloud storage. - Start with
--dry-run. See what the tool finds before committing. - Use
--verboseif you want to see exactly what’s happening during backup.
Requirements
- Bash 4+
- Docker with Compose V2 (
docker compose) - Standard tools:
tar,gzip
Get It
curl -fsSL https://raw.githubusercontent.com/bird/compose-backup/main/compose-backup.sh -o /usr/local/bin/compose-backup
chmod +x /usr/local/bin/compose-backup
Source: GitHub
Stop winging your Docker backups. One command, everything saved, sleep better at night.