Skip to main content
Back to blog

Understanding Linux file permissions (the stuff that trips people up)

·4 min readLinux

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.md

Reading 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/data

The 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_keys

If 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/Caddyfile

Ownership

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 group

The 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/directory

setgid (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/project

Debugging 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

Enjoying the blog? Subscribe via RSS to get new posts in your reader.

Subscribe via RSS