Every file and directory on Linux has permissions that decide who can read, write and execute it. chmod (change mode) sets them. Getting them right is the difference between a working, secure web server and “403 Forbidden” — or a site anyone can deface.

Reading permissions

ls -l
-rw-r--r-- 1 www-data www-data  4096 Nov  4 10:00 index.php
drwxr-xr-x 2 www-data www-data  4096 Nov  4 10:00 uploads
-rwxr-x--- 1 root     deploy     812 Nov  4 10:00 deploy.sh

The first column breaks down as:

-  rw-  r--  r--
│   │    │    └── others (everyone else)
│   │    └─────── group
│   └──────────── user (owner)
└──────────────── type: - file, d directory, l link

What r, w and x mean

File Directory
r (read) Read the contents List the names inside
w (write) Modify the contents Create, delete, rename entries inside
x (execute) Run it as a program Enter it (cd) and access files inside

The directory rules surprise people:

  • To read /var/www/site/index.html, a user needs x on every directory in the path, plus r on the file.
  • Deleting a file depends on w on the directory, not on the file itself.

Numeric (octal) modes

Each permission has a value: r = 4, w = 2, x = 1. Add them per class:

Number Permissions
7 rwx
6 rw-
5 r-x
4 r–
0 —

Three digits = user, group, others:

chmod 644 index.php        # rw-r--r--  normal files
chmod 755 uploads          # rwxr-xr-x  normal directories, scripts
chmod 600 ~/.ssh/id_ed25519  # rw-------  private keys, secrets
chmod 700 ~/.ssh           # rwx------  private directories
chmod 640 wp-config.php    # rw-r-----  owner writes, group (web server) reads
chmod 750 deploy.sh        # rwxr-x---  owner and group may run it

Symbolic modes

Change specific bits without restating everything:

chmod u+x script.sh        # add execute for the owner
chmod g-w file             # remove write from the group
chmod o-rwx secret.txt     # remove everything for others
chmod a+r file             # add read for all (user, group, others)
chmod u=rw,go=r file       # set exactly: same as 644
chmod +x script.sh         # execute for everyone (respecting umask)

u user, g group, o others, a all; + add, - remove, = set exactly.

Recursive changes — carefully

chmod -R 755 /var/www/site makes every file executable, which is wrong for files. Treat files and directories separately with find:

find /var/www/site -type d -exec chmod 755 {} +
find /var/www/site -type f -exec chmod 644 {} +

Or use the capital X, which adds execute only to directories (and files already executable by someone):

chmod -R u=rwX,go=rX /var/www/site

Why chmod 777 is (almost) never the answer

777 gives everyone on the system full control. On a web server, that means any compromised process — another site, a vulnerable plugin — can modify your files and plant malware. When something “only works with 777”, the real problem is ownership: the web server user doesn’t own the directory it needs to write to. Fix that with chown instead:

sudo chown -R www-data:www-data /var/www/site/wp-content/uploads
sudo chmod 755 /var/www/site/wp-content/uploads
Path Mode Notes
Directories 755 or 750 if others needn’t access
Files 644 or 640
Config with secrets (wp-config.php, .env) 640 or 600 readable by the app only
Upload/cache directories 755, owned by the web server user
Scripts 750

See also WordPress file permissions.

SSH is strict about permissions

OpenSSH refuses keys with loose permissions, with errors like UNPROTECTED PRIVATE KEY FILE! or a silent fallback to password login:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys ~/.ssh/id_*
chmod 644 ~/.ssh/*.pub

Your home directory must not be group- or world-writable either. Details in SSH “Permission denied (publickey)”.

Special bits: setuid, setgid, sticky

A fourth, leading digit sets special permissions:

chmod 2775 /srv/shared     # setgid on a directory: new files inherit the group
chmod 1777 /tmp            # sticky bit: users can delete only their own files
chmod 4755 /usr/bin/passwd # setuid: runs as the file's owner (root)

The setgid directory is handy for team folders. Setuid binaries are a security risk — audit them with find / -perm -4000 -type f. More in setuid, setgid and sticky bit.

Default permissions: umask

New files get permissions from the umask, typically 022 → files 644, directories 755. umask 027 gives 640/750. See umask explained.

Useful options

chmod -v 644 file          # verbose: print each change
chmod -c -R u+rwX dir      # print only files actually changed
chmod --reference=a.txt b.txt   # copy a.txt's mode to b.txt
stat -c '%a %n' *          # show numeric modes

Learn the full model in Linux file permissions explained. The safest place to practise is a scratch server — any Linux VPS can be reinstalled in minutes if you break something.

  • Linux
  • Permissions
  • Command Line