DEV Community

Cover image for Understanding Linux Users, Groups & File Permissions
serverkueche.de
serverkueche.de

Posted on Originally published at serverkueche.de

Understanding Linux Users, Groups & File Permissions

Almost every "Permission denied" message, every container that won't start and every insecure config has the same root cause: a misunderstanding of who is allowed to do what on a Linux server. This guide clears that up for good – with real commands instead of theory.

What are we building?

Not a service this time, but the foundation every other recipe stands on: the Linux permission model. By the end you'll understand what a user and a group are, how to read and set rwx permissions and the numbers like 755, why www-data and docker keep showing up as groups – and when sudo is the right tool and when it isn't. All examples were run on Debian 13 and work on any Linux server.

Prerequisites

  • A Linux server with root or sudo access (your netcup VPS will do)
  • Familiarity with the essential terminal commands (ls, cd, cat)
  • No extra package needed – all tools ship with Debian

Step by step

Step 1: Who am I? Users and their IDs

Every process and every file belongs to a user. Who you currently are is shown by id:

id
Enter fullscreen mode Exit fullscreen mode
uid=0(root) gid=0(root) groups=0(root)
Enter fullscreen mode Exit fullscreen mode

Three things here: the UID (user ID, 0 = root, the administrator), the primary GID (group ID) and every group you're a member of. On Debian, human users get UIDs from 1000 up; below that are system users for services.

Users live in /etc/passwd – a plain text file:

grep -E '^(root|www-data|nobody):' /etc/passwd
Enter fullscreen mode Exit fullscreen mode
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
Enter fullscreen mode Exit fullscreen mode

The fields are name, password placeholder (x = the real hash lives in /etc/shadow), UID, GID, comment, home directory and login shell. Note that www-data – the user web servers run as – has the shell /usr/sbin/nologin. Such service users deliberately can't log in; they exist only so a process runs with minimal privileges instead of as root.

Step 2: Creating a user

For everything except the initial setup you shouldn't work as root. Create a normal user – here cook:

useradd -m -s /bin/bash cook
Enter fullscreen mode Exit fullscreen mode

-m creates the home directory /home/cook, -s /bin/bash sets the login shell. Set a password with passwd cook. Check the result:

id cook
Enter fullscreen mode Exit fullscreen mode
uid=1000(cook) gid=1000(cook) groups=1000(cook)
Enter fullscreen mode Exit fullscreen mode

useradd automatically created a primary group of the same name, cook (GID 1000). That's the Debian default: every user gets their own group – so a new file is never accidentally readable by others just because they share a common group.

Step 3: Reading permissions – the rwx model

Every file carries three sets of permissions: for the owner, for the group and for everyone else. Look at them with ls -l.

Create two quick examples first, so the output below matches your terminal:

cd /tmp && touch datei.txt && mkdir -p ordner
Enter fullscreen mode Exit fullscreen mode

Now look at them:

ls -l
Enter fullscreen mode Exit fullscreen mode
-rw-r--r-- 1 root root  0 Jul 24 19:02 file.txt
drwxr-xr-x 2 root root 40 Jul 24 19:02 folder
Enter fullscreen mode Exit fullscreen mode

The first column is the key. Break down drwxr-xr-x:

  • Character 1 – the type: - file, d directory, l symbolic link.
  • Characters 2–4 (rwx) – the owner's permissions: read (r), write (w), execute (x).
  • Characters 5–7 (r-x) – the group's permissions.
  • Characters 8–10 (r-x) – everyone else's permissions.

Then come the owner (root) and group (root). So for file.txt only root may write, everyone may read.

ℹ️ x means something different on directories

On a file, x means "executable" (a program or script). On a directory, x means "allowed to enter" (cd). A folder without x can't be entered even if you have r – a common trap.

Step 4: Permissions as a number – why 755 and 644

The same permissions are written compactly as an octal number. Each digit stands for one of the three sets, and it's the sum of: read = 4, write = 2, execute = 1.

  • 7 = 4+2+1 = rwx (everything)
  • 6 = 4+2 = rw- (read + write)
  • 5 = 4+1 = r-x (read + execute)
  • 4 = r-- (read only)

That makes the two most common patterns fall out on their own: 644 (rw-r--r--) for normal files and 755 (rwxr-xr-x) for directories and programs. stat shows both notations side by side:

stat -c '%A %a %U %G %n' file.txt folder
Enter fullscreen mode Exit fullscreen mode
-rw-r--r-- 644 root root file.txt
drwxr-xr-x 755 root root folder
Enter fullscreen mode Exit fullscreen mode

Step 5: Setting permissions with chmod

chmod changes permissions – either numerically or symbolically. Numerically you set all three sets at once. This makes a file readable only by owner and group:

chmod 640 file.txt
stat -c '%A %a %n' file.txt
Enter fullscreen mode Exit fullscreen mode
-rw-r----- 640 file.txt
Enter fullscreen mode Exit fullscreen mode

