Skip to main content

Permission and Ownership Basics

Linux permissions define what can be done to a file (read, write, execute), and ownership defines which user and group those rules apply to. On a WordPress server, the goal is to keep code read-only while ensuring only the directories that must be writable (like uploads) are writable. This page covers chmod, chown, and chgrp, how to read modes, and a safe baseline you can apply after installs and migrations.

Prerequisites

  • Shell access to the server (SSH).
  • sudo or root access for changing ownership.
  • Basic navigation commands: ls, cd.

How Linux Decides Access

Permissions are evaluated against the file's owner and group.

Directory execute bit

For directories, x means "traverse" (enter the directory). A directory that is readable but not executable can be listed but not entered.

Permission Codes Reference (Common WordPress Defaults)

CodeSymbolicOwnerGroupOthersTypical WordPress useNotes
600rw-------Read, writeNoneNonewp-config.phpStrict: only the owner can read/write
640rw-r-----Read, writeReadNonewp-config.phpUse when the web server group must read
644rw-r--r--Read, writeReadReadMost filesStandard: writable only by owner
660rw-rw----Read, writeRead, writeNoneDev groupsGroup can edit
664rw-rw-r--Read, writeRead, writeReadShared environmentsGroup edit, world read
700rwx------Full accessNoneNonePrivate scriptsOwner-only
750rwxr-x---Full accessRead, executeNonePrivate directoriesGroup can traverse and read
755rwxr-xr-xFull accessRead, executeRead, executeMost directoriesStandard for directories
775rwxrwxr-xFull accessFull accessRead, executeShared directoriesGroup can edit
777rwxrwxrwxFull accessFull accessFull accessAvoidGrants world write
warning

Avoid 777 on WordPress paths. It turns every local user and many service accounts into a potential write path.

Command Reference (chmod, chown, chgrp)

CommandOptionMeaningExample
chmodOctal modeSet the full mode at oncechmod 644 wp-config.php
chmodSymbolic modeAdd/remove specific bitschmod g+w uploads/
chmod-RApply recursivelychmod -R 755 wp-content/
chownuser:groupChange owner and groupchown www-data:www-data index.php
chown-RRecursive ownership changechown -R www-data:www-data /var/www/html/
chgrpGroupChange group onlychgrp developers style.css

Symbolic Permissions (u/g/o/a, +/-, r/w/x)

A symbolic permission expression is built like this:

symbolic-permission-expression.txt
[WHO][OPERATOR][PERMISSION]
  • WHO: u (owner), g (group), o (others), a (all)
  • OPERATOR: + add, - remove, = set exactly
  • PERMISSION: r read, w write, x execute

Examples

CommandMeaningExample use
chmod u+x file.shAdd execute for ownerMake a script runnable
chmod g+w uploads/Add write for groupLet a group write uploads
chmod o-r config.phpRemove read from othersHide sensitive config from world
chmod a+r style.cssAdd read for allMake file world-readable
chmod u-w index.phpRemove write from ownerReduce accidental edits
chmod g-x scripts/Remove execute from groupPrevent traversing/executing
chmod a=rw file.txtSet all to read/write onlyShared text file
chmod u=rwx,g=rx,o= file.txtOwner full, group rx, others noneLock down access

Example: decode g+w

chmod-add-group-write-uploads.sh
chmod g+w wp-content/uploads/

Before:

ls-l-uploads-before.txt
drwxr-xr-x 5 www-data www-data 4096 Sep 23 uploads

After:

ls-l-uploads-after.txt
drwxrwxr-x 5 www-data www-data 4096 Sep 23 uploads

Numeric vs Symbolic Modes

  • Numeric (example: chmod 644 file) sets the whole mode in one operation.
  • Symbolic (example: chmod g+w file) changes only the specified bits.

Example:

chmod-add-group-write-without-overwriting.sh
chmod g+w index.php

If index.php starts as 644 (-rw-r--r--), group write makes it 664 (-rw-rw-r--).

Quick Lab (safe)
quick-lab-symbolic-permissions.sh
touch demo.txt
chmod 644 demo.txt
ls -l demo.txt
chmod g+w demo.txt
ls -l demo.txt
chmod o-r demo.txt
ls -l demo.txt

Expected results:

  1. Start: rw-r--r--
  2. After g+w: rw-rw-r--
  3. After o-r: rw-rw----

WordPress Baseline: Reset Modes and Ownership

warning

Recursive changes can break deployments if you apply them to the wrong path. Confirm the target path and keep a rollback plan.

A common baseline after a clean install or migration:

reset-wordpress-permissions-and-ownership.sh
find /var/www/html/ -type d -exec chmod 755 {} ;
find /var/www/html/ -type f -exec chmod 644 {} ;
chown -R www-data:www-data /var/www/html/

