E-NO
Docker backup 7 Min Read

Docker backup and restore with practical, tested examples: an operator's guide

calendar_today Published: 2026-07-17
update Last Updated: 2026-08-02
analytics SEO Efficiency: 100%
Technical guide illustration for Docker backup and restore with practical, tested examples: an operator's guide.

Introduction

This hands-on guide shows how to back up and restore Docker images, volumes, and configuration using practical, copy-paste examples. You will get an end-to-end workflow, modern best practices, deeper examples (including databases), and a clear disaster recovery drill you can run on a clean host. By the end, you will have a repeatable approach you can use on a laptop and extend to production.

Prerequisites and assumptions

  • Linux host with Docker Engine 20.10+ (24.x recommended) and Docker Compose v2
  • Shell with bash, GNU tar, and sha256sum available
  • User in the docker group (or use sudo before docker commands)
  • At least 2x the size of your data free on the backup target
  • Optional but recommended: encryption (age, gpg, or openssl) and offsite/object storage
  • Images are pinned by tag or digest (avoid latest) and Compose files are in git

Tip: use a clean VM or a Docker Desktop context to test restores safely.

Workflow overview

  1. Inventory what to protect
  • Images and exact tags or digests
  • Container definitions (Compose files, Dockerfiles, env files)
  • Volumes and bind mounts that hold state
  • Databases inside containers (take logical dumps, not raw file copies)
  • Secrets and keys (store separately or encrypt)
  1. Quiesce or snapshot
  • Put apps in maintenance mode or schedule short downtime to pause writes
  • For databases: use logical dumps (pg_dump, mysqldump) or storage snapshots designed for consistency
  1. Back up
  • Config: git-managed files, plus a resolved Compose lock export
  • Images: docker save to a tar archive
  • Volumes: tar via a temporary helper container
  • Databases: dump to files stored with the backup
  1. Store and protect
  • Create checksums (sha256)
  • Encrypt at rest and in transit
  • Keep offsite copies with versioned retention and lifecycle policies
  1. Validate
  • Test a restore on a clean host
  • Verify container health, data checksums, logs, and app endpoints
  1. Automate
  • Shell scripts or Makefile with clear logs and non-zero exits on failure
  • Schedule via cron, systemd timers, or CI/CD runners
  1. Document rollback
  • Exact steps to return to a known-good backup, who approves, and how to verify success

Quick artifact map

ArtifactHow to back upHow to verify
Imagesdocker save -o images.tar repo:tagsha256sum -c images.tar.sha256; docker load -i images.tar
VolumesTar from a helper containersha256sum -c volume.sha256; tar tzf volume.tar.gz
Compose configdocker compose config > compose.lock.yamlDiff with expected; track in git
DB dumpspg_dump/mysqldump to filesInspect headers; test import into a temp DB

Practical backups (copy-paste)

The example backs up a simple Nginx site that serves content from a named volume. Adapt the pattern for your services.

Set up a demo service

# Network and volume
docker network create appnet
docker volume create webdata

# Run Nginx pinned to a tag (avoid latest)
docker run -d --name web \
  --network appnet -p 8080:80 \
  -v webdata:/usr/share/nginx/html:rw \
  nginx:1.25

# Put sample content in the volume
docker run --rm -v webdata:/data alpine \
  sh -c "echo 'Hello from backup demo' > /data/index.html"

Back up the volume with a helper container

set -euo pipefail
mkdir -p backups
STAMP=$(date +%F_%H%M%S)
VOL_ARCHIVE="backups/webdata-$STAMP.tar.gz"
VOL_SUM="${VOL_ARCHIVE}.sha256"
TMP_VOL_ARCHIVE="${VOL_ARCHIVE}.tmp"

# Read-only mount of the volume; preserve ownership/permissions
docker run --rm \
  -v webdata:/data:ro \
  -v "$(pwd)/backups":/backup \
  alpine sh -c "tar --numeric-owner -czf /backup/$(basename \"$TMP_VOL_ARCHIVE\") -C /data ."

mv "$TMP_VOL_ARCHIVE" "$VOL_ARCHIVE"
sha256sum "$VOL_ARCHIVE" > "$VOL_SUM"

