On a production Docker host, a good backup lets you rebuild every service on a new machine with the same configuration and the latest data. This article collects the practices that make that possible: what to include, how to handle databases and secrets, how to automate, and how to prove that restores work.

Define the goal: rebuild the host, not just copy files

The question to ask is not "which directories should I copy?" but "if this server disappeared tonight, what would I need to run everything again tomorrow?" The answer usually has four parts:

  1. the definition of the stack (Compose files, environment, secrets, proxy configuration);
  2. the persistent data (volumes and bind mounts);
  3. consistent database backups;
  4. the software versions in use (image tags or digests, Docker Engine and Compose versions).

If you need a refresher on images, containers and volumes, start with How to back up Docker volumes safely.

Practice 1: keep the stack definition in version control

Store docker-compose.yml, override files, Dockerfiles and proxy configuration in a Git repository. Git gives you history and review, but a repository hosted on the same server is not a backup: push it to a remote and include it in your backup set as well.

Secrets are the exception. Do not commit .env files with passwords to a repository. Keep them in a secrets manager or include them in the encrypted backup of the host.

Practice 2: pin image versions

A Compose file using image: postgres:latest restores to whatever version is "latest" on the day you restore, which may be a new major version that cannot read your data directory. Pin explicit tags, and for critical services consider digests:

services:
  db:
    image: postgres:16.4
    volumes:
      - pgdata:/var/lib/postgresql/data
  app:
    image: registry.example.com/shop/app:2026.10.2
    env_file: .env
volumes:
  pgdata:

Record the versions in your backup as well. A simple way is to save the output of docker compose images next to each backup.

Practice 3: back up databases with their own tools

Never rely only on a file copy of a running database volume. Schedule logical dumps from inside the container, which use the server's own consistency mechanisms:

#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR=/srv/backups/$(date +%F)
mkdir -p "$BACKUP_DIR"

# PostgreSQL in the "db" service of the "shop" project
docker compose -p shop exec -T db pg_dump -U shop -Fc shop > "$BACKUP_DIR/shop.dump"

# MariaDB in the "mariadb" service of the "blog" project
docker compose -p blog exec -T mariadb sh -c \
  'exec mariadb-dump --single-transaction --routines --events -uroot -p"$MARIADB_ROOT_PASSWORD" --all-databases' \
  | gzip > "$BACKUP_DIR/blog-all.sql.gz"

The -T flag disables pseudo-terminal allocation, which keeps the dump output intact. For very large databases or point-in-time recovery, use physical backups and log archiving as described in our MySQL, MariaDB and PostgreSQL guides.

Practice 4: back up the remaining volumes consistently

For volumes that are not databases, decide whether the application tolerates a live copy:

  • Append-only or static data (uploads, media, generated reports): a live copy is usually fine.
  • Applications with embedded databases (SQLite, search indexes, message queues): stop the container briefly, or use the application's export feature.

Back up named volumes through a temporary container, mounting the volume read-only:

docker run --rm -v shop_uploads:/data:ro -v /srv/backups/$(date +%F):/backup \
  alpine tar czf /backup/shop_uploads.tar.gz -C /data .

Practice 5: protect secrets in backups

Backups of a Docker host contain database passwords, API keys and TLS private keys. Treat them as sensitive data:

  • encrypt backups before they leave the host;
  • restrict who can read the backup storage;
  • rotate credentials if a backup is exposed;
  • keep the encryption key somewhere that survives the loss of the host.

Practice 6: automate and monitor

A backup script that runs from cron without monitoring will eventually fail silently: a full disk, an expired credential, a renamed container. Make every run observable:

# /etc/cron.d/docker-backup
30 2 * * * root /usr/local/bin/docker-backup.sh >> /var/log/docker-backup.log 2>&1

Use set -euo pipefail so a failing dump stops the script, check that output files are not empty, and send the result to a monitoring system or a dead man's switch service that alerts you when the expected success signal does not arrive. Alternatively, a systemd timer gives you logs in the journal and a clear failed state.

Practice 7: store copies offsite with retention

Copy the backup directory to storage outside the host and outside the provider account that runs it, for example S3-compatible object storage in another region. Apply retention so storage does not grow without limit, and keep at least one copy that cannot be deleted from the Docker host itself, such as a bucket with Object Lock or credentials that allow upload but not delete. The 3-2-1-1-0 rule summarizes these requirements.

Practice 8: document and rehearse the restore

Write the restore procedure as a numbered list, then follow it on a clean machine:

  1. Install Docker Engine and the Compose plugin.
  2. Restore the repository with Compose files and the encrypted .env files.
  3. Create the volumes and restore their archives.
  4. Start the database containers and load the dumps.
  5. Start the remaining services and update DNS or the reverse proxy.
  6. Run the verification checklist: login works, recent orders exist, uploads load.

Measure how long each step takes. That is your actual recovery time objective, discussed in RPO vs RTO.

What not to back up

  • Images from public registries, unless they may disappear; store custom images in your own registry instead.
  • Container writable layers; if something important lives there, move it to a volume.
  • Build caches and logs that you do not need for compliance.
  • The whole /var/lib/docker directory while Docker runs.

A checklist for production hosts

  • Compose files and Dockerfiles in a remote Git repository.
  • Pinned image tags, recorded with each backup.
  • Scheduled database dumps with consistency options.
  • Volume archives for non-database data.
  • Encrypted secrets and TLS keys included.
  • Offsite copy with retention and deletion protection.
  • Monitoring that alerts on failure or absence of a backup.
  • A restore test at least every quarter.

Next steps

Pick one production host and apply the checklist this week. Start with the database dumps, since they protect the most valuable data, then add volumes and configuration. The Backnix Docker backup page shows how Backnix plans to automate these steps and the current status of the integration.

References

Topics: Best practicesDockerDocker Compose