Security

Web server users and file permissions: www-data, nginx, nobody and suEXEC

Which Linux user your web server and PHP run as, how that decides what they can read and write, safe ownership and permission patterns for websites, and how hosting panels isolate users.

IntermediateLinux VPS3 min read

Every web server and PHP process runs as a Linux user. That web server user decides which files can be read, which can be changed, and how much damage a hacked plugin can do. Most "Permission denied" errors and many security incidents come down to getting this wrong. This guide explains the users involved and safe permission patterns.

Before you start

Who runs what

SoftwareDefault user
Apache on Debian/Ubuntuwww-data
Apache on AlmaLinux/Rockyapache
Nginxwww-data (Debian) or nginx (RHEL family)
OpenLiteSpeednobody
PHP-FPM poolWhatever user = says in the pool (default same as web server)

The master process starts as root to bind ports 80/443, then workers drop to the unprivileged user. Check with ps -eo user,comm | grep -E 'nginx|apache|httpd|php-fpm|lsphp'.

Two users matter: web server and PHP

  • The web server user must read static files (CSS, images) and be able to traverse directories.
  • The PHP user must read code and write only where the app needs: uploads, cache, sessions.

When both are the same shared user (e.g. www-data) for every site, any compromised site can modify every other site. Running each site's PHP as its own user fixes that: PHP-FPM pools per site.

A safe permission pattern for one site

Site owner siteuser, PHP pool running as siteuser, web server www-data in the siteuser group:

sudo chown -R siteuser:siteuser /var/www/example.com
sudo find /var/www/example.com -type d -exec chmod 750 {} \;
sudo find /var/www/example.com -type f -exec chmod 640 {} \;
sudo usermod -aG siteuser www-data
  • Directories 750: owner full, group can read and enter, others nothing.
  • Files 640: owner read/write, group (the web server) read-only.
  • Config files with secrets (wp-config.php, .env) can be 600 when PHP runs as the owner.
  • Restart the web server after changing its group membership.

When PHP runs as the shared web server user

If you must keep a single www-data pool, give the code to a different owner and allow writes only where needed:

sudo chown -R deploy:www-data /var/www/example.com
sudo find /var/www/example.com -type d -exec chmod 750 {} \;
sudo find /var/www/example.com -type f -exec chmod 640 {} \;
sudo chmod -R g+w /var/www/example.com/wp-content/uploads

PHP can then read the code but not change it, which blocks many attacks that try to inject code into existing files. Updates must be run as deploy.

Never use 777

chmod 777 lets every user on the system write the file. It "fixes" permission errors by removing all protection and is a common entry point for malware. Find and fix such files:

find /var/www -perm -0002 -type f -print

How hosting panels isolate users

On cPanel servers each account is a separate Linux user. PHP runs as that user (suEXEC-style), so files are typically 644 and directories 755 owned by the account. On MdmHost, CloudLinux CageFS additionally gives every account its own virtual filesystem, so one account cannot even see others' files.

SELinux on AlmaLinux and Rocky

Even with correct Unix permissions, SELinux can block access. Web content needs the httpd_sys_content_t label, and writable folders httpd_sys_rw_content_t:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/example.com/uploads(/.*)?"
sudo restorecon -Rv /var/www/example.com

Troubleshooting

  • 403 on static files: the web server user can't traverse a parent directory. Check every level with namei -l /var/www/example.com/public/index.html.
  • Plugin or upload can't write: PHP user lacks write permission on that folder only. Grant it there, not site-wide.
  • Correct permissions but still denied on RHEL: SELinux context. Check ls -Z and the audit log.

FAQ: web server users and permissions

Should files be owned by www-data?

Not all of them. Ownership by www-data lets any PHP code on the server rewrite them. Prefer a separate owner.

What permissions does WordPress need?

Typically 644/755 when PHP runs as the file owner, with uploads writable.

Is suEXEC still used?

The idea is: modern setups achieve it with per-user PHP-FPM pools or LiteSpeed's per-user lsphp.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.