Understanding Linux file permissions (the stuff that trips people up)
File permissions cause more headaches in self-hosting than almost anything else. A Docker container that cannot write to a volume, a web server that cannot read its config, a backup script that silently fails. Nine times out of ten, it is a permissions issue.
The basics
Every file and directory on Linux has three sets of permissions for three types of users:
- Owner (u): the user who owns the file
- Group (g): members of the file's group
- Others (o): everyone else
Each set has three permission types:
- Read (r = 4): view the file or list directory contents
- Write (w = 2): modify the file or create/delete files in a directory
- Execute (x = 1): run the file as a program or access a directory
ls -la
# drwxr-xr-x 3 jeremy users 4096 Mar 15 10:00 projects
# -rw-r--r-- 1 jeremy users 842 Mar 15 10:00 readme.mdReading this: drwxr-xr-x means directory, owner has rwx, group has r-x, others have r-x.
Numeric notation
Each permission is a number: read=4, write=2, execute=1. Add them up for each set:
755= owner rwx (7), group r-x (5), others r-x (5)644= owner rw- (6), group r-- (4), others r-- (4)700= owner rwx (7), group --- (0), others --- (0)
chmod 755 script.sh # Owner can do everything, others can read and execute
chmod 644 config.yaml # Owner can read/write, others can only read
chmod 600 .env # Only owner can read/write (good for secrets)Common mistakes
Docker volume permissions. A container runs as a specific user (often root or a custom user like www-data with UID 33). If the host directory is owned by your user (UID 1000), the container might not be able to write to it:
# Fix: match the ownership to the container's user
sudo chown -R 33:33 /path/to/nextcloud/data
# Or: set broad permissions (less secure, fine for development)
chmod -R 777 /path/to/dataThe 777 approach works but gives everyone full access. For production, match the UID instead.
SSH key permissions. SSH refuses to use keys that are too permissive:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keysIf SSH says "Permissions 0644 for '/home/user/.ssh/id_ed25519' are too open," this is why.
Web server config. Nginx and Caddy need to read config files but should not be able to write to them:
chmod 644 /etc/caddy/Caddyfile
chown root:root /etc/caddy/CaddyfileOwnership
Every file has an owner and a group. Change them with chown:
chown jeremy:users file.txt # Set owner and group
chown -R jeremy:users ./project/ # Recursive (all files in directory)
chown :docker /var/run/docker.sock # Change only the groupThe sticky bit, setuid, and setgid
You will occasionally encounter these special permissions:
Sticky bit (t): on a directory, only the file owner can delete their files. /tmp uses this so users cannot delete each other's temp files.
chmod +t /shared/directorysetgid (s on group): files created in the directory inherit the directory's group. Useful for shared directories where multiple users need access.
chmod g+s /shared/projectDebugging permission issues
When something is not working, check these three things:
# 1. Who owns the file?
ls -la /path/to/file
# 2. What user is the process running as?
ps aux | grep process-name
# 3. Can that user read/write/execute the file?
sudo -u username test -r /path/to/file && echo "readable" || echo "not readable"Most permission problems come down to a mismatch between the user running a process and the owner of the files it needs to access.
Sources
Related posts
Setting up a productive dev environment on Linux
The actual tools, terminal setup, and configuration I use for web development on Linux.
Why I use Linux for web development
My case for using Linux as a web development environment, and the practical advantages it has over Windows.
Why Pop!_OS is my Linux distro of choice
What makes Pop!_OS stand out as a Linux distribution for developers, and why I chose it over Ubuntu, Fedora, and Arch.
Enjoying the blog? Subscribe via RSS to get new posts in your reader.
Subscribe via RSS