Symbolically you flip individual bits: u (user/owner), g (group), o (others), a (all), with +/-/=:

chmod u+x,g-r file.txt
stat -c '%A %a %n' file.txt
Enter fullscreen mode Exit fullscreen mode
-rwx------ 700 file.txt
Enter fullscreen mode Exit fullscreen mode

⚠️ Never chmod 777

chmod 777 gives everyone on the system full write access – a classic beginner move to quickly "make a permission problem go away". It's almost always the wrong fix and a real security hole. The right answer is to set the correct owner (step 6), not to weaken the permissions.

Step 6: Transferring ownership with chown

Who owns a file is changed with chown – in the format user:group:

chown cook:cook file.txt
stat -c '%A %a %U %G %n' file.txt
Enter fullscreen mode Exit fullscreen mode
-rwx------ 700 cook cook file.txt
Enter fullscreen mode Exit fullscreen mode

For a whole directory tree add -R (recursive) – exactly what you need constantly with Docker volumes when a container has to write as a specific user:

chown -R cook:cook /opt/myapp/data
Enter fullscreen mode Exit fullscreen mode

What happens when the permissions are missing? Create a root-only readable file for this:

echo secret > /tmp/secret.txt && chmod 600 /tmp/secret.txt
Enter fullscreen mode Exit fullscreen mode

Now try to open it as cook:

su - cook -c "cat /tmp/secret.txt"
Enter fullscreen mode Exit fullscreen mode
cat: /tmp/secret.txt: Permission denied
Enter fullscreen mode Exit fullscreen mode

That message is the most common permission error of all – now you know it doesn't mean something is broken, but that the model is working exactly as designed.

Step 7: Groups – shared access

Groups bundle users who should access the same files. A user is added to another group with usermod -aG (append to group):

usermod -aG docker cook
id cook
Enter fullscreen mode Exit fullscreen mode
uid=1000(cook) gid=1000(cook) groups=1000(cook),990(docker)
Enter fullscreen mode Exit fullscreen mode

The -a is crucial: without -a, usermod -G replaces all secondary groups instead of adding one – that's how people accidentally drop out of sudo or docker. Two groups show up constantly:

  • sudo – members may run commands as root by prefixing sudo.
  • docker – members may control Docker. Handy, but security-relevant: access to the Docker socket is effectively root access (see the warning below).

⚠️ A new group is active only after a new login

A freshly assigned group only applies in a new session. After usermod -aG you must log out and back in (or start newgrp docker), otherwise id shows the group but docker ps keeps failing with "permission denied".

Step 8: sudo instead of permanent root

Staying logged in as root is dangerous: one typo wipes half the system, and any compromised process runs with full privileges. The safe way is a normal user in the sudo group who elevates individual commands when needed:

usermod -aG sudo cook
Enter fullscreen mode Exit fullscreen mode

After that, cook runs administrative commands by prefixing sudo (sudo apt update) and is asked for their own password. This is traceable (every action lands in the journal, readable with journalctl -t sudo), reversible and far safer than a permanent root login. This is exactly what Harden SSH builds on when it disables direct root login.

When things go wrong

Permission denied even though the permissions look right. Check the permissions of the parent directory: if it's missing the x bit, you can't reach the file at all, no matter what its own permissions are. ls -ld /path/to/folder shows it.

docker ps still says "permission denied" after usermod -aG docker. The new group isn't active in the current session yet – log out and back in (see the warning box in step 7). id in the new session must show docker.

New files have unexpected permissions. That's set by the umask – it subtracts permissions from the defaults. The Debian default umask 0022 produces 644 for files and 755 for directories. Check it with the umask command (no argument).

A container won't write to the volume. The process inside the container runs under a specific UID (often not root). Set the owner of the host directory to match: chown -R 1000:1000 ./data – the image's docs name the correct UID (environment variables like PUID/PGID).

usermod dropped the user from groups. You used -G without -a. -G replaces the secondary groups. Always use usermod -aG. Repair: re-add the missing groups with usermod -aG group1,group2 user.

Maintenance & backups

  • Permissions rarely need maintenance, but an audit pays off. Occasionally look for world-writable files – a common security leak: find /opt -perm -0002 -type f. Defuse any hits with chmod o-w.
  • The Docker socket is root-equivalent. ls -l /var/run/docker.sock shows ownership root:docker – anyone in the docker group can start containers with the host filesystem mounted and thereby read and write everything. Only add trusted accounts to that group.
  • Backups need to carry the permissions along. When you back up data, make sure ownership and permissions are preserved – restic and rsync -a do this automatically. Otherwise everything belongs to root after a restore and services won't start. How to do it cleanly is shown in Backups with Restic.

This post first appeared on serverkueche.de.

Top comments (0)