chmod 755 vs 644: Linux Permissions for Web Servers
"Set directories to 755 and files to 644" is the most repeated advice in web hosting, and it's right. But knowing why is what lets you fix the cases where it isn't enough — and stops you reaching for chmod 777.
Reading the numbers
Each digit is a sum of three bits: read is 4, write is 2, execute is 1. The three digits apply, in order, to the file's owner, its group, and everyone else.
| Mode | Owner | Group | Others | ls -l |
|---|---|---|---|---|
| 755 | read, write, execute | read, execute | read, execute | rwxr-xr-x |
| 644 | read, write | read | read | rw-r--r-- |
The only difference between them is the execute bits — and execute means something different for files and for directories.
Execute means two different things
On a file, execute means "may run this as a program". HTML, CSS, images and PHP files don't need it: the web server reads them (PHP is read and interpreted by PHP-FPM, not run by the kernel). Leaving execute off ordinary files means a stray upload can't be run directly.
On a directory, execute means "may enter it and reach things inside". Read on a directory only lets you list the names; without execute you can't open any file inside, even one you're allowed to read. That's why directories need 755 — and why chmod -R 644 on a site makes everything vanish behind 403 errors.
So 755 on directories lets the web server walk the tree, and 644 on files lets it read them. Only the owner can change anything.
Fixing a whole tree properly
chmod -R applies one mode to files and directories alike, which is never what you want here. Use find to treat them separately:
find /var/www/site -type d -exec chmod 755 {} +
find /var/www/site -type f -exec chmod 644 {} +
Then tighten anything holding secrets — .env, wp-config.php, database credentials — to 640, readable by the web server's group, or 600, owner only.
When 755 and 644 aren't enough
The classic case: the app needs to write — uploads, caches, generated thumbnails — and gets "Permission denied". The tempting fix is 777. The right fix is almost always ownership:
# Let the web server's group write to the uploads directory
sudo chown -R deploy:www-data /var/www/site/uploads
sudo chmod 2775 /var/www/site/uploads
2775 gives the group write access, and the setgid bit — the leading 2 — makes new files inherit the www-data group, so permissions stay consistent as files are created.
Why not 777?
777 lets every account and every process on the machine modify the files. On a web server, that means a compromised plugin, a misbehaving cron job, or another tenant on shared hosting can rewrite your code. It "fixes" permission errors only by removing all protection.
If you're tempted, find the real problem instead:
- The app runs as a different user from the files' owner?
chownthe files, or add the app's user to the owner's group. - Several people deploy? Use a shared group, with 2775 directories and 664 files.
- A scratch directory everyone writes to? Use 1777, like
/tmp, so users can't delete each other's files.
Quick reference
| Path | Mode |
|---|---|
| Directories | 755 (750 if others needn't read) |
| Regular files | 644 |
| Executable scripts | 755 |
| Writable upload or cache directories | 2775, with a shared group |
Secrets (.env, keys) |
600 or 640 |
~/.ssh |
700, with private keys at 600 |
Work out any other combination with the chmod calculator.