Skip to main content

Linux File Permissions and Ownership — chmod, chown, umask, and ACLs

Understand the Unix permission model and manage file permissions and ownership on production Linux servers using chmod, chown, and ACLs.

30 Terms

Permission denied. Three words that stop a production deployment. A deployment script fails because the process user cannot write to a log directory. A web server returns 403 because the document root is not readable. A CI/CD pipeline fails because the SSH key file has permissions that are too open and SSH refuses to use it.

Linux file permissions are not a niche topic for systems administrators. They are a daily reality for every DevOps engineer. Understanding them deeply means diagnosing and fixing permission issues in seconds instead of minutes — or causing them in the first place.

Why It Matters

Every file and directory on a Linux system has an owner, a group, and a set of permission bits. These three things together determine who can read, write, and execute the file. Get them wrong and applications fail to start. Get them too permissive and you create security vulnerabilities. The Unix permission model has been unchanged for fifty years because it is simple, powerful, and correct.

At Razorpay, every file in the payment service directory is owned by the payment-svc user and group. No other user can write to those files. Not the web server. Not the CI runner. Not a developer who has SSH access. This containment means that even if one component is compromised, it cannot modify the payment service code.

Core Principles

Reading the 10-character permission string:

◈ DIAGRAM
- r w x r - x r - -
| |-----| |-----| |-----|
| owner group other
|
+-- File type: - (file), d (dir), l (symlink), c (char device), b (block device)
r = read (4)
w = write (2)
x = execute (1)
- = no permission (0)

Calculating octal from the string:

TEXT
-rwxr-xr--
owner: rwx = 4+2+1 = 7
group: r-x = 4+0+1 = 5
other: r-- = 4+0+0 = 4
Octal: 754

Production permission reference:

TEXT
644 -rw-r--r-- Config files, HTML, static assets
Owner reads/writes, everyone reads
640 -rw-r----- Sensitive config files (DB passwords)
Owner reads/writes, group reads, others nothing
600 -rw------- SSH private keys, secret files
Owner reads/writes only, no one else
755 -rwxr-xr-x Scripts, binaries, web directories
Owner full, everyone reads/executes
700 -rwx------ SSH directory (~/.ssh/)
Owner full, no one else
750 -rwxr-x--- Restricted scripts, app directories
Owner full, group reads/executes
777 -rwxrwxrwx NEVER use in production
Everyone can do everything

Execute on directories means something different:

For directories, the execute bit means "can enter this directory" (traverse). Without execute on a directory, you cannot cd into it or access anything inside it, even if you have read permission on the files inside.

Bash
## This is why web server directories need 755 not 644
## Without the x bit, nginx cannot traverse into the document root
chmod 755 /var/www/html/

The special permission bits:

TEXT
Setuid (s on user execute position):
When an executable has setuid, it runs as the file owner
regardless of who executes it.
Example: /usr/bin/passwd has setuid root -- lets regular
users change their own password by temporarily running as root.
chmod u+s filename or chmod 4755 filename
Setgid (s on group execute position):
On files: runs with file's group permissions.
On directories: new files inherit the directory's group
instead of the creator's primary group.
chmod g+s dirname or chmod 2755 dirname
Sticky bit (t on other execute position):
On directories: users can only delete files they own,
even if they have write permission on the directory.
/tmp has sticky bit -- you cannot delete other users' temp files.
chmod +t dirname or chmod 1777 dirname

Step-by-Step Lab

Milestone 1 — Read and understand permissions

Bash
## Create test directory and files
mkdir -p /tmp/permissions-lab
cd /tmp/permissions-lab
touch file1.txt file2.sh
mkdir subdir/
## View permissions in long format
ls -la
## -rw-r--r-- 1 ubuntu ubuntu 0 Jan 15 10:00 file1.txt
## -rw-r--r-- 1 ubuntu ubuntu 0 Jan 15 10:00 file2.sh
## drwxr-xr-x 2 ubuntu ubuntu 4096 Jan 15 10:00 subdir
## Get detailed info on one file
stat file1.txt
## Access: (0644/-rw-r--r--) Uid: (1000/ubuntu) Gid: (1000/ubuntu)

Milestone 2 — Change permissions with chmod

Bash
## Symbolic mode: u=user, g=group, o=other, a=all
## + adds, - removes, = sets exactly
## Make a script executable by owner only
chmod u+x file2.sh
ls -la file2.sh
## -rwxr--r-- 1 ubuntu ubuntu 0 Jan 15 10:00 file2.sh
## Remove write from group and other
chmod go-w file1.txt
## Set exact permissions with octal
chmod 644 file1.txt ## -rw-r--r--
chmod 755 file2.sh ## -rwxr-xr-x
chmod 700 subdir/ ## drwx------
## Apply recursively to a directory
chmod -R 755 /var/www/html/
## Verify with ls
ls -la

Milestone 3 — Change ownership with chown

