Skip to content
Serverküche
Search

Loading search … (only available on the published site).

Basics Difficulty: Beginner

Understanding Linux Users, Groups & File Permissions

Who is allowed to do what on your server? This foundational guide explains users, groups and file permissions with real commands – the basis of every setup.

· 8 min read ·Duration: approx. 25 minutes
Table of contents

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

🍳 Recommendation Ad

VPS 1000 G12

4 vCores · 8 GB RAM · 256 GB NVMe

from €10.36/month

Any server works for practice – the commands are the same on every Linux.

Go to netcup →

💶 5 € voucher for new netcup customers:36nc17844976032 (new customers only, no domains)

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:

Terminal
id
Ausgabe
uid=0(root) gid=0(root) groups=0(root)

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:

Terminal
grep -E '^(root|www-data|nobody):' /etc/passwd
Ausgabe
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

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:

Terminal
useradd -m -s /bin/bash cook

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

Terminal
id cook
Ausgabe
uid=1000(cook) gid=1000(cook) groups=1000(cook)

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:

Terminal
ls -l
Ausgabe
-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

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:

Terminal
stat -c '%A %a %U %G %n' file.txt folder
Ausgabe
-rw-r--r-- 644 root root file.txt
drwxr-xr-x 755 root root folder

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:

Terminal
chmod 640 file.txt
stat -c '%A %a %n' file.txt
Ausgabe
-rw-r----- 640 file.txt

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

Terminal
chmod u+x,g-r file.txt
stat -c '%A %a %n' file.txt
Ausgabe
-rwx------ 700 file.txt

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:

Terminal
chown cook:cook file.txt
stat -c '%A %a %U %G %n' file.txt
Ausgabe
-rwx------ 700 cook cook file.txt

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:

Terminal
chown -R cook:cook /opt/myapp/data

What happens when the permissions are missing? Opening a root-only file as cook:

Terminal
su - cook -c "cat /tmp/secret.txt"
Ausgabe
cat: /tmp/secret.txt: Permission denied

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):

Terminal
usermod -aG docker cook
id cook
Ausgabe
uid=1000(cook) gid=1000(cook) groups=1000(cook),990(docker)

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:

Terminal
usermod -aG sudo cook

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 /var/log/auth.log), 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.

You might also like

Restic backups: encrypted and off-site
Security Intermediate

Restic backups: encrypted and off-site

Off-site backups with Restic: set up encrypted, restore snapshots, prune with retention and automate via a systemd …

· 12 min read