← Back to Linux Notes
ES · EN

🔐 Permissions & Ownership (chmod, chown, groups)

About 80% of “Permission denied” errors on servers come from this. This guide teaches you how to read permissions, understand owner/group, and fix access issues without breaking security (avoiding the classic chmod 777).

Basic → Intermediate
Level
15–25 min
Read time
Servers / EC2
Context
Goal: be able to answer quickly: Who has access? Why is it failing? Should I change chmod or chown? What is the safer fix?

🧠 Minimal concepts (no fluff)

Linux access control is basically two things: ownership (owner/group) + permissions (r/w/x). If either is wrong, your app, your service, or your CI/CD pipeline will fail.

👀 How to read permissions (the most important part)

The “truth” command:

ls -lah
# -l  long format (permissions, owner, group, size, date)
# -a  include hidden files (starting with .)
# -h  human-readable sizes (K/M/G)

Typical examples:

-rw-r-----  1 ubuntu  devops  120K Jan 18  app.log
drwxr-x---  2 root    devops  4.0K Jan 18  /opt/app
-rwxr-xr-x  1 ubuntu  ubuntu  2.3K Jan 18  deploy.sh
DevOps checklist before changing anything:
Run:
ls -lah
whoami
id
That tells you: what permissions exist, who you are, and what groups you have.

📁 The golden rule for directories (this confuses everyone)

On directories, r/w/x mean:

Real case: if a folder has r but not x, you can “see” file names, but you cannot enter the directory or access files inside.

🛠 chmod (change permissions) — clear beginner mode

Two styles: symbolic (readable) and numeric (fast). In DevOps you’ll see both.

✅ Symbolic mode (recommended at the start)

You specify who is affected: u (owner), g (group), o (others), a (all).

chmod u+rwx file         # u = owner
chmod g+rx dir           # g = group
chmod o-r file           # o = others
chmod a+r file           # a = all

⚡ Numeric mode (most common on servers)

Values:

chmod 644 file       # owner rw- (6), group r-- (4), others r-- (4)
chmod 600 secret     # owner rw-, nobody else (great for keys/credentials)
chmod 755 script.sh  # owner rwx, group rx, others rx (common executable)
chmod 750 /opt/app   # owner rwx, group rx, others none (safer on servers)
Real tip: for scripts:

👤 chown (change owner/group) — when to use it

chmod does not fix ownership. If the file/folder belongs to the wrong user/group, permissions alone may not solve your issue.

chown ubuntu file                 # change owner to ubuntu
chown ubuntu:devops file          # owner ubuntu and group devops
chown -R ubuntu:devops /opt/app   # recursive (common in deployments)
Quick rule:

👥 Groups (the DevOps trick to share access without “777”)

In DevOps, a service/pipeline usually runs as a specific user (e.g., www-data, jenkins, deploy). Instead of opening access to everyone, you define a group and grant access to the group.

groups                 # see your groups
id                     # see uid/gid and group memberships

# (as root) add a user to a group
usermod -aG devops ubuntu

# apply group access to app directory
chown -R root:devops /opt/app
chmod -R 770 /opt/app

⭐ Special permissions (only what you actually use)

setgid on directories (for team/shared work)

Makes new files inherit the directory’s group. This prevents new files from landing in the wrong group and breaking access.

chmod g+s /opt/app
# you'll see an "s" in the group permission block when listing

Sticky bit (common on /tmp)

Allows many users to write there, but prevents them from deleting each other’s files. That’s why /tmp usually has the sticky bit set.

chmod +t /tmp

☁️ Real AWS / DevOps scenarios

✅ Takeaways (remember this)

🧪 Practical lab (10–15 min) — “Permission Denied Lab”

Real scenario: your pipeline (or deploy user) tries to write logs into a directory created by provisioning (root), and it fails with Permission denied.

Where to run it: use /tmp so you don’t break anything.
Requirements: Linux / WSL / VM / EC2.

1) Create an app-like structure

# 1) Create typical app folders
mkdir -p /tmp/perm-lab/app/{bin,logs,config}
cd /tmp/perm-lab

# 2) Create a simple "start script"
cat > /tmp/perm-lab/app/bin/start.sh << 'EOF'
#!/bin/bash
echo "App started at $(date)" >> /tmp/perm-lab/app/logs/app.log
echo "OK"
EOF

# 3) Inspect the structure
ls -lah /tmp/perm-lab/app/bin
ls -lah /tmp/perm-lab/app/logs

2) Simulate the problem (root-owned directories)

# Simulate provisioning that created everything as root
sudo chown -R root:root /tmp/perm-lab/app
sudo chmod -R 700 /tmp/perm-lab/app

# Try running the script (it should fail)
bash /tmp/perm-lab/app/bin/start.sh

You should see something like:

Permission denied

3) Diagnose like a DevOps engineer

whoami
id
ls -lah /tmp/perm-lab/app
ls -lah /tmp/perm-lab/app/bin
ls -lah /tmp/perm-lab/app/logs

Ask yourself:

👀 Show the correct solution (no 777) + explanation

✅ Professional fix: use a group (e.g., devops) and grant access to the group. That way your deploy/pipeline user can operate without opening the directory to everyone.

# 1) Create devops group if it doesn't exist (safe if it already exists)
sudo groupadd devops 2>/dev/null || true

# 2) Add your user to the devops group
sudo usermod -aG devops "$USER"

# 3) Change group ownership (keep root as owner)
sudo chown -R root:devops /tmp/perm-lab/app

# 4) Full access for owner+group, none for others
sudo chmod -R 770 /tmp/perm-lab/app

# 5) Ensure group inheritance for new files (setgid)
sudo chmod g+s /tmp/perm-lab/app /tmp/perm-lab/app/logs

# 6) Ensure script is executable (in case it lost +x)
sudo chmod 770 /tmp/perm-lab/app/bin/start.sh

# 7) Retry
bash /tmp/perm-lab/app/bin/start.sh

# 8) Check the log
cat /tmp/perm-lab/app/logs/app.log

Why this works:

Note: if group changes don’t apply immediately, open a new terminal or run:

newgrp devops