Deploy website files with SSH keys, rsync previews and limited access
Separate deployment access from account administration, preview rsync changes and verify a release without exposing credentials or deleting target data blindly.
Read the guideVPS security · Practical guide
Use stat, namei and find to diagnose Linux website permissions, separate writable data from code and apply targeted changes instead of chmod 777.
Archive placement: December 2024

A permission problem is usually about which account runs a process, who owns a file and which directories must be traversed to reach it. Changing everything to world-writable hides that model and increases the damage a compromised application can cause. This guide shows how to diagnose the actual access path before making a focused change.
id
ps -eo user,group,comm | grep -E 'nginx|apache2|php-fpm'
stat -c '%U:%G %a %n' /srv/www/example-app
namei -l /srv/www/example-app/public/index.phpThe deployment user, web-server worker and application runtime can be different identities. A reverse proxy may read public files while a PHP worker needs access to application configuration and a cache directory. Determine the actual users and groups from your service configuration, not just from a process name copied from another server.
namei shows each directory in the path. Reading a file requires the relevant traversal permissions on its parents as well as permission on the file itself. This explains why a file can have apparently correct read bits but still produce a permission-denied error.
For ordinary files, read permits reading the contents, write permits changing them and execute permits execution as a program where the format supports it. Directory permissions have different operational effects: execute allows traversal, read lists names and write permits changing directory entries. Removing write access from a file does not necessarily stop someone deleting it through a writable parent directory.
A value such as 755 is an octal representation of owner, group and other permissions. It is not a universal website setting. Common read-only code files might use 644 or 640, but the correct choice depends on the runtime account and whether unrelated users share the machine. Secrets should not become world-readable just because public assets need to be served.
SITE_ROOT='/srv/www/example-app'
test -d "$SITE_ROOT"
find "$SITE_ROOT" -xdev -type d -perm -0002 -print
find "$SITE_ROOT" -xdev -type f -perm -0002 -print
find "$SITE_ROOT" -xdev -type f -perm /111 -printThese lists identify world-writable directories, world-writable files and executable files for review; they do not prove that every result is wrong. A deployment helper can legitimately be executable, while an uploaded image normally should not need that permission. -xdev avoids descending into another filesystem, but symlink destinations and application-managed storage still need separate consideration.
If the acl tools are installed, getfacl -p on the affected file or directory reveals access-control entries that ordinary mode bits do not fully explain. Review effective ACL masks and default ACLs before concluding that chmod alone will fix the issue.
Document which locations genuinely need writes: uploads, cache, sessions, generated files or logs. Keep code and configuration owned by a deployment identity when the application does not need to modify them. Place private configuration outside the public document root where the application supports that layout.
# Assumes deploy owns releases and www-data is the verified runtime group.
sudo chown deploy:www-data /srv/www/example-app/var/cache
sudo chmod 2770 /srv/www/example-app/var/cache
stat -c '%U:%G %a %n' /srv/www/example-app/var/cacheThis example changes only the named directory, not the entire site. The setgid bit makes new entries inherit the directory's group; application umasks and ACLs still influence the permissions of those entries. Do not apply this ownership model to cPanel or another service whose runtime identity differs.
Use the application's normal workflow to test an upload, cache write or deployment. On a VPS you administer, you can also test whether the actual runtime account can read or write a specific path. A successful test as root proves very little about an unprivileged worker.
sudo -u www-data test -r /srv/www/example-app/public/index.php
sudo -u www-data test -w /srv/www/example-app/var/cache
echo "last_check_exit=$?"Each test returns zero on success and nonzero on failure; the final echo only reports the immediately preceding check. If a permission check passes but the application still fails, inspect its logs and other controls such as AppArmor, container mounts or a read-only filesystem. Avoid repeatedly widening Unix permissions to work around a different enforcement layer.
Before a larger permissions repair, record current ownership and mode information and take a suitable backup. Make one targeted adjustment, then retest. Do not run recursive chmod or chown against /, an account home or an unverified variable. Restoring access should preserve the hosting platform's expected ownership model.
Copyright 2026 © Plenty Host Inc. - All Rights Reserved.
By using our services, you agree to our Terms & Conditions and Privacy Policy.
We Accept: 