Ownership and chown
Every Linux file has an owner (a user) and an owning group. The kernel checks ownership first to decide which rwx triplet applies. chown changes owner and group; chgrp changes group alone. Wrong ownership is the most common cause of unexpected permission denials.
You set chmod 755 on a file and your web server still returns 403. You check the permissions — they look right. The problem is almost always ownership: the file belongs to root but the web server runs as www-data, so the server hits the “other” triplet, not the “user” one. Understanding how the kernel picks which rwx triplet to apply — and how to change ownership — is the missing piece that makes permissions actually work.
After this lesson you can read the owner and group from ls -l output, explain which rwx triplet the kernel uses for a given process, and change file ownership with chown user:group file and chgrp group file.
Every file has an owner and a group. ls -l shows them in columns three and four:
ls -l /etc/nginx/nginx.conf-rw-r--r-- 1 root root 2656 Jun 10 09:00 /etc/nginx/nginx.confHere the owner is root and the owning group is also root. The nine permission bits (rw-r--r--, i.e. 644) only make sense once you know who those identities are — because the kernel applies different triplets depending on who is asking.
The kernel picks a triplet using a strict three-step rule. When a process tries to access a file, the kernel checks in order:
- If the process’s effective UID matches the file’s owner → apply the user triplet (bits 2–4).
- Else if the process’s effective GID (or any supplementary group) matches the file’s group → apply the group triplet (bits 5–7).
- Else → apply the other triplet (bits 8–10).
The kernel stops at the first match. This is why a file with mode 640 owned by root:root is completely inaccessible to a non-root user who is not in the root group — they hit the “other” triplet which is ---.
This also means: if you are the owner of a file, your access is determined solely by the user triplet — even if the group triplet would grant more access.
chown changes the owner, the group, or both. You need root (or sudo) to change ownership:
# change owner only
sudo chown alice file.txt
# change group only (colon with empty owner field)
sudo chown :devs file.txt
# change both owner and group at once
sudo chown alice:devs file.txt
# change recursively — use with care
sudo chown -R alice:devs /var/www/myappThe user:group syntax is the most common form. Some older documentation uses user.group (dot) — both work, but colon is standard.
chgrp changes only the group. It exists because unprivileged users can use it to change a file’s group to any group they belong to (without needing sudo):
# alice can do this if she is a member of 'devs'
chgrp devs project.conf
# root can change to any group
sudo chgrp www-data /var/www/html/index.htmlIn practice chown :group file does the same thing, so chgrp is mostly used in scripts where the intent is clear.
Diagnosing a web server 403.
The file /var/www/html/app.conf exists with mode 640. The web server runs as www-data.
ls -l /var/www/html/app.conf-rw-r----- 1 root root 1024 Jun 10 15:00 /var/www/html/app.confMode 640: owner=rw-, group=r--, other=---. The web server (www-data) is not root and not in the root group, so the kernel applies the “other” triplet: ---. No read permission → 403.
Fix: change the group to www-data so the server hits the group triplet (r--):
sudo chown root:www-data /var/www/html/app.conf
ls -l /var/www/html/app.conf-rw-r----- 1 root www-data 1024 Jun 10 15:01 /var/www/html/app.confNow www-data matches the group → group triplet r-- applies → read allowed. The file stays at 640; only the group changed.
▸Why this works
On macOS, chown and chgrp work the same way and the kernel’s three-step ownership check is identical. One macOS-specific note: System Integrity Protection (SIP) prevents even root from changing ownership of certain system files under /System and /usr. On a regular Linux server this restriction does not exist — root can chown anything.
▸Common mistake
A common mistake when deploying apps is running chown -R root:root /var/www/myapp to “secure” the directory, then wondering why the app can’t write its log files. The app process runs as a non-root user (e.g. node or www-data), so every write attempt hits the “other” triplet of ---. The fix is to set the group to the app’s service user and make sure the group triplet allows writes: chown -R root:www-data /var/www/myapp && chmod -R 664 /var/www/myapp/logs.
A file is owned by alice:devs with mode 640. User bob is a member of the devs group. What can bob do with this file?
Every Linux file has an owner (a UID) and a group (a GID). When a process accesses a file the kernel runs a three-step check: does the process UID match the file owner? → use the user triplet. Does any process GID match the file group? → use the group triplet. Otherwise → use the other triplet. The first match wins. chown user:group file changes owner and group in one command; chgrp group file changes the group alone. Wrong ownership — not wrong permissions — is the most common cause of unexpected 403s and permission denials in production.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.