|

Why Docker Compose and .env Can Break NFS Bind Mounts

Recently while setting up a Docker Compose-based media stack, I ran into a tricky issue. It looked like everything was working, the containers were up, the mounts were in place, and the files were visible, yet I couldn’t write to my NFS share from inside the containers.

Here’s what happened, and how I fixed it.

What I Was Building

I had a shared NFS mount point at /mnt/data on my Ubuntu Docker host, and I wanted to use environment variables to keep things clean:

In my .env:

# Data Share
DATA=/mnt/data

And in my docker-compose.yml:

volumes:
  - ${DATA}:/data

This approach seemed solid — clean, reusable, and friendly for future automation.

What Looked Right

  • The container started successfully
  • The NFS share mounted properly on the host
  • Inside the container, I could ls /data and see all my files and folders
  • Permissions looked fine on the host: the NFS export mapped to UID/GID 1000, which matched the container user

Where It Broke

Despite being able to browse files, I couldn’t write to the mounted folder inside the container.

Commands like:

touch /data/testfile

would fail with:

Permission denied

What I Discovered

After hours of chasing NFS export settings, UID mapping, and file ownership, I tried one small change that fixed it instantly:

volumes:
  - /mnt/data:/data

Just like that, everything worked — I could read, write, and delete files inside /data from within the container.

The Real Issue

While using environment variables like ${DATA} in volume paths is supported by Docker Compose, they don’t always behave reliably with bind mounts, especially when the host path involves mounted filesystems like NFS.

Even though ${DATA} correctly pointed to /mnt/data

  • Docker Compose resolved the variable
  • Mounted the NFS share correctly
  • But bind permissions didn’t behave as expected when the path came via an environment variable

It’s unclear whether there was a problem with Docker Compose, the NFS client, or how the filesystem is resolved. But using an env variable in the volume path led to silent permission issues, even though everything else appeared fine.

What I Recommend

Use an absolute path for bind mounts

volumes:
  - /mnt/data:/data

It’s simple, reliable, and eliminates variable resolution from the bind mount path.

Final Thoughts

If your container can read but not write to an NFS-mounted volume using an environment variable, try an absolute path instead. It might just save you hours of debugging.

Found this helpful? I share more hands-on fixes and Docker tips from my homelab over on GitHub and here on the blog.

Similar Posts