Back to problems

problem hub

Read-only first

Linux permission denied

Trace owner, mode, ACL, symlink, and parent-directory permissions before recursive chmod or chown.

Safest first command

namei -l /var/www/example/index.html

Before you run this

Expected output: A path-by-path permission chain showing each parent directory and the final file.

When not to use it: Do not use broad recursive chmod or chown as a first response. It can expose files or break services.

Expected output example

f: /var/www/example/index.html
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-x--- root www-data www
-rw-r----- deploy www-data index.html

How to read the result

Every parent directory needs execute permission for the user or service that traverses it. The final file also needs the needed read/write/execute bit for that access path.

What to check next

A parent directory lacks execute permission

Means: The user or service cannot traverse the path even if the final file is readable.

Next step: Confirm the service user and inspect the exact path chain before any chmod.

Trace Every Parent Directory on a Permission Denial

The final file owner or group is unexpected

Means: A deploy, restore, or copy step may have changed ownership.

Next step: Inspect owner and mode on the file and nearby expected-good files.

Check Owner and Mode in One Line

Modes look correct but access still fails

Means: ACLs, symlink targets, or mandatory access control may be involved.

Next step: Inspect symlink targets and extended permission context before broad changes.

Audit a Symlink Permission Chain

Trace the whole path

A readable file can still fail if a parent directory lacks execute permission. Start with the path chain.

  1. namei -l /var/www/example/index.html
  2. stat -c '%A %U:%G %n' /var/www/example/index.html

Permission denied decision tree

Start with the exact path, then branch on the first failing proof: parent traversal, final owner/group, symlink target, ACL, service user, or mandatory access-control denial. Each branch stays read-only until the failing object is named.

  1. namei -l /var/www/example/index.html
  2. stat -c '%A %U:%G %n' /var/www/example/index.html
  3. readlink -f /var/www/example/index.html
  4. getfacl /var/www/example/index.html
  5. ps -o user,comm -C nginx
  6. systemctl show -p User nginx
  7. journalctl --since "15 minutes ago" | grep -iE 'denied|apparmor|selinux|audit'

Check symlinks and special bits

Symlinks, setuid bits, sticky directories, and ACLs can make a simple mode display misleading.

Why this page is safe to share

The repair path starts with inspection commands that explain where access breaks. Share the page instead of a chmod command so parent-directory execute bits, service users, ACLs, and SELinux/AppArmor notes stay visible.

Bad fixes to avoid

Avoid chmod -R 777, recursive chown without knowing the service user, changing every parent directory, or disabling SELinux/AppArmor before reading denial logs.

Common causes

  • Missing execute bit on a parent directory
  • Wrong owner or group after deploy
  • ACL overriding simple mode bits
  • Symlink target with stricter permissions
  • SELinux/AppArmor denial even when Unix mode looks correct

What not to change yet

  • Do not run chmod -R 777.
  • Do not chown a whole web root without knowing the service user.
  • Do not change symlink targets before checking the full path chain.
  • Do not change every parent directory to make one path work.
  • Do not disable SELinux/AppArmor before reading denial logs.

Stop and escalate if

  • The path belongs to a system service, package manager, database, or shared production directory.
  • The tempting fix is recursive chmod or chown and you cannot explain every affected path.
  • The command output exposes secrets, keys, customer files, or private user data.

platform notes

Distro and service notes

Web servers

Nginx/Apache usually read as www-data, nginx, apache, or a configured service user.

macOS

BSD stat/namei behavior differs; use macOS-specific pages for Apple Terminal workflows.

SELinux/AppArmor

If modes look correct, check mandatory access-control logs before broad chmod/chown.

supporting commands

Command path

Guides and drills