Bash
## Create a service account user for testing
sudo useradd -r -s /sbin/nologin app-service
## Change owner
sudo chown app-service file1.txt
## Change owner and group together
sudo chown app-service:app-service file2.sh
## Change only the group
sudo chown :app-service subdir/
## Shorthand for: chgrp app-service subdir/
## Change recursively
sudo chown -R app-service:app-service /opt/myapp/
## Verify
ls -la
## -rw-r--r-- 1 app-service ubuntu 0 Jan 15 10:00 file1.txt
## -rwxr-xr-x 1 app-service app-service 0 Jan 15 10:00 file2.sh

Milestone 4 — Understand and set umask

umask controls default permissions for newly created files and directories. It is a mask that removes bits from the maximum (666 for files, 777 for directories).

Bash
## Check current umask
umask
## 0022
## How umask 022 works:
## New file: 666 - 022 = 644 (-rw-r--r--)
## New directory: 777 - 022 = 755 (drwxr-xr-x)
## Create files and verify
touch /tmp/test-umask-file
mkdir /tmp/test-umask-dir
ls -la /tmp/test-umask-file /tmp/test-umask-dir
## -rw-r--r-- /tmp/test-umask-file
## drwxr-xr-x /tmp/test-umask-dir
## Set umask for more restrictive defaults
umask 027
## New file: 666 - 027 = 640 (group can read, others nothing)
## New directory: 777 - 027 = 750
## Set permanently for a service account in /etc/profile.d/
echo 'umask 027' | sudo tee /etc/profile.d/service-umask.sh

Milestone 5 — Set ACLs for granular control

ACLs (Access Control Lists) extend the basic model to allow per-user and per-group permissions beyond the three-level system.

Bash
## Install ACL tools if needed
sudo apt install acl # Debian/Ubuntu
## View current ACLs
getfacl /tmp/permissions-lab/file1.txt
## # file: file1.txt
## # owner: ubuntu
## # group: ubuntu
## user::rw-
## group::r--
## other::r--
## Give a specific user read/write access without changing ownership
sudo setfacl -m u:deploy:rw file1.txt
getfacl file1.txt
## user::rw-
## user:deploy:rw- <- deploy user now has read/write
## group::r--
## other::r--
## Give a specific group read access
sudo setfacl -m g:developers:r file1.txt
## Set a default ACL on a directory (new files inherit it)
sudo setfacl -d -m u:deploy:rw /var/log/myapp/
## Remove an ACL entry
sudo setfacl -x u:deploy file1.txt
## Remove all ACLs
sudo setfacl -b file1.txt

Milestone 6 — Apply production permission patterns

Bash
## Web server document root
sudo chown -R www-data:www-data /var/www/html/
sudo find /var/www/html/ -type f -exec chmod 644 {} \;
sudo find /var/www/html/ -type d -exec chmod 755 {} \;
## Application directory
sudo chown -R app-service:app-service /opt/myapp/
sudo chmod 750 /opt/myapp/
sudo chmod 640 /opt/myapp/config/*.conf # readable by group only
## SSH directory (strict requirements - SSH will refuse keys with wrong permissions)
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519 # private key
chmod 644 ~/.ssh/id_ed25519.pub # public key can be world-readable
## Log directory
sudo chown app-service:syslog /var/log/myapp/
sudo chmod 775 /var/log/myapp/
## Owner and syslog group can write; verify readable by log shippers

Common Mistakes

Mistake Problem Fix
chmod 777 to "fix" permission errors Creates security vulnerability Identify correct owner and set minimal permissions
SSH private key permissions too open SSH refuses to use it (security check) chmod 600 ~/.ssh/id_ed25519
Forgetting -R on recursive chown Only top-level directory changes Always use -R for directory trees
Not accounting for execute on directories Cannot cd into dir even with r permission Directories need x bit for traversal
Using octal 0 for no permission on all File becomes 000 — owner locked out too Verify octal before applying

Troubleshooting

Symptom First Command What to Look For
Permission denied when writing ls -la on target file/dir Write bit for current user/group
SSH ignores authorized_keys ls -la ~/.ssh/ ~/.ssh should be 700, authorized_keys 600
Web server returns 403 Forbidden ls -la /var/www/html/ www-data needs read + execute on path
Script runs fine but fails in cron Check script file permissions Script needs execute bit for cron user
App cannot read config file ls -la configfile File owner/group matches app user
Tip

When diagnosing a permission issue, trace the full path. Every directory in the path needs execute (traverse) permission for the user. A file with 644 permissions inside a directory with 700 permissions is inaccessible to anyone except the directory owner.

Remember

The numeric (octal) and symbolic (rwx) modes do the same thing. Octal is faster to type. Symbolic is clearer to read. Learn both — you will see both in production scripts and documentation.

Security

Setuid binaries are a common privilege escalation vector. Audit setuid files regularly: find / -perm -4000 -type f 2>/dev/null. Any unexpected setuid binary is a potential security issue.

Resources

Explore More in Linux Fundamentals and File System

All 4 Topics

Frequently Asked Questions

Is Linux File Permissions and Ownership — chmod, chown, umask, and ACLs free to learn on DevOps Network?

Yes - this topic, like everything on DevOps Network, is 100% free with no paywall or sign-up gate.

What does the Linux File Permissions and Ownership — chmod, chown, umask, and ACLs topic cover?

Understand the Unix permission model and manage file permissions and ownership on production Linux servers using chmod, chown, and ACLs.