Configuring Docker Volumes for Persistent Data Storage
Containers are ephemeral by nature—when you run docker rm, everything inside disappears. For databases, uploads, logs, and configs this means data loss on every restart. Docker Volumes solve this, but misconfiguration leads to two opposite problems: data still gets lost, or volumes grow uncontrollably and fill the host disk. In our practice, we had a case: after docker compose down && up on a PostgreSQL project, we lost 300 GB of data—anonymous volumes were not removed, new ones were created over old ones, and data became inaccessible. In this article, we break down how to set up reliable persistent storage and avoid typical mistakes. Our engineers with 5+ years of DevOps experience guarantee that after setup your volumes will work like clockwork. Request a volume audit—we will show where the risks are hidden.
Three Mount Types—Where Each Fits
Named volumes are the primary tool for production. Docker manages their location on the host (/var/lib/docker/volumes/), and you can use drivers for NFS, S3, Ceph. They are portable between environments via docker volume create.
Bind mounts attach a specific host path. Convenient for development (hot reload of code), dangerous in production: If the path is wrong, the container gets an empty directory or wrong content, which is not always obvious from logs.
tmpfs mounts are only in memory, not written to disk. For secrets, temporary files, cache that does not need to survive restart.
| Type | Purpose | Backup | Performance |
|---|---|---|---|
| Named volume | Production, databases, files | Simple via temporary container | Native, with driver possibilities |
| Bind mount | Development, configs, logs | Manual copy from host | Direct disk access |
| tmpfs mount | Secrets, cache, temp data | Not required (in-memory) | Highest (in-memory) |
Why Named Volumes Are Better Than Bind Mounts
Bind mounts in production are a frequent cause of incidents. According to our practice statistics, 90% of storage problems in Docker are related to bind mounts. Imagine: during deployment you accidentally mount an empty directory, and the application writes data there. After restart, real data ends up elsewhere, and garbage is in the mounted directory. With named volumes this does not happen: Docker creates the directory and controls its contents. Also, named volumes are easy to back up and move between servers using drivers. Volume storage optimization can save up to 40% of disk space through deduplication and proper rotation.
How to Configure Named Volumes in Compose
services:
postgres:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_USER: app
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes --appendfsync everysec
minio:
image: minio/minio:latest
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
volumes:
postgres_data:
driver: local
redis_data:
driver: local
minio_data:
driver: local
Explicit declaration of volumes in the volumes: section is mandatory—without it, Compose creates an anonymous volume with a random hash name, which accumulates on every docker compose down && up and is not removed without docker volume prune. Each such anonymous volume can take up several gigabytes, and with dozens of them, disk fills with garbage.
Backing Up Named Volumes (Step by Step)
- Create a dump of the database through the running container:
docker exec postgres_container pg_dump -U app myapp | gzip > backup_$(date +%Y%m%d).sql.gz - For binary data, use a temporary container with read-only mount:
docker run --rm \ -v postgres_data:/source:ro \ -v /backup:/dest \ alpine tar czf /dest/postgres_data_$(date +%Y%m%d).tar.gz -C /source .Mounting with
:ro(read-only) during backup is a good practice: accidental writes to source will not corrupt data.How to Use NFS for Shared Storage
For multi-host environments (Docker Swarm, multiple servers), local volumes do not work—data is tied to a specific node. The solution is an NFS volume driver or specialized plugins.
--- volumes: shared_uploads: driver: local driver_opts: type: nfs o: "addr=nfs-server.internal,rw,nfsvers=4" device: ":/exports/uploads"For AWS, EFS mounts to multiple EC2 instances simultaneously, unlike EBS. If you use the cloud, we help configure the optimal storage driver for your infrastructure.
How to Solve Permission Issues
The most common problem with volumes in production: the container runs under an unprivileged user, but the volume is created with root permissions. The result: Permission denied on the first write.
# In Dockerfile, explicitly create the directory with correct permissions BEFORE declaring VOLUME RUN mkdir -p /app/data && chown -R appuser:appuser /app/data USER appuserOr on first run:
services: app: user: "1001:1001" volumes: - app_data:/app/data volumes: app_data: driver: localdocker volume inspect app_datawill showMountpointon the host—there you can manually fix permissions if something went wrong. As part of setup, we always check UID/GID and adjust rights if needed. In 80% of cases, the error is resolved in 5 minutes.Typical Volume Configuration Mistakes
- Anonymous volumes in Compose—use named ones.
- Missing
user:in docker-compose—root rights inside container. - Forgetting
:roduring backup—risk of data modification. - NFS version below 4—issues with locks.
- No backup rotation—disk fills up in a week.
What Is Included in End-to-End Volume Setup
- Current volume audit: inventory of all volumes, types, data criticality, backup status.
- Migration of anonymous volumes to named with explicit naming.
- Driver configuration tailored to your infrastructure: local, NFS, cloud (AWS EFS, Azure Files).
- Permission configuration for each volume considering the container user.
- Backup strategy: automation via cron or CI/CD, archive rotation.
- Restoration documentation: runbook with instructions for on-call team.
- Team training: how to add new volumes, how to check status.
After completion, you receive a transparent storage scheme with a guarantee that volumes will not be lost on restart and will not clog the disk.
Scope of Work Estimated Time Typical Cost Compose stack cleanup 4–8 hours $500–$1,500 NFS or cloud volume driver 1–2 days $1,000–$3,000 Swarm + multi-host shared storage 2–3 days $2,500–$6,000 The cost is calculated individually after auditing your current data and storage infrastructure. Our team has 10+ years of containerization experience and over 100 successful projects, ensuring a reliable outcome. Contact us to evaluate your project and get a consultation from a certified DevOps engineer. Request an audit of your Docker volumes—we will show where the risks are stored and how to eliminate them. Over 50 successful projects—your guarantee of reliability.







