A practical guide to linux file permissions and chmod explained with examples.
You deploy a script, it fails with "Permission denied," and your first instinct is chmod 777 because it makes the error go away. It does — and now any user on that machine can read, write, and execute the file. On a shared server or a container with a compromised process, that's a real hole, not a shortcut. Understanding what the permission bits actually mean takes ten minutes and removes the temptation entirely.
ls -l deploy.sh
# -rwxr-xr-- 1 nitheesh staff 812 Sep 12 10:03 deploy.sh
Break -rwxr-xr-- into four groups:
- — file type (- = regular file, d = directory, l = symlink)rwx — owner's permissions (read, write, execute)r-x — group's permissions (read, execute — no write)r-- — everyone else's permissions (read only)So nitheesh can edit and run this script, anyone in the staff group can run it but not edit it, and everyone else can only view it.
chmod u+x deploy.sh # add execute for the owner
chmod g-w deploy.sh # remove write for the group
chmod o=r deploy.sh # set "others" to read-only, exactly
chmod a+r deploy.sh # add read for everyone (a = all)
This is usually clearer than numeric mode when you're making a targeted change, since it reads like what it does.
Each permission is a bit: read = 4, write = 2, execute = 1. Add them per group:
chmod 755 deploy.sh
# owner: 7 = rwx (4+2+1)
# group: 5 = r-x (4+0+1)
# other: 5 = r-x (4+0+1)
chmod 644 config.json
# owner: 6 = rw- (4+2+0)
# group: 4 = r-- (4+0+0)
# other: 4 = r-- (4+0+0)
755 is the standard mode for executable scripts and directories. 644 is standard for regular files that shouldn't be executable — config files, source code, data files.
chmod 777 deploy.sh
# rwxrwxrwx — literally everyone can read, edit, and run this file
On a single-user dev machine this is mostly harmless. On a shared server, in a Docker image, or on anything internet-facing, it means any process running as any other user — including a compromised web app on the same box — can modify the file. The "permission denied" error you were fixing is almost always solved by chmod +x (adding execute for the owner) or fixing actual ownership with chown, not by opening everything to everyone.
chown nitheesh:staff deploy.sh # set owner and group
sudo chown www-data:www-data /var/www/app # common web server pattern
Permission bits are meaningless without knowing who they apply to. A file owned by root with 644 permissions can't be edited by your deploy user even though 644 "looks" reasonable — because your user falls into the "other" bucket, which only has read access.
This confuses people coming from other OSes: on a directory, the execute bit doesn't mean "run it," it means "you can cd into it and access files inside by name."
chmod 755 mydir # can list, enter, and traverse
chmod 644 mydir # can list contents, but NOT cd into it — usually not what you want
777 (or chmod -R 777) as a generic fix for permission errors, instead of diagnosing what's actually wrong — usually wrong ownership or a missing execute bit.chmod -R recursively without realizing it applies the same mode to both files and directories, which often breaks directory traversal (files don't need execute; directories do).chmod (permission bits) with chown (ownership) — "permission denied" is often actually an ownership problem, not a mode problem.chmod 4755) without understanding they let a script run with the file owner's privileges regardless of who executes it — a real privilege escalation risk if misused.755 for executables and directories, 644 for everything else, and fix ownership with chown before ever reaching for broader permissions. If something genuinely needs group-shared write access, use a shared group and chmod 664/775 rather than opening it to the entire system with 777.
Run find /path/to/project -perm -o+w to find any world-writable files in your project — that's a quick audit for accidental 777s left over from past "just make it work" fixes.