Backup & Restore
March 11, 2026 · View on GitHub
Back up all your Docker service volumes, compose files, and environment variables in one command.
Quick Start
homebutler backup # backup everything
homebutler backup --service jellyfin # backup a specific service
homebutler backup --to /mnt/nas/backups/ # custom destination
homebutler backup list # list existing backups
Restore from a backup:
homebutler restore ./backup_2026-03-11_1830.tar.gz # restore all
homebutler restore ./backup_2026-03-11_1830.tar.gz --service postgres # restore one service
How It Works
When you run homebutler backup, here's what happens step by step:
Step 1: Discover Docker services
docker compose ls
homebutler finds all running Docker Compose projects and their compose file locations.
Step 2: Inspect container mounts
docker inspect <container> --format '{{json .Mounts}}'
For each container, homebutler identifies all attached volumes — both named volumes (managed by Docker) and bind mounts (host directories).
Step 3: Back up volumes
Named volumes can't be accessed directly from the host. homebutler uses the official Docker pattern — spinning up a temporary Alpine container that mounts the volume read-only and creates a tar archive:
docker run --rm \
-v my_volume:/source:ro \
-v /backup/path:/backup \
alpine tar czf /backup/my_volume.tar.gz -C /source .
The temporary container is removed immediately after (--rm). The volume is mounted read-only (:ro), so your data is never modified.
Bind mounts are backed up directly from the host filesystem using tar.
Step 4: Copy compose files
The docker-compose.yml and .env files are copied into the archive. These are essential for restoring your services.
Step 5: Generate manifest
A manifest.json is created with full metadata:
{
"version": "1",
"created_at": "2026-03-11T18:30:00+09:00",
"services": [
{
"name": "postgres",
"container": "a1b2c3d4...",
"image": "postgres:16",
"mounts": [
{
"type": "volume",
"name": "postgres_data",
"source": "/var/lib/docker/volumes/postgres_data/_data",
"destination": "/var/lib/postgresql/data"
}
]
}
]
}
Step 6: Create archive
Everything is bundled into a single .tar.gz:
backup_2026-03-11_1830.tar.gz
├── manifest.json
├── compose/
│ ├── docker-compose.yml
│ └── .env
└── volumes/
├── postgres_data.tar.gz
└── jellyfin_config.tar.gz
Restore
When you run homebutler restore ./backup.tar.gz:
- Extracts the archive to a temp directory
- Reads
manifest.jsonto understand what was backed up - Restores named volumes using the reverse pattern (alpine container +
tar xzf) - Restores bind mounts by extracting to the original host path
- Restores compose files to their original location
Use --service <name> to restore only a specific service.
Configuration
Set a custom backup directory in your homebutler.yml:
backup:
dir: /mnt/nas/backups/homebutler
Default location: ~/.homebutler/backups/
Scheduled Backups
Combine with cron for automated backups:
# Every day at 3 AM
0 3 * * * homebutler backup --to /mnt/nas/backups/
# Weekly on Sunday at 2 AM, keep only the latest
0 2 * * 0 homebutler backup --to /mnt/nas/weekly/
JSON Output
homebutler backup --json
{
"archive": "/home/user/.homebutler/backups/backup_2026-03-11_1830.tar.gz",
"services": ["postgres", "jellyfin", "pihole"],
"volumes": 5,
"size": "2.5 GB"
}
⚠️ Important Notes
Database consistency
homebutler copies volume files as-is. It does not automatically stop or pause containers during backup. For most services (config files, media libraries, etc.) this is perfectly fine.
However, database services (PostgreSQL, MySQL, MongoDB, etc.) may be writing data during the backup, which can result in an inconsistent snapshot.
Recommended approach for databases:
# Option A: Pause the container (brief freeze, no downtime)
docker pause postgres
homebutler backup --service postgres
docker unpause postgres
# Option B: Use native database dump (most reliable)
docker exec postgres pg_dump -U myuser mydb > dump.sql
homebutler backup # backs up everything else
Security
- Backup archives are not encrypted. They may contain sensitive data (database contents, environment variables with passwords, API keys).
- Store backups in a secure location with appropriate file permissions.
- Consider encrypting with
gpgfor offsite storage:
homebutler backup --to /tmp/
gpg --symmetric /tmp/backup_2026-03-11_1830.tar.gz
What is NOT backed up
- Docker images (they can be re-pulled with
docker compose pull) - Container logs
- Docker networks (they are recreated by
docker compose up) - System-level configs outside of Docker