The first time I deployed a web application to a Linux server, I spent two hours debugging a 500 Internal Server Error that turned out to be a file permissions issue. The application couldn’t read its own config file because permissions were 600 instead of 644. Since then, I’ve internalized the permission system — but I still see developers struggle with the same issues regularly.
How Linux Permissions Work
Every file and directory has three permission sets:
-rwxr-xr-- 1 alice developers 4096 Mar 15 deploy.sh
│├──┤├──┤├──┤
│ │ │ └─ Others (everyone else)
│ │ └───── Group (developers)
│ └───────── Owner (alice)
└──────────── File type (- = file, d = directory)
Each set has three permissions:
| Symbol | Permission | For Files | For Directories |
|---|---|---|---|
r | Read | View contents | List contents |
w | Write | Modify contents | Create/delete files |
x | Execute | Run as program | cd into directory |
Octal Notation
Each permission has a numeric value: Read=4, Write=2, Execute=1, None=0. You add them together: rwx = 7, r-x = 5, r-- = 4.
chmod 755 deploy.sh → Owner: rwx(7) Group: r-x(5) Others: r-x(5)
Calculate visually: The Chmod Calculator lets you toggle permissions for owner, group, and others, showing both octal and symbolic notation in real time.
Permissions You’ll Use Every Day
755 — Directories and Executable Scripts
Owner can read, write, execute. Everyone else can read and execute. Standard for all directories, shell scripts, and web server document roots.
644 — Regular Files
Owner can read and write. Everyone else can only read. Default for static web files (HTML, CSS, JS, images) and non-secret configuration files.
600 — Private Files
Only owner can read and write. Required for SSH private keys, .env files with secrets, database backups, and SSL private keys. SSH refuses to use a key with looser permissions.
700 — Private Directories
Only owner can access. Required for ~/.ssh/ directory and any directory containing sensitive data.
Real-World Patterns
Web Server Files
# Static files
find /var/www/html -type f -exec chmod 644 {} \;
# Directories
find /var/www/html -type d -exec chmod 755 {} \;
# Upload directories (web server needs write)
chmod 775 /var/www/html/uploads
The common 403 Forbidden error on newly deployed sites is almost always caused by incorrect permissions.
SSH Keys
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/id_rsa # Private key
chmod 644 ~/.ssh/id_rsa.pub # Public key
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/config
Docker
COPY --chmod=755 entrypoint.sh /app/entrypoint.sh
COPY --chmod=644 config.json /app/config.json
RUN chmod 600 /app/.env
CI/CD Pipelines
- name: Deploy
run: |
chmod +x ./scripts/deploy.sh
./scripts/deploy.sh
Scripts checked out by CI often lose execute permission. Always set chmod +x before running.
Common Mistakes
Mistake 1: chmod 777
777 means everyone can do everything. It’s the permission equivalent of leaving your front door open. If you’re reaching for 777, figure out which user your process runs as and grant minimum permissions.
Mistake 2: Recursive chmod Without Separating Files and Directories
# Wrong: makes all files executable
chmod -R 755 /var/www/html
# Correct: different permissions for files vs directories
find /var/www/html -type f -exec chmod 644 {} \;
find /var/www/html -type d -exec chmod 755 {} \;
Mistake 3: Forgetting Group Permissions
In team environments, use the setgid bit so new files inherit the directory’s group:
chown -R alice:webteam /var/www/html
chmod g+s /var/www/html
Quick Reference
| Octal | Symbolic | Common Use |
|---|---|---|
| 755 | rwxr-xr-x | Directories, scripts |
| 644 | rw-r--r-- | Regular files |
| 600 | rw------- | Private files (.env, SSH keys) |
| 700 | rwx------ | Private directories (~/.ssh) |
| 444 | r--r--r-- | Read-only files |
| 775 | rwxrwxr-x | Shared directories |
Further Reading
Use the Chmod Calculator to toggle permissions visually and get both octal and symbolic notation instantly.