File permissions are a fundamental Linux security mechanism. Wrong permissions can leak config files with passwords or let an attacker execute code.
Numeric chmod notation
| Number | Permissions | Use case |
|---|---|---|
| 777 | rwxrwxrwx | Never! Dangerous |
| 755 | rwxr-xr-x | Directories, scripts |
| 644 | rw-r--r-- | HTML, PHP files |
| 600 | rw------- | Private keys, config files |
| 400 | r-------- | Read-only for the owner |
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;
chmod u+x script.sh
chmod g-w config.php
chown -R www-data:www-data /var/www/site/
Symbolic notation and common mistakes
Symbolic notation changes permissions relative to the current ones instead of setting them all at once: chmod u+x adds execute permission for the owner without touching group or other permissions. This is more convenient than numeric notation when you only need to change one bit without first finding out the current value of the rest.
The letters u, g, o and a stand for the owner (user), the group, others, and everyone at once (all); the signs +, - and = add, remove or set permissions exactly. For example, chmod go=r file sets group and others to exactly read permission, whatever the previous value was.
Mistake: chmod -R 777 as a quick fix
Recursive 777 on the whole site directory "to finally make it work" opens write access to any system user, including the web server of other sites on the same host and any process that gains access to the system. The right approach is to find who actually lacks permissions (usually the owner of the web server process) and grant access precisely through chown or ACL, not to everyone at once.
Mistake: identical permissions for files and directories
Execute permission (x) on a directory means the right to enter it and open files by name — it is not the same as running a program, as it is for a file. A directory with 644 instead of 755 will not let you into it even with correct permissions on the files inside, while a script file with 755 when 644 was needed allows it to be executed if the web server is configured to execute files by extension.
Special bits: SUID, SGID, Sticky
# SUID - run with the file owner's permissions
chmod u+s /usr/bin/program # chmod 4755
# ls: -rwsr-xr-x
# SGID - inherit the directory's group
chmod g+s /shared/dir # chmod 2755
# Sticky bit - only the owner can delete the file
chmod +t /tmp # chmod 1777
# ls: drwxrwxrwt
# Find SUID files (potential risk)
find / -perm -4000 -type f 2>/dev/null
ACL - extended permissions
apt install acl -y
setfacl -m u:deploy:rw /var/www/config.php
setfacl -Rm g:devteam:rwx /var/www/project/
getfacl /var/www/config.php
setfacl -b /var/www/config.php # Remove ACL
chmod or ACL: which to choose
| Task | Regular chmod/chown | ACL |
|---|---|---|
| A single owner and a single group | Enough | Overkill |
| Access for several users with different permissions on one file | Not expressible | Fits - a separate entry for each |
| Default permissions for new files in a shared directory | Only through SGID on the group | Default ACL sets exact permissions for several entities at once |
When ACL will not work
- The filesystem is mounted without the
acloption — most modern ext4 filesystems enable it by default, but old entries in/etc/fstabor network mounts may not set it explicitly. - Some network filesystems and old versions of NFS support ACL only partially or not at all — permissions then apply only at the regular chmod level.
- Archivers and copy tools without special flags (for example, plain
cpwithout--preservein some cases) may not carry ACL entries along with the file — check withgetfaclafter moving important files to a new location.
Verifying the result
- Run
stat -c "%a %U %G" /var/www/site/config.php— the numeric permissions and the owner should match what you set. - For ACL, run
getfacl fileand confirm the expecteduser:orgroup:entry is present in the output. - Try logging in as an unprivileged user and reading a file with
600permissions owned by someone else — access should be denied. - After a recursive permission change, spot-check several files and directories with
ls -larather than just the top-level directory — recursive commands sometimes stumble on files with unusual names.
File permissions are only one layer of server security; tracking who changed them and when is covered in auditing events with auditd, and additional access separation at the process level is covered in setting up SELinux and AppArmor.