For bind mounts on the host, prefer rsync -aHAX to preserve metadata, or tar the directory directly from the host.

Back up the image (restore without pulling)

IMG_ARCHIVE="backups/nginx-1.25-images-$STAMP.tar"
TMP_IMG_ARCHIVE="${IMG_ARCHIVE}.tmp"

docker pull nginx:1.25

docker save -o "$TMP_IMG_ARCHIVE" nginx:1.25
mv "$TMP_IMG_ARCHIVE" "$IMG_ARCHIVE"
sha256sum "$IMG_ARCHIVE" > "${IMG_ARCHIVE}.sha256"

Back up container definition and Compose

# Capture the running container inspect (ports, mounts, env)
docker inspect web > "backups/web-$STAMP.inspect.json"

# If you use Compose, export a resolved lock (run in the project dir)
# docker compose config > "backups/compose-$STAMP.lock.yaml"

Optional: database dumps (Postgres and MySQL)

# Postgres logical dump example
# export PGPASSWORD=yourpassword
# docker exec -e PGPASSWORD=$PGPASSWORD pg \
#   pg_dump -U $PGUSER -h localhost -F c -f /tmp/db.dump $PGDATABASE
# docker cp pg:/tmp/db.dump "backups/pg-$STAMP.dump"

# MySQL logical dump example
# docker exec mysql \
#   sh -c 'mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE > /tmp/db.sql'
# docker cp mysql:/tmp/db.sql "backups/mysql-$STAMP.sql"

Good practice: dump to a temporary path and move to the final filename only after success to avoid partial artifacts.

Practical restore and verification

Always start by restoring on a clean host or throwaway VM. Treat it as a disaster recovery drill.

Load images

# Verify and load the saved image
sha256sum -c backups/nginx-1.25-images-*.tar.sha256
IMG_TAR=$(ls -1 backups/nginx-1.25-images-*.tar | tail -n1)
docker load -i "$IMG_TAR"

Recreate and restore the volume

# Create the target volume
NEW_VOL=webdata
docker volume create "$NEW_VOL"

# Pick the latest archive and verify
sha256sum -c backups/webdata-*.sha256
VOL_ARCHIVE=$(ls -1 backups/webdata-*.tar.gz | tail -n1)

# Extract into the empty volume
docker run --rm \
  -v "$NEW_VOL":/data \
  -v "$(pwd)/backups":/backup \
  alpine sh -c "cd /data && tar xzf /backup/$(basename \"$VOL_ARCHIVE\")"

Start the container and validate

docker run -d --name web-restore \
  -p 8080:80 \
  -v "$NEW_VOL":/usr/share/nginx/html \
  nginx:1.25

# Basic health check
curl -fsS http://localhost:8080 | tee /tmp/page.html
grep -q "Hello from backup demo" /tmp/page.html && echo "OK" || (echo "FAIL"; exit 1)

# Optional deeper checks: logs and container health
docker logs --tail=50 web-restore

If you use Compose, restore with the locked config

# In the project directory that holds compose-$STAMP.lock.yaml
# docker compose -f backups/compose-$STAMP.lock.yaml up -d
# docker compose ps

Disaster recovery drill: step-by-step

Run this quarterly (or after significant changes) and record timing to validate RTO/RPO.

  1. Provision a clean VM or Docker context with enough disk space.
  2. Copy the latest backup set (images, volume tars, DB dumps, compose lock, checksums).
  3. Verify checksums for all artifacts with sha256sum -c.
  4. docker load images; confirm tags/digests match expectations.
  5. Create fresh named volumes; never restore into a used volume.
  6. Restore volume tarballs using a helper container.
  7. Recreate secrets/env files (decrypt if needed) and validate permissions.
  8. Start services (Compose or docker run) and wait for healthchecks.
  9. Verify:
  • App endpoint(s) respond with expected content or status.
  • Logs are free of repeated errors.
  • Database basic integrity (e.g., run SELECT COUNT(*) on key tables or mysqlcheck).
  1. Document exact commands, timings, and outcomes. Fix gaps before the next drill.

