chown: changing ownership of '/volume1/docker/myapp/data': Operation not permitted
If you’ve run Docker on a Synology NAS, you’ve seen this error. If you’re like me, you’ve also spent hours trying to fix it before realizing it’s not actually breaking anything.
Docker permissions on NAS devices are different from Docker on a regular Linux server. Here’s everything I learned the hard way.
The Problem
I was setting up ruTorrent containers on my Synology. The compose file looked standard:
services:
rutorrent:
image: crazymax/rtorrent-rutorrent
container_name: rutorrent
environment:
- PUID=1026
- PGID=100
volumes:
- /volume1/docker/rutorrent:/data
ports:
- "8080:8080"
Started the container. Got a wall of permission errors. Container was running anyway. Files were being created with wrong ownership. Authentication wasn’t working. Everything was broken.
Understanding PUID and PGID
Most Docker images that deal with files support PUID and PGID environment variables. These tell the container what user and group ID to use when creating files.
On a standard Linux system, you’d match these to your user:
id username
# uid=1000(username) gid=1000(username) groups=1000(username)
On Synology, user IDs start at 1024 or higher. The default admin user isn’t UID 1000. And there’s a “users” group (GID 100) that most files should belong to.
To find your Synology user’s IDs:
id your_username
# uid=1026(your_username) gid=100(users)
Those are the numbers that go in PUID and PGID. But setting them correctly is only half the battle.
Why chown Fails on Synology
Synology’s DSM uses a modified Linux with extra permission restrictions. Regular users can’t change file ownership, even on files they own. Only root can chown.
Docker containers typically run a startup script that does something like:
chown -R $PUID:$PGID /data
This works on normal Linux. On Synology, it fails with “Operation not permitted” because the container isn’t running as root on the host—it’s running as a user without chown privileges.
The errors are misleading. The container usually still works. It’s just complaining about something it can’t do but doesn’t actually need to do.
The Real Fix: Correct Ownership Before Starting
Instead of letting the container try (and fail) to fix permissions, set them correctly before starting:
# On Synology, via SSH
sudo chown -R 1026:100 /volume1/docker/rutorrent
sudo chmod -R 755 /volume1/docker/rutorrent
Now when the container starts, the files already have the right ownership. The chown command inside the container still fails, but there’s nothing to fix.
The Port Conflict Problem
While debugging permissions, I hit another classic:
Error starting userland proxy: listen tcp4 0.0.0.0:8081: bind: address already in use
Docker couldn’t bind the port because something else was using it. On Synology, many ports are already taken by DSM services you might not know about.
Find what’s using a port:
netstat -tunlp | grep 8081
Or just pick ports above 8100 to avoid conflicts with Synology’s built-in services. I ended up using 8091, 8092, etc. for my containers.
Authentication: htpasswd Files
The ruTorrent image uses htpasswd files for authentication. These need to exist before the container starts, with correct permissions:
# Create password directory
mkdir -p /volume1/docker/rutorrent/passwd
# Generate htpasswd file (using Docker to get htpasswd binary)
docker run --rm httpd:2.4-alpine htpasswd -Bnb myuser mypassword > /volume1/docker/rutorrent/passwd/rutorrent.htpasswd
# Set permissions
sudo chown 1026:100 /volume1/docker/rutorrent/passwd/rutorrent.htpasswd
chmod 644 /volume1/docker/rutorrent/passwd/rutorrent.htpasswd
The -B flag uses bcrypt hashing. The -n flag outputs to stdout instead of updating a file. The -b flag takes the password from the command line (convenient but visible in shell history—use -i for interactive input on production systems).
The Complete Docker Compose
After all the debugging, here’s what actually works:
version: "3.9"
services:
rutorrent:
image: crazymax/rtorrent-rutorrent
container_name: rutorrent
ports:
- "6881:6881/udp"
- "8091:8080"
- "51413:50000"
environment:
- TZ=America/Denver
- PUID=1026
- PGID=100
volumes:
- /volume1/docker/rutorrent/data:/data
- /volume1/docker/rutorrent/downloads:/downloads
- /volume1/docker/rutorrent/passwd:/passwd
restart: unless-stopped
The key differences from a generic setup:
- PUID/PGID match my Synology user (found via
id username) - Ports are above 8100 to avoid Synology conflicts
- Password directory is mounted at
/passwdwhere the image expects it - All directories pre-created with correct ownership
Pre-flight Checklist
Before running any Docker container on Synology:
# 1. Create directories
mkdir -p /volume1/docker/myapp/{data,config}
# 2. Set ownership to your user
sudo chown -R $(id -u):$(id -g) /volume1/docker/myapp
# 3. Set permissions
chmod -R 755 /volume1/docker/myapp
# 4. Find your PUID/PGID
id
# Use these values in docker-compose.yml
# 5. Check for port conflicts
netstat -tunlp | grep :8080
Do this before docker-compose up and you’ll skip most permission headaches.
When Containers Actually Need Root
Some containers legitimately need root access—typically for:
- Binding to ports below 1024
- Accessing hardware devices
- Running system services like VPNs
For these, you might need privileged mode:
services:
vpn-client:
image: some-vpn-image
privileged: true
cap_add:
- NET_ADMIN
But use this sparingly. Most applications don’t need it, and it weakens container isolation.
The Synology-Specific Gotchas
Volume paths are different. Synology uses /volume1/, /volume2/, etc. Not /data or /mnt.
User IDs start higher. Expect UIDs in the 1024+ range, not 1000.
GID 100 is special. The “users” group includes most regular users. Use it unless you have a reason not to.
DSM updates can break things. Major DSM updates sometimes reset Docker configurations. Keep your compose files backed up.
The Docker package location matters. Install Docker from Synology’s Package Center, not manually. It integrates with DSM’s permissions system.
The Debugging Flow
When a container won’t start or behaves strangely:
-
Check the logs first
docker logs container_name -
Verify directory permissions
ls -la /volume1/docker/myapp/ -
Confirm PUID/PGID match
id your_username -
Test port availability
netstat -tunlp | grep :yourport -
Try running interactively
docker run -it --rm image_name /bin/sh
Nine times out of ten, it’s permissions or ports.
The Lesson
Docker permission errors on Synology are usually warnings, not failures. The container is complaining about things it can’t do, but those things often don’t matter if you’ve set up the directories correctly beforehand.
Set ownership before starting containers. Use your actual Synology UID/GID. Pick ports above 8100. And learn to ignore the chown errors that don’t actually break anything.
The ruTorrent containers have been running for months now. The permission errors still appear in the logs every restart. I’ve stopped caring.