Skip to content

Automated Docker Compose Backups

This guide shows a simple way to create automated backups of your Docker Compose folders using a lightweight Docker container and rsync.

The approach is intentionally simple:

  • One backup container
  • One scheduled nightly backup
  • Backup copies stored on another disk or NAS
  • No external backup software required

This works well for homelab environments and small self-hosted setups.

What This Backs Up

This guide backs up:

  • Docker Compose files
  • Container configuration folders
  • Application data volumes
  • Environment files
  • Stack folders under /docker

Example:

/docker/
├── jellyfin
├── vaultwarden
├── homeassistant
├── immich
└── paperless

Create the Project Folder

mkdir -p ~/docker/docker-backups
cd ~/docker/docker-backups

Create the Docker Compose File

Create:

nano docker-compose.yml

Paste:

services:
  docker-backups:
    image: alpine
    container_name: docker-backups
    restart: unless-stopped

    volumes:
      - /docker:/docker:ro
      - /mnt/backups/docker:/backup

    entrypoint: /bin/sh

    command: |
      -c '
      apk add --no-cache rsync tzdata busybox-suid

      cat << "EOF" > /backup-script.sh
      #!/bin/sh

      DATE=$$(date +%F)
      DEST=/backup/$$DATE

      mkdir -p $$DEST

      rsync -a --delete /docker/ $$DEST

      find /backup -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
      EOF

      chmod +x /backup-script.sh

      echo "30 1 * * * /backup-script.sh" > /etc/crontabs/root

      crond -f -l 8
      '

Start the Backup Container

Run:

docker compose up -d

How It Works

This setup:

  • Runs a lightweight Alpine Linux container
  • Installs rsync
  • Creates a nightly cron job
  • Copies /docker into dated backup folders
  • Automatically removes backups older than 30 days

Example backup structure:

/mnt/backups/docker/
├── 2026-05-25
├── 2026-05-26
├── 2026-05-27
└── latest

Avoid storing backups on the same physical disk as the original Docker data.

Better options include:

  • A second SSD
  • External USB storage
  • Synology NAS
  • Another server
  • Network share

Restoring a Backup

To restore:

  • Stop the affected containers
  • Copy the backup data back into /opt/docker
  • Restart the containers

Example:

docker compose down
rsync -a /backup/2026-05-25/jellyfin/ /opt/docker/jellyfin/
docker compose up -d

Notes

  • This is a file-level backup approach
  • Databases may benefit from application-aware backups
  • Nightly backups are sufficient for many homelab environments
  • rsync is efficient and only copies changed files

Advanced Example (Reference Only)

This is my current backup container setup.

It is more advanced than most users require, but may provide useful ideas for larger homelab environments.

services:
  docker-backups:
    image: alpine
    container_name: docker-backups
    stop_grace_period: 30s
    restart: unless-stopped

    environment:
      - TZ=America/Santo_Domingo

    volumes:
      - /opt/docker:/docker:ro
      - /mnt/sjb2/docker-backups/micropc:/backup

    entrypoint: /bin/sh

    command: |
      -c '
      apk add --no-cache rsync tzdata busybox-suid

      cat << "EOF" > /backup-script.sh
      #!/bin/sh

      DATE=$$(date +%F)
      DEST=/backup/$$DATE
      LAST=/backup/latest

      mkdir -p $$DEST

      if [ -d "$$LAST" ]; then
        rsync -a --delete --no-owner --no-group --link-dest=$$LAST /docker/ $$DEST
      else
        rsync -a --delete --no-owner --no-group /docker/ $$DEST
      fi

      rm -f /backup/latest
      ln -s $$DEST /backup/latest

      find /backup -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
      EOF

      chmod +x /backup-script.sh

      echo "30 1 * * * /backup-script.sh" > /etc/crontabs/root

      crond -f -l 8
      '