
Linux Permissions: chmod and chown
Senior dev said 'just chmod 777 it'. Turns out, that was reckless advice. Secrets of rwx and numbers.

Senior dev said 'just chmod 777 it'. Turns out, that was reckless advice. Secrets of rwx and numbers.
Why does my server crash? OS's desperate struggle to manage limited memory. War against Fragmentation.

Two ways to escape a maze. Spread out wide (BFS) or dig deep (DFS)? Who finds the shortest path?

A comprehensive deep dive into client-side storage. From Cookies to IndexedDB and the Cache API. We explore security best practices for JWT storage (XSS vs CSRF), performance implications of synchronous APIs, and how to build offline-first applications using Service Workers.

Fast by name. Partitioning around a Pivot. Why is it the standard library choice despite O(N²) worst case?

During my Linux newbie days, Permission denied haunted me everywhere.
Tried to read a file? Denied. Run a script? Denied. Even entering a directory? Denied.
My senior dev taught me a magic spell: "Just chmod 777 it when things don't work."
It worked like a charm. I thought that was the solution. (Until the Security Team ripped me apart.)
Looking back, I cringe. chmod 777 was basically "leaving my front door wide open with the password taped to the doorframe."
Docker volume mounts kept throwing permission errors.
Couldn't write logs, couldn't read config files. I kept patching things with sudo, but I realized "If I don't understand this properly, I'll keep hitting the same wall."
So I dug into Linux permissions. What rwx means, what 755 signifies, the difference between chmod and chown. Once the fog cleared, I could look at an error message and instantly know, "Ah, permission issue."
Running ls -l shows this:
-rw-r--r-- 1 ubuntu dev 1024 Feb 6 12:34 config.txt
drwxr-xr-x 2 ubuntu dev 4096 Feb 6 12:35 logs
It seemed like there was a pattern, but it looked like alien code.
What's -rw-r--r--? Why the number 1024? What's ubuntu dev?
The most confusing part: x permission on directories. "You need execute permission to enter a directory" didn't make sense at first. Directories aren't programs, so why do they need execute permission?
And why chmod 644 is fine but chmod 777 is dangerous wasn't immediately obvious.
Thinking of the Linux file system as an apartment building made everything clear.
This 3-tier structure is the essence of Linux permissions.
In Linux, there are exactly 3 actions you can perform on a file or directory:
ls.cd).Without x permission on a directory, you can't cd into it. This clicked for me when I thought: "If you don't have entry clearance to an apartment hallway, you can't enter no matter what's inside."
Converting rwx to numbers seemed magical at first, but it boiled down to this:
You just add them up.
rwx = 4 + 2 + 1 = 7 (read, write, execute all allowed)rw- = 4 + 2 + 0 = 6 (read, write only, no execute)r-x = 4 + 0 + 1 = 5 (read, execute only, no write)r-- = 4 + 0 + 0 = 4 (read only)--- = 0 + 0 + 0 = 0 (no access)For example, 755 means:
Conversely, when I see -rwxr-xr-x in ls -l, I immediately know: "Ah, 755 permissions."
$ ls -l
-rw-r--r-- 1 ubuntu dev 1024 Feb 6 12:34 config.txt
drwxr-xr-x 2 ubuntu dev 4096 Feb 6 12:35 logs
-rwxr-xr-x 1 ubuntu www 12288 Feb 6 12:36 deploy.sh
Breaking down each column:
- is file, d is directory.rwx in chunks of 3 (Owner / Group / Others).ubuntu dev - owner and group.config.txt has rw-r--r-- (644):
logs directory has rwxr-xr-x (755):
deploy.sh script has rwxr-xr-x (755):
Most straightforward approach.
$ chmod 755 deploy.sh
# Owner: rwx(7), Group: r-x(5), Others: r-x(5)
$ chmod 644 config.txt
# Owner: rw-(6), Group: r--(4), Others: r--(4)
$ chmod 600 ~/.ssh/id_rsa
# SSH private key should only be readable/writable by owner
# Group and Others: ---(0)
If SSH key permissions are wrong, SSH will refuse with "permissions are too open" error. Actually running chmod 644 ~/.ssh/id_rsa causes ssh to throw "UNPROTECTED PRIVATE KEY FILE!" errors.
Use when you want to modify only part of existing permissions.
$ chmod u+x script.sh
# Add eXecute permission for User (owner)
$ chmod g-w config.txt
# Remove Write permission from Group
$ chmod o-rwx secret.txt
# Remove all permissions from Others
$ chmod a+r readme.txt
# Add Read permission for All (owner+group+others)
u = User (Owner)
g = Group
o = Others
a = All
+ = Add permission
- = Remove permission
= = Set permission (ignoring existing)
For example:
$ chmod u=rwx,g=rx,o=r script.sh
# Owner: rwx, Group: r-x, Others: r--
# Numerically equivalent to 754
To apply to all files/directories inside a folder, use -R option.
$ chmod -R 755 /var/www/html
# Set entire web server directory to 755
Warning: -R is powerful and dangerous. Misuse can break system file permissions.
$ chown ubuntu config.txt
# Change owner of config.txt to ubuntu
$ chown ubuntu:dev config.txt
# Owner becomes ubuntu, Group becomes dev
$ chown :www deploy.sh
# Change only Group to www (owner unchanged)
Nginx or Apache web servers typically run as the www-data user.
$ sudo chown -R www-data:www-data /var/www/html
$ sudo chmod -R 755 /var/www/html
This ensures:
If the web server needs to write log files:
$ sudo chown www-data:www-data /var/log/nginx
$ sudo chmod 755 /var/log/nginx
Instead of chown :group, you can use chgrp.
$ chgrp dev config.txt
# Change group of config.txt to dev
In practice, chown :dev config.txt is more commonly used.
Files created inside a Docker container sometimes become inaccessible from the host.
$ docker run -v $(pwd)/data:/app/data myapp
# Creates /app/data/output.log inside container
The container runs as root, but on the host I'm the ubuntu user, causing a permission conflict.
Solution:
# In Dockerfile, specify user
RUN useradd -m -u 1000 appuser
USER appuser
Or from the host:
$ sudo chown -R $(whoami):$(whoami) ./data
After several rounds of this struggle, the concept "container and host UID/GID must match" finally clicked.
When a file is executed, it runs with the owner's permissions.
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 /usr/bin/passwd
See that s? That's SUID.
The passwd command needs to modify /etc/shadow, which only root can write. Thanks to SUID, when a regular user runs passwd, it executes with root privileges, allowing password changes.
$ chmod u+s script.sh
# Or
$ chmod 4755 script.sh
Prepend 4 to enable SUID.
When a file is executed, it runs with the group's permissions. When applied to a directory, all files created inside inherit the directory's group.
$ chmod g+s shared_folder
# Or
$ chmod 2755 shared_folder
Prepend 2 to enable SGID.
For example, a team project folder:
$ mkdir /project
$ chgrp dev /project
$ chmod 2775 /project
Now, no matter who creates a file inside /project, its group automatically becomes dev.
When set on a directory, only the file owner can delete files inside.
The /tmp directory is a classic example.
$ ls -ld /tmp
drwxrwxrwt 10 root root 4096 /tmp
See that t at the end? That's the Sticky bit.
Anyone can create files in /tmp, but you can't delete someone else's files.
$ chmod +t shared_folder
# Or
$ chmod 1777 shared_folder
Prepend 1 to enable Sticky bit.
When you create a new file, it has automatically applied permissions. That's umask.
$ umask
0022
umask works by "subtraction."
666 (rw-rw-rw-)777 (rwxrwxrwx)umask 0022 means:
Let's verify:
$ umask 0022
$ touch newfile.txt
$ mkdir newfolder
$ ls -l
-rw-r--r-- 1 ubuntu dev 0 newfile.txt
drwxr-xr-x 2 ubuntu dev 4096 newfolder
Exactly 644 and 755.
If you change to umask 0077:
$ umask 0077
$ touch private.txt
$ ls -l private.txt
-rw------- 1 ubuntu dev 0 private.txt
Now only the owner can read and write.
umask is typically set in ~/.bashrc or ~/.zshrc.
# ~/.bashrc
umask 0022
SSH private keys must have 600 permissions.
$ chmod 600 ~/.ssh/id_rsa
$ ls -l ~/.ssh/id_rsa
-rw------- 1 ubuntu ubuntu 1679 ~/.ssh/id_rsa
If permissions are wrong:
$ chmod 644 ~/.ssh/id_rsa
$ ssh user@server
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/ubuntu/.ssh/id_rsa' are too open.
SSH enforces "private keys must not be exposed to others," so it outright rejects loose permissions.
Public keys can be 644.
$ chmod 644 ~/.ssh/id_rsa.pub
Suppose you're running an Nginx web server.
$ sudo chown -R www-data:www-data /var/www/html
$ sudo find /var/www/html -type f -exec chmod 644 {} \;
$ sudo find /var/www/html -type d -exec chmod 755 {} \;
This ensures:
644 (owner can write, others read-only)755 (owner can write, others read+enter)If the web server needs to write to an uploads folder:
$ sudo chmod 775 /var/www/html/uploads
$ sudo chown www-data:www-data /var/www/html/uploads
Now the web server can write files to the uploads directory.
777 means "Anyone can read, write, delete, and execute freely."
For example, if a web server config file is 777:
$ chmod 777 /etc/nginx/nginx.conf
This means:
nginx.conf and inject malicious code.x permission, they can even execute scripts.I once got frustrated with Permission denied errors in a Docker container and lazily ran chmod -R 777 /app.
Security Team found it during log analysis and interrogated "Who did this?" It was embarrassing.
Stick to:
644 (owner can write)755 (owner can write, others can execute)600 (owner read/write only)These are the best practices.
cd won't work.Once these concepts solidified, whenever I see Permission denied, I can immediately think "Check file permissions" or "Verify container UID matches" and respond accordingly.