Linux File Permissions: chmod, chown, and chgrp
Linux file permissions form the foundation of system security. Every file and directory has three permission sets: one for the owner (user), one for the group, and one for everyone else (others)....
Key Insights
- Linux file permissions operate on three levels (user, group, others) with three types of access (read, write, execute), and you can modify them using either numeric octal notation (755) or symbolic notation (u+x).
- The
chmodcommand changes permissions,chownchanges ownership (user and optionally group), andchgrpchanges only group ownership—understanding when to use each prevents security vulnerabilities. - Most permission problems stem from overly permissive settings like 777; always apply the principle of least privilege and use specific permissions like 644 for files and 755 for directories.
Understanding Linux File Permissions Basics
Linux file permissions form the foundation of system security. Every file and directory has three permission sets: one for the owner (user), one for the group, and one for everyone else (others). Each set can grant read (r), write (w), and execute (x) permissions.
When you run ls -l, you see permission strings like this:
$ ls -l
-rw-r--r-- 1 john developers 1234 Jan 15 10:30 config.txt
drwxr-xr-x 2 john developers 4096 Jan 15 10:31 scripts
-rwxr-x--- 1 john developers 2048 Jan 15 10:32 deploy.sh
The first character indicates the file type (- for regular file, d for directory, l for symbolic link). The next nine characters represent permissions in three groups of three:
- Characters 2-4: User/owner permissions
- Characters 5-7: Group permissions
- Characters 8-10: Other permissions
Each permission has a numeric value: read (4), write (2), execute (1). Sum them to get octal notation. For example, rwxr-xr-x translates to 755 (4+2+1, 4+1, 4+1).
Execute permission on directories means you can enter them and access their contents. Without it, you can’t cd into a directory even if you can read it.
chmod: Changing File Permissions
The chmod command modifies file permissions. You can use symbolic or numeric notation, and both have their place.
Symbolic mode is intuitive for making specific changes:
# Make a script executable for the owner
chmod u+x deploy.sh
# Remove write permission for group and others
chmod go-w config.txt
# Add read permission for everyone
chmod a+r readme.txt
# Set exact permissions: owner can read/write, others can only read
chmod u=rw,go=r config.txt
The symbolic format uses:
u(user/owner),g(group),o(others),a(all)+(add),-(remove),=(set exactly)r(read),w(write),x(execute)
Numeric mode is faster when you know exactly what you want:
# Standard file permissions: owner read/write, others read-only
chmod 644 config.txt
# Standard directory permissions: owner full, others read/execute
chmod 755 scripts/
# Executable script: owner full, group read/execute, others none
chmod 750 deploy.sh
# Private file: owner read/write only
chmod 600 ~/.ssh/id_rsa
For web applications, you typically want 755 for directories and 644 for files:
# Set permissions recursively for a web directory
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# Or using chmod's recursive flag (less precise)
chmod -R 755 /var/www/html
The recursive -R flag is convenient but dangerous—it applies the same permissions to everything. Use find with -type for more control.
chown: Changing File Ownership
The chown command changes file ownership. This is crucial when transferring files between users or setting up services.
Basic syntax allows changing the user, group, or both:
# Change owner to 'www-data'
chown www-data /var/www/html/index.php
# Change owner and group
chown www-data:www-data /var/www/html/index.php
# Change only group (colon with no user)
chown :developers project.txt
# Recursive ownership change
chown -R appuser:appuser /opt/myapp
Real-world scenario: You’ve deployed a web application and need to set proper ownership:
# Set ownership for Apache/Nginx
chown -R www-data:www-data /var/www/myapp
# But keep specific directories writable by the application
chown -R www-data:www-data /var/www/myapp/storage
chown -R www-data:www-data /var/www/myapp/cache
When moving files from your user account to a service account:
# You uploaded files as 'john', but the app runs as 'appuser'
sudo chown -R appuser:appuser /home/john/uploaded-data
sudo mv /home/john/uploaded-data /opt/myapp/data
One common pattern is using chown with find to selectively change ownership:
# Change ownership of all PHP files
find /var/www -name "*.php" -exec chown www-data:www-data {} \;
chgrp: Changing Group Ownership
While chown can change groups, chgrp exists for changing only group ownership. It’s cleaner when you don’t need to touch user ownership.
# Change group ownership
chgrp developers project/
# Recursive group change
chgrp -R developers /shared/projects/alpha
# Useful for collaborative directories
chgrp -R webteam /var/www/shared-assets
Use chgrp when managing shared directories where multiple users need access:
# Create a shared project directory
mkdir /projects/teamalpha
chgrp developers /projects/teamalpha
chmod 2775 /projects/teamalpha # Note the leading 2 (SetGID)
The advantage of chgrp over chown :group is clarity—your intent is obvious. In scripts, this explicitness helps maintainability.
Special Permissions and Advanced Concepts
Beyond basic permissions, Linux has three special permission bits:
SetUID (4) - When set on executables, runs the file with the owner’s privileges:
# Usually you won't set this yourself, but it's on system binaries
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 May 28 2020 /usr/bin/passwd
SetGID (2) - On directories, new files inherit the directory’s group:
# Perfect for team collaboration
mkdir /projects/shared
chgrp developers /projects/shared
chmod 2775 /projects/shared
# Now any file created here automatically belongs to 'developers' group
Sticky Bit (1) - On directories, only file owners can delete their files:
# Essential for /tmp and shared upload directories
chmod 1777 /var/www/uploads
# or
chmod +t /var/www/uploads
ls -ld /tmp
drwxrwxrwt 20 root root 4096 Jan 15 10:30 /tmp
The umask command sets default permissions for new files:
# Check current umask
umask
0022
# Set umask to create files as 644, directories as 755
umask 022
# Set umask to create files as 640, directories as 750
umask 027
Practical Real-World Scenarios
Web Server Setup (Nginx/Apache):
# Initial deployment
sudo chown -R www-data:www-data /var/www/myapp
sudo find /var/www/myapp -type f -exec chmod 644 {} \;
sudo find /var/www/myapp -type d -exec chmod 755 {} \;
# Make storage and cache writable
sudo chmod -R 775 /var/www/myapp/storage
sudo chmod -R 775 /var/www/myapp/bootstrap/cache
# If you need to edit files as your user, add yourself to www-data group
sudo usermod -a -G www-data john
Securing SSH Keys:
# SSH is strict about key permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 644 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/config
Shared Development Environment:
# Create a shared project with proper collaboration settings
sudo mkdir -p /projects/webapp
sudo groupadd webdevs
sudo chgrp webdevs /projects/webapp
sudo chmod 2775 /projects/webapp
# Add users to the group
sudo usermod -a -G webdevs alice
sudo usermod -a -G webdevs bob
# Set umask for the group (in /etc/profile or user's .bashrc)
umask 002 # Creates files as 664, directories as 775
Common Pitfalls and Best Practices
Never use 777 unless absolutely necessary. It grants full access to everyone, creating security vulnerabilities. If you think you need 777, you probably need to fix ownership or group membership instead.
# Wrong approach
chmod 777 /var/www/uploads # Security nightmare
# Right approach
chown -R www-data:www-data /var/www/uploads
chmod 755 /var/www/uploads
Apply the principle of least privilege. Grant only the minimum permissions needed:
# Configuration files: owner can modify, others can read
chmod 644 config.ini
# Secrets and keys: owner read/write only
chmod 600 .env
# Executables: owner can modify, everyone can execute
chmod 755 script.sh
# Shared writable directory: group collaboration with sticky bit
chmod 2775 shared/
Troubleshooting permission denied errors:
# Check current permissions and ownership
ls -la problematic-file
# Check if you're in the necessary group
groups
id
# Check directory permissions (you need execute on all parent directories)
namei -l /path/to/file
Security audit script to find overly permissive files:
#!/bin/bash
# Find world-writable files (dangerous)
echo "World-writable files:"
find /var/www -type f -perm -002 -ls
# Find files with permissions wider than 644
echo -e "\nFiles more permissive than 644:"
find /var/www -type f ! -perm 644 -ls
# Find SetUID/SetGID files (review these carefully)
echo -e "\nSetUID/SetGID files:"
find /var/www -type f \( -perm -4000 -o -perm -2000 \) -ls
Understanding these three commands—chmod, chown, and chgrp—is essential for Linux system administration. Master the basics, apply least privilege, and always consider the security implications of your permission changes. When in doubt, be more restrictive rather than more permissive.