Site's logo

KL, MY

7:30:00 AM

A hard drive disk

How to backup your docker service named volume

A quick guide to backing up Docker named volumes manually and automatically using best practices.

January 16, 2024(Last update at April 16, 2025)

5 min read

So, you’ve got your containerized service up and running—everything works flawlessly for months, maybe even years. Then one day, your server becomes inaccessible, and your service goes down. After troubleshooting, you discover the cause: a failed storage drive. Now, you’re either spending time and money to recover it—or accepting that your data is gone forever.

One of the main reasons to run a homelab is to take control of your own data. That also means taking responsibility for protecting it. In this article, we’ll cover how to back up Docker container data stored in named volumes—and why that’s a little different than working with bind mounts.

Why Focus on Named Volumes?

If your container stores data using bind mounts, you can easily back it up by tarring the folder and transferring it via scp or sftp.

However, named volumes are managed by Docker itself and not directly tied to a visible host path. Simply tarring their directories is not best practice. Instead, there’s a safer and more structured way to back them up.

How to Manually Back Up a Named Volume

To back up a named volume, we’ll spin up a temporary container that:

  • Mounts the volume
  • Archives its content
  • Saves the archive to a directory on your host machine

It is recommended that you stop the container before you backup your named volume.

On Linux:

Terminal window
docker run --rm -v "VOLUME_NAME:/tmp" \
-v "HOST_BACKUP_DIR:/backup" \
ubuntu tar -czvf /backup/BACKUP_FILE.tar /tmp

On Windows (WSL2):

Terminal window
docker run --rm -v "VOLUME_NAME:/tmp" `
-v "HOST_BACKUP_DIR:/backup" `
ubuntu tar -czvf /backup/BACKUP_FILE.tar /tmp
  • VOLUME_NAME – your Docker named volume (check with docker volume ls)
  • HOST_BACKUP_DIR – where to save the backup file, e.g., $HOME/docker
  • BACKUP_FILE.tar – name your backup clearly and include the date

Example: Backing up Firefly III’s database (on Ubuntu)

I will be using Firefly III as an example as I use this everyday. The example will be in Linux (Ubuntu):

Terminal window
docker run --rm -v "firefly_iii_db:/tmp" \
-v "$HOME/docker/firefly/backup:/backup" \
ubuntu tar -czvf /backup/firefly_db_2024_01_04.tar /tmp

This command:

  • Mounts firefly_iii_db to /tmp in the container
  • Mounts your host’s $HOME/docker/firefly/backup to /backup
  • Tars /tmp and saves it to the backup directory

How to Restore the Backup

To restore from the backup, simply reverse the process:

Terminal window
docker run --rm -v "VOLUME_NAME:/recover" \
-v "HOST_BACKUP_DIR:/backup" \
ubuntu tar -xvf /backup/BACKUP_FILE.tar -C /recover --strip 1

Just like with backups, stop any running containers that are using the volume before restoring it.

Automatic backup is easier

Manual backups are great—but automated backups are better. You shouldn’t rely on your memory to protect your data.

For this, we’ll use offen/docker-volume-backup. This Docker image can:

  • Back up named volumes daily
  • Store them locally
  • Upload to S3
  • Optionally encrypt with GPG

Example: Compose Service for Automated Backup

backup:
# In production, it is advised to lock your image tag to a proper
# release version instead of using `latest`.
# Check https://github.com/offen/docker-volume-backup/releases
# for a list of available releases.
container_name: {SERVICE_NAME}_backup
image: offen/docker-volume-backup:v2
environment:
BACKUP_FILENAME: {SERVICE_NAME}-backup-%Y-%m-%dT%H-%M-%S.tar.gz
BACKUP_PRUNING_PREFIX: {SERVICE_NAME}-backup-
BACKUP_RETENTION_DAYS: 21
AWS_S3_BUCKET_NAME: {AWS_BUCKET_NAME}
AWS_S3_PATH: {SERVICE_NAME}
AWS_ACCESS_KEY_ID: {AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: {AWS_SECRET_ACCESS_KEY}
GPG_PASSPHRASE: {PASSPHRASE_TO_ENCRYPT_YOUR_FILE}
BACKUP_STOP_CONTAINER_LABEL: {SERVICE_NAME}
restart: always
volumes:
- {VOLUME_NAME_TO_BACKUP}:/backup/{CONTAINER_NAME}:ro
- {VOLUME_NAME_TO_BACKUP}:/backup/{CONTAINER_NAME}:ro
# Mounting the Docker socket allows the script to stop and restart
# the container during backup. You can omit this if you don't want
# to stop the container. In case you need to proxy the socket, you can
# also provide a location by setting `DOCKER_HOST` in the container
- /var/run/docker.sock:/var/run/docker.sock:ro
# If you mount a local directory or volume to `/archive` a local
# copy of the backup will be stored there. You can override the
# location inside the container by setting `BACKUP_ARCHIVE`.
# You can omit this if you do not want to keep local backups.
- ./backups:/archive

Don’t Forget: Add Backup Labels to Your Main Service

{SERVICE_NAME}:
container_name: {MY_SERVICE_APP_NAME}
image: {MY_SERVICE_IMAGE}
restart: always
labels:
// the {SERVICE_NAME} should be the same as the one you specify
// in the backup container environment - BACKUP_STOP_CONTAINER_LABEL
- docker-volume-backup.stop-during-backup={SERVICE_NAME}

📆 By default, backups run daily at 12:00 AM UTC. You can customize this with the TIMEZONE variable.

To manually trigger a backup:

Terminal window
docker exec <container_ref> backup

Restoring backup from docker-volume-backup

Restoration is still a manual step. The process is identical to the manual restore described above.

If your backup is encrypted (ends in .gpg), decrypt it first:

Terminal window
gpg -o {TAR_FILE_NAME}.gz -d {TAR_FILE_NAME}.gz.gpg

Then restore it using the tar command.

Backing Up Multiple Named Volumes

To include multiple volumes in a single backup file, just map them into subdirectories:

backup:
container_name: firefly_iii_backup
image: offen/docker-volume-backup:v2
environment: .....
restart: always
volumes:
- db:/backup/db:ro
- upload:/backup/upload:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./backups:/archive

Restoring Specific Volumes from Combined Backup

To restore the db volume:

Terminal window
docker run --rm -v "firefly_iii_db:/recover" \
-v "$HOME/docker/firefly:/backup" \
ubuntu tar -xvf /backup/{TAR_VOLUME_NAME}.gz \
--strip-components=2 -C /recover /backup/db

To restore upload volume:

Terminal window
docker run --rm -v "firefly_iii_upload:/recover" \
-v "$HOME/docker/firefly:/backup" \
ubuntu tar -xvf /backup/{TAR_VOLUME_NAME}.gz \
--strip-components=2 -C /recover /backup/upload

Final Thoughts: Backup Is Non-Negotiable

You now know how to:

  • Back up and restore Docker named volumes manually
  • Automate backups with daily schedules
  • Store backups locally and to cloud providers like S3

Following the 3-2-1 backup rule may seem like overkill—but at the very least, aim to store your backups in two different locations.

Thanks for reading, and happy self-hosting!