Mounting QNAP NFS by filesystem path re-owned every file on another share

An NFS mount using the QNAP filesystem path instead of the export name resolved to a different share, and an image that runs chown -R at startup re-owned almost everything on it. How to mount correctly, how to verify by inode, and why to keep the chown output.

A container image started, ran its usual chown -R on the directory it thought was its data, and quietly re-owned nearly every file of every other application on the same NAS share. Nothing crashed. I found out because something else stopped being able to read its own files.

The mount that lied

My Paperless volumes were defined as <nas>:/share/MD0_DATA/Paperless/.... On a QNAP with NFSv3 that is not an export path. The export is called /Paperless, and the long form is the underlying filesystem path. The server still answered, but it resolved the path to the root of a different share, the one that held my Docker data. The Paperless image and the official Postgres image both walk their mount at startup with find ... -exec chown, so the walk re-owned that other share’s tree to the container user.

The real Paperless data was fine, because it had never been mounted. Every other app’s files on the share were not.

It was not consistent

Which directory the odd path resolved to changed with server state. First it was another share’s root; later it was the right share’s root with the sub-path ignored. That happened with and without nosharecache, through Docker’s local NFS driver and through mount.nfs on the command line. Treat a path that “works” this way as undefined rather than as slightly wrong.

What to do instead

Mount by export name: <nas>:/<Share>. Ask the NAS which shares it exports and use exactly those names. My fstab and Ansible mounts had the same long form for other shares, so they carried the same risk and were on the fix list.

Verify by inode, not by findmnt

/proc/mounts and findmnt print the device string you asked for, which tells you nothing about what the server resolved it to. Compare stat -c %i on a directory you know exists in the tree you meant. If the inode is not the one you see when you look at the share on the NAS, you are looking at something else.

Keep the evidence

The only record of what got re-owned is the container’s own --changes output, and docker compose down deletes it together with the container. If an image chowns its data at startup, run the first start with that output going somewhere permanent.

Those two images are not unusual. Many images chown their volume on start, so a mount that points at the wrong tree is a much bigger event than a wrong path usually is.