Master Linux File Permissions: How to Use chmod and chown Effectively
This comprehensive guide explains Linux's permission model, demonstrates numeric and symbolic chmod usage, details chown operations, introduces ACL for fine‑grained control, and provides troubleshooting steps and security best practices for production environments.
Background and Scenarios
Linux is a multi‑user operating system where file‑permission management is the foundation of system security. Correct permissions prevent unauthorized access, limit user actions, and protect sensitive data on everything from personal VPS instances to large enterprise servers.
Part 1: Core Permission Model
Basic Permission Model
Each file has three sets of permissions: Owner (u) , Group (g) , and Others (o) . Each set contains three bits: read (r = 4), write (w = 2), and execute (x = 1). Example output of ls -l /var/log/syslog shows the breakdown of these bits and the file type indicator.
ls -l /var/log/syslog
-rw-r----- 1 syslog adm 12345 May 29 10:30 /var/log/syslogPermission and Directory Relationship
For files, r allows reading content, w allows modifying, and x allows execution. For directories, r lists filenames, w creates/deletes/renames entries, and x permits entering the directory. The write bit on a directory controls deletion regardless of the file’s own permissions.
Default Permissions and umask
When a new file or directory is created, the system applies default permissions reduced by the umask value. Typical umask values are 0022 (resulting in 644 files and 755 directories) or 0002. Commands:
umask # show current umask (e.g., 0022)
umask 0027 # set temporary umask for the current shellPermanent changes are made in shell startup files such as ~/.bashrc or /etc/profile.
Part 2: chmod Details
Numeric Mode
Most common usage uses three octal digits: chmod 755 file # rwxr-xr-x, chmod 644 file # rw-r--r--, chmod 600 file # rw-------, chmod 700 dir # rwx------. The digits map to Owner‑Group‑Others permissions.
# chmod ABC path
# A = Owner permissions
# B = Group permissions
# C = Others permissions
# 755 means: Owner rwx, Group r-x, Others r-xSymbolic Mode
More granular control uses who ( u,g,o,a), operator ( +, -, =), and permission ( r,w,x). Common examples:
chmod u+x script.sh # add execute for owner
chmod g-w file.txt # remove write for group
chmod o=r file.txt # set others to read‑only
chmod a+rx program # add read & execute for all
chmod u=rwx,go=rx file # owner rwx, group & others r-xCombined Operations
Modify multiple classes at once:
chmod ug+rw file.txt # owner & group get read/write
chmod u=rwx,g=rx,o=r file # explicit set for each classRecursive Changes
Apply permissions to a directory tree:
chmod -R 755 /var/www/html # all files & dirs
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;Common Permission Values
777 rwxrwxrwx – dangerous, gives everyone full access
755 rwxr-xr-x – executable files or public directories
750 rwxr-x--- – private directories (owner & group only)
700 rwx------ – private files, owner only
644 rw-r--r-- – public files, configuration files
600 rw------- – private files, e.g., SSH keys
Part 3: chown Details
Basic Usage
Change file owner:
chown user /path/to/file # only owner
chown user:group /path/to/file # owner and group
chown :group /path/to/file # only groupRecursive Change
chown -R user:group /path/to/directoryReference File
chown --reference=/etc/passwd /etc/shadow # copy owner/group from another fileCommon Scenarios
Web applications : chown -R www-data:www-data /var/www/html or separate users for Nginx and PHP‑FPM.
Databases : chown -R mysql:mysql /var/lib/mysql and chmod -R 700 /var/lib/mysql (similarly for PostgreSQL).
Log directories : chown -R myapp:adm /var/log/myapp and chmod -R 750 /var/log/myapp.
Service configuration : chown -R root:root /etc/nginx and chmod 640 /etc/nginx/*.conf.
Part 4: ACL (Access Control List)
Check ACL Support
Most modern filesystems (ext4, xfs, btrfs) support ACL. Enable temporarily with:
tune2fs -o acl /dev/sda1
mount -o acl /dev/sda1 /mntView ACL
getfacl /path/to/fileSample output shows entries for specific users, groups, mask, and others.
Set ACL
# User specific
setfacl -m u:alice:rw /var/www/html/file.txt
# Group specific
setfacl -m g:developers:rx /var/www/html/dir
# Default ACL for new files in a directory
setfacl -m d:u:www-data:rw /var/www/html/uploadsACL vs Traditional Permissions
Traditional permissions are the baseline; ACL adds finer‑grained entries. Effective permissions are limited by the mask entry ( mask::).
Web App ACL Example
# Nginx reads, PHP‑FPM writes
chown nginx:nginx /var/www/html
chmod 750 /var/www/html
setfacl -R -m u:php-fpm:rw /var/www/html/uploads
setfacl -R -m u:nginx:rx /var/www/html/uploads
setfacl -R -m d:u:php-fpm:rw /var/www/html/uploadsBackup and Restore
# Backup ACLs
getfacl -R /etc/nginx > /backup/nginx_acl_$(date +%Y%m%d).txt
# Restore
setfacl --restore=/backup/nginx_acl_20260529.txtPart 5: Production Troubleshooting
Problem 1 – Web app cannot read files (403 Forbidden)
Steps:
Check Nginx error log ( tail -20 /var/log/nginx/error.log).
Inspect file permissions ( ls -la /var/www/html/index.html).
Verify Nginx run‑user ( ps aux | grep nginx).
Common causes: wrong owner, missing directory execute bit, SELinux/AppArmor restrictions.
Solution:
# Ensure correct owner
chown nginx:nginx /var/www/html/index.html
# Directory execute permission
chmod 755 /var/www/html
# File read permission
chmod 644 /var/www/html/index.htmlProblem 2 – Web app cannot write files (uploads, logs)
Steps: check PHP‑FPM logs, directory permissions, PHP‑FPM user, filesystem writability.
# Fix ownership and write permission
chown php-fpm:php-fpm /var/www/html/uploads
chmod 775 /var/www/html/uploads
# If SELinux is enforcing
chcon -R -t httpd_sys_rw_content_t /var/www/html/uploads
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
restorecon -R /var/www/html/uploadsProblem 3 – Database cannot start (MySQL/PostgreSQL)
Check error logs, data directory permissions, and config file permissions. Example fix for MySQL:
systemctl stop mysql
chown -R mysql:mysql /var/lib/mysql
chmod -R 700 /var/lib/mysql
systemctl start mysqlProblem 4 – SSH key login fails
Correct permissions:
chmod 700 /home/username/.ssh
chmod 600 /home/username/.ssh/authorized_keys
chmod 755 /home/usernameProblem 5 – Script "Permission denied"
Add execute bit:
chmod +x script.sh # or chmod 755 script.shProblem 6 – Shared directory access
Use SGID so new files inherit the directory’s group, and set a permissive umask for the team:
chmod 2775 /shared # SGID + rwx for owner & group
chown :developers /shared
umask 002 # ensures new files are 664Part 6: Security Best Practices
Principle of Least Privilege
Never apply chmod -R 777 on production paths. Use find to set directories to 755 and files to 644, and grant write permission only where needed.
# Apply least‑privilege defaults
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 775 /var/www/html/uploads
chown www-data:www-data /var/www/html/uploadsSensitive File Protection
# Password files
chmod 640 /etc/passwd
chmod 600 /etc/shadow
# SSH private key
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
# Database configs
chmod 640 /etc/mysql/my.cnf
chmod 640 /etc/postgresql/*/main/pg_hba.conf
# Application secrets
chmod 600 /var/www/html/.envService‑Specific Users
useradd -r -s /sbin/nologin nginx
useradd -r -s /sbin/nologin php-fpm
useradd -r -s /sbin/nologin mysql
useradd -r -s /sbin/nologin postgres
useradd -m -s /bin/bash myappRegular Audits
#!/bin/bash
echo "=== Permission Audit Report ==="
echo "Time: $(date)"
# Sensitive files
for file in /etc/passwd /etc/shadow /etc/group; do
perms=$(stat -c "%a" $file)
owner=$(stat -c "%U:%G" $file)
echo "$file: $owner $perms"
done
# Find dangerous 777 files/dirs
echo "--- 777 files/dirs (dangerous) ---"
find /var/www -perm -007 -type f 2>/dev/null | head -10
find /var/www -perm -007 -type d 2>/dev/null | head -10
# Executable files in /tmp
echo "--- Suspicious executables in /tmp ---"
find /tmp -perm /111 -type f 2>/dev/null | head -10Directory Permission Standards
/home/user – 755 (home directory)
/home/user/.ssh – 700 (SSH keys)
/var/www/html – 755 (web root)
/var/www/html/uploads – 775 (upload dir)
/var/log/app – 750 (application logs)
/data/shared – 2775 (shared dir with SGID)
/tmp – 1777 (sticky‑bit temporary dir)
/etc/nginx – 750 (config files)
/var/lib/mysql – 700 (MySQL data)
umask Recommendations
System‑wide ( /etc/profile) set to 0027. For team shared directories add in user profiles:
# In ~/.bashrc for developers group
if [ "$(id -gn)" = "developers" ]; then
umask 002
fi
# Web‑app user
su - www-data -c "umask 002"Part 7: Risks and Rollback
High‑Risk Operations
chmod -R 777 – high risk, grants full access.
chmod -R 000 – high risk, locks out all access.
chown -R root:root / – extremely high risk, can break the system.
chmod -x /bin/* – extremely high risk, may render the system unbootable.
Modifying /etc/shadow permissions – high risk, must backup first.
Backup Before Change
# Backup ACLs
getfacl -R /etc/nginx > /backup/nginx_acl_$(date +%Y%m%d).txt
getfacl /etc/passwd > /backup/passwd_acl.txtRestore
setfacl --restore=/backup/nginx_acl_20260529.txt
setfacl --restore=/backup/passwd_acl.txtRollback Procedure
Locate original permissions from version control, backup, or documentation.
Use setfacl --restore=backup.txt if an ACL backup exists.
For standard files, revert to typical defaults (e.g., chmod 644 file, chmod 755 dir, chmod 640 /etc/passwd, chmod 600 /etc/shadow).
Part 8: Special Bits Deep Dive
SUID Practical Use
SUID allows a program to run with the file owner’s privileges. Common example: /bin/ping is owned by root with the SUID bit set, enabling ordinary users to send ICMP packets.
ls -l /bin/ping
-rwsr-xr-x 1 root root 4096 May 29 10:30 /bin/ping # s indicates SUIDFind all SUID binaries:
find /usr -perm /4000 -type f 2>/dev/null
find / -perm -4000 -type f 2>/dev/null | grep -vE "^/(usr|bin|sbin)/"Remove SUID when not needed:
chmod u-s /usr/bin/someprogram # or chmod 755 /usr/bin/someprogramSGID Practical Use
On directories, SGID forces new files to inherit the directory’s group. Example shared directory for a development team:
mkdir /opt/shared
groupadd developers
chown :developers /opt/shared
chmod 2775 /opt/shared # SGID (2) + rwx for owner/group, r-x for others
usermod -aG developers alice
usermod -aG developers bob
# Verify
su - alice -c "touch /opt/shared/alice_file.txt"
ls -l /opt/shared/alice_file.txt # shows group 'developers' and rw-rw-r--Multiple groups can be granted via ACL:
mkdir /data/project
chown :dev /data/project
chmod 2770 /data/project
setfacl -m g:qa:rw /data/project
setfacl -m d:g:qa:rw /data/project
getfacl /data/projectSticky Bit Practical Use
Sticky Bit on public directories (e.g., /tmp) ensures users can only delete their own files.
ls -ld /tmp
drwxrwxrwt 10 root root 4096 May 29 10:30 /tmp # t indicates Sticky Bit
chmod 1777 /opt/public
chown root:root /opt/public # anyone can write, but only owners can deleteSELinux/AppArmor Interaction
Check SELinux status:
getenforce # Enforcing, Permissive, or Disabled
sestatus
ls -Z /var/www/html # show SELinux context
chcon -R -t httpd_sys_content_t /var/www/html
semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
restorecon -R /var/www/htmlAppArmor (Ubuntu) commands:
aa-status
cat /etc/apparmor.d/usr.sbin.nginx
systemctl reload apparmorConclusion
Understanding Linux's permission model, mastering chmod and chown, and leveraging ACL, SUID/SGID, and the Sticky Bit are essential skills for reliable and secure system administration. Regular audits, proper backups, and adherence to the principle of least privilege prevent most production incidents.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
