After uploading a website, unpacking an archive or copying files from Windows, permissions are often a mess: some files executable, some folders unreadable. A plain chmod -R cannot fix this, because files and folders need different values. This guide shows how to set folders and files separately across a whole tree, safely.
Before you start
- A Linux VPS with Ubuntu 22.04 or 24.04, Debian 12, or AlmaLinux or Rocky Linux 8 or 9.
- An SSH session with sudo, or as the owner of the files.
- The exact path of the folder to fix, for example
/var/www/example.com. - Ideally, a backup of the folder. See Back up a config before editing for quick copy habits.
Warning: These commands change every file under the path you give. A typo that points them at / or /etc can break the server and lock you out. Type the full path, check it, and never run them from a folder you have not confirmed with pwd.
Why one chmod -R is not enough
Folders need the execute bit so users and services can enter them. Regular files almost never need it. So:
chmod -R 644 site/stripsxfrom folders. Nothing below the top can be reached, and the site returns 403 errors.chmod -R 755 site/makes every file executable. That is untidy and, for uploads, a security risk.
The usual target is 755 for directories and 644 for files, with tighter values for secrets.
Method 1: find with -type
find can select only directories or only files, and run chmod on each set.
Set all directories to 755:
find /var/www/example.com -type d -exec chmod 755 {} +Set all regular files to 644:
find /var/www/example.com -type f -exec chmod 644 {} +-type dmatches directories and-type fmatches regular files.-exec chmod... {} +passes many paths to eachchmodcall, which is much faster than one call per file.
Add sudo in front if the files belong to another user.
Dry run first
See what will be touched before changing anything. These commands only list:
find /var/www/example.com -type d | wc -l
find /var/www/example.com -type f ! -perm 644 | headThe second command shows files that do not already have 644, so you can see the scale of the change.
Method 2: chmod with capital X
The capital X adds execute only to directories, and to files that already have execute for someone. One command gives folders 755 and plain files 644:
chmod -R u=rwX,go=rX /var/www/example.comIt is fast and easy to remember. The catch is that a file that was wrongly executable stays executable. After an upload from Windows, where everything may arrive as 777, use Method 1, or strip x first:
chmod -R a-x,u=rwX,go=rX /var/www/example.coma-x removes execute everywhere, then X adds it back to directories only.
Keep scripts executable
Some files need x, such as shell scripts or binaries in a bin folder. Restore them after the bulk change:
find /var/www/example.com/bin -type f -exec chmod 755 {} +
chmod 755 /var/www/example.com/deploy.shTighten secrets
Config files with passwords should not be readable by everyone. Set them explicitly after the bulk change:
chmod 640 /var/www/example.com/.env
chmod 640 /var/www/example.com/wp-config.phpWith 640, the owner can edit and the group, usually the web server group, can read. Make sure the group is right with chown. More detail for WordPress is in WordPress file permissions.
Skip parts of the tree
To leave a folder alone, such as .git or a cache, prune it:
find /var/www/example.com -path /var/www/example.com/.git -prune -o -type f -exec chmod 644 {} +Everything except .git gets 644.
Fix ownership at the same time
Permissions only make sense with the right owner. A typical web root:
sudo chown -R deploy:www-data /var/www/example.comUse nginx or apache in place of www-data on AlmaLinux and Rocky. The full picture is in chown: change file owner and group.
Check it works
Count anything that does not match the target values. Both commands should print 0:
find /var/www/example.com -type d ! -perm 755 | wc -l
find /var/www/example.com -type f ! -perm 644 | wc -lFiles you set on purpose, such as scripts or .env, will show up in the second count. That is expected. Finally, load the site in a browser and confirm pages and images load.
Troubleshooting
- 403 Forbidden after the change: a folder lost its
xbit, or a parent folder above the web root is too strict. Check the whole path withnamei -l /var/www/example.com/index.html. - find says "missing argument to -exec": the command is missing
{} +or\;at the end. Copy it again exactly. - "Operation not permitted" on some files: they belong to another user. Run the command with
sudo. - A script stopped running: it lost
x. Restore it withchmod 755 script.sh. - Uploads fail after the fix: the web server needs write access to the uploads folder. Grant it to the group with
chmod 775on that folder only.
Next steps
- Make new files arrive with the right values: umask: control default permissions.