Local pilot plan

  • Scope: One Nginx service with a named volume.
  • Artifacts: image tar, volume tar.gz, inspect JSON, Compose lock (if used), checksums.
  • Success criteria: RTO under 5 minutes on a laptop; checksum validation passes; homepage text matches expected.
  • Steps:
  1. Implement the backup script from the examples.
  2. Schedule a daily cron job to write into ./backups.
  3. Run a restore on a fresh VM or Docker Desktop context.
  4. Record the process, timings, and results in your runbook.
  • Next iteration: add a small Postgres container with pg_dump; move scripts behind Make targets; add encryption and offsite sync.

Validation checklist and useful commands

  • Pre-backup: containers healthy (docker ps), app endpoints OK (curl -fsSI), disk space headroom (df -h).
  • Artifact checks: sha256sum for all tars; list tar contents (tar tzf backups/…tar.gz | head -n10).
  • Post-restore: service responds; logs clean; run a smoke test or integration test script.

Failure modes and how to recover

SymptomLikely causeFix
tar: write error: No space left on deviceInsufficient disk spaceFree space or change backup target; verify with df -h
sha256sum: FAILEDCorrupted or partial artifactRecreate/recopy; write to a temp file then rename atomically
mysqldump/pg_dump permission errorsWrong credentials or rolesPass correct env vars; grant a read-only backup role
port already allocatedOld container still boundStop/remove old container or remap ports
Volume not empty on restoreRestoring into a used volumeCreate a new volume; never mix old and new data
Permission denied on bind mountSELinux/AppArmor or host permsUse :z/:Z for SELinux; fix ownership; prefer named volumes
docker load invalid tarWrong file or truncated transferValidate checksum; recopy from source
App crash loop after restoreMissing env/secret or version mismatchRestore env/secrets; ensure image and data versions are compatible

Rollback planning and cautions

  • Keep at least 3 recent backup sets per service; label with timestamp, environment, and app git commit.
  • Pin images to immutable tags or digests so rollback is deterministic.
  • Never roll back databases without considering schema migrations; keep a current logical dump and test compatibility.
  • During rollback, stop workloads first, restore the known-good set, then start and validate before reopening traffic.
  • Keep secrets outside of general backups or encrypt them; regularly test decryption.

Example:

# Stop the faulty release
docker compose down # or: docker stop <containers>

# Restore previous artifacts (images and volumes) as in the restore section

# Start known-good images explicitly
docker run -d --name app \
  -v appdata:/var/lib/app \
  myorg/app:1.2.3

# For Compose, pin and start
docker compose -f compose-rollback.lock.yaml up -d

Automation examples

Cron scheduling (daily at 02:15):

# Edit with: crontab -e
15 2 * * * cd /opt/myapp && ./backup.sh >> backup.log 2>&1

Simple Makefile targets:

backup:
	@./scripts/backup.sh

restore-latest:
	@./scripts/restore.sh latest

verify:
	@./scripts/verify.sh

clean-old:
	@find backups -type f -mtime +30 -delete

Ensure scripts use set -euo pipefail, exit non-zero on failure, and store logs alongside artifacts. Consider a systemd timer or CI/CD schedules for centralized visibility.

  • Docker Compose: commit compose files to git; create a compose lock via docker compose config; back it up with checksums. Use healthchecks and pinned versions.
  • Kubernetes: back up manifests (git), use CSI volume snapshots or logical DB dumps, and test restores in a separate namespace. Validate Deployments roll out and Pods become Ready.
  • CI/CD: run backup scripts in a scheduled pipeline, store artifacts in your object storage, and keep credentials in protected variables with rotation.

Conclusion

Backups only matter if restores work. You now have a practical, operator-focused workflow to back up and restore Docker images, volumes, and configuration, plus a clean recovery drill you can run today. Start small, pin image versions or digests, add checksums and encryption, and practice a full restore on a fresh host. As you scale to Compose stacks or Kubernetes, the same principles hold: inventory state, quiesce, back up, validate, and document rollback.

Related Research

Article Quality Score

Reader usefulness 100%
  • check_circle Reader-ready guide
  • check_circle Practical examples included
  • check_circle Clean SEO article URL