Harden wp-config.php:

lock-down-wp-config-php.sh
chmod 600 /var/www/html/wp-config.php
note

If your workflow requires a non-webserver user to edit files directly, consider an owner/group model where your admin user owns files and the web server user is the group. Apply the same permission concepts, but adjust ownership to match your deployment process.

Common Command Examples (reference)
chmod-644-index-php.sh
chmod 644 index.php
ls -l index.php
chmod-600-wp-config-php.sh
chmod 600 wp-config.php
ls -l wp-config.php
chmod-700-backup-script.sh
chmod 700 backup.sh
ls -l backup.sh
chmod-add-group-write-style-css.sh
chmod g+w style.css
ls -l style.css
chmod-remove-others-write-uploads.sh
chmod o-w uploads/
ls -ld uploads
chmod-add-execute-to-directory.sh
chmod +x wp-content/
ls -ld wp-content/
chmod-recursive-755-wp-content.sh
chmod -R 755 wp-content/
chmod-recursive-644-files-wp-content.sh
find wp-content/ -type f -exec chmod 644 {} ;
chown-debug-log-to-web-user.sh
sudo chown www-data:www-data wp-content/debug.log
ls -l wp-content/debug.log
chown-recursive-web-user-docroot.sh
sudo chown -R www-data:www-data /var/www/html/
chgrp-style-css-to-developers.sh
sudo chgrp developers style.css
chown-user-only-style-css.sh
sudo chown ubuntu: style.css
chgrp-recursive-themes-to-developers.sh
sudo chgrp -R developers wp-content/themes/
chmod-add-group-exec-deploy-script.sh
chmod g+x deploy.sh
chmod-remove-exec-readme.sh
chmod -x readme.txt
chmod-750-private-directory.sh
chmod 750 private/
chmod-777-cache-debug-only.sh
chmod 777 cache/
chmod-explicit-u-rw-g-r-o-none.sh
chmod u=rw,g=r,o= index.php
chown-and-chmod-uploads-collaboration.sh
sudo chown ubuntu:www-data wp-content/uploads/
chmod 775 wp-content/uploads/

WordPress-Specific Benefits

CommandBenefit
chmod 644Prevents public write access to most WordPress files
chmod 755Keeps directories traversable without granting write
chmod 600 wp-config.phpProtects database credentials
chown www-data:www-dataEnsures the web server can read/write where needed
chgrp developersEnables collaboration without full root access

Implementation Steps (repeatable workflow)

  1. Audit ownership and modes:
audit-docroot-ownership-and-modes.sh
ls -l /var/www/html
  1. Secure files:
set-644-on-all-files-under-docroot.sh
find /var/www/html/ -type f -exec chmod 644 {} ;
  1. Secure directories:
set-755-on-all-directories-under-docroot.sh
find /var/www/html/ -type d -exec chmod 755 {} ;
  1. Harden sensitive files:
harden-wp-config-php.sh
chmod 600 /var/www/html/wp-config.php
  1. Fix ownership:
fix-ownership-recursively-docroot.sh
sudo chown -R www-data:www-data /var/www/html/

Use Case Scenarios

ScenarioActionOutcome
File upload errorschown -R www-data:www-data wp-content/uploads/Fixes permission denied on uploads
Post-migrationReset to 644/755 and correct ownershipPrevents broken themes/plugins from wrong modes
Multiple developerschgrp developers on theme filesControlled group access for edits
Hardening configchmod 600 wp-config.phpReduces risk of config disclosure

Best Practices

  • Apply least privilege: default to 644 for files and 755 for directories.
  • Restrict wp-config.php to 600 (or 640 when a group needs read access).
  • Avoid 777, even temporarily; prefer fixing ownership and group access.
  • After migrations, verify both modes and ownership before troubleshooting the application layer.
  • Use find to separate directory and file mode changes instead of chmod -R when you care about exec bits.
Cheat Sheet (copy-ready)
CommandPurpose
chmod 644 fileSet a typical WordPress file mode
chmod 755 dirSet a typical directory mode
chmod 600 wp-config.phpLock down the main config file
chmod -R 755 path/Recursive mode change (use carefully)
chown user:group fileChange file owner and group
chown -R user:group path/Recursive ownership change
chgrp group fileChange only group ownership
Mini Quiz (self-check)
  1. What is the difference between chmod and chown?
  2. Why do directories usually need x (execute) even when you are not "executing" them?
  3. Which command fixes ownership for an entire WordPress site after migration?
  4. What risk comes with chmod 777 on wp-content/uploads/?
  5. How would you give group developers ownership of all files in themes/?

What's Next