Skip to content

Run Apache workers as an unprivileged user

Severity: mediumApplies to: Apache httpd 2.4.xApplies to: Apache httpd 2.4.68
The fixapache2.conf / httpd.conf
User www-data # Debian, Ubuntu
Group www-data
# User apache # RHEL, Rocky, Alma

Distribution packages already do this. The page matters for hand-built installs, containers, and configs where someone set User root to fix a permissions error.

Apache runs as two kinds of process, and only one should concern you:

  • The parent starts as root. It has to: binding ports below 1024 requires privilege, as does reading a properly locked-down TLS private key. It handles no requests.
  • The children parse requests, terminate TLS and run your application. They drop to the configured User.

So one root line in ps is normal. Every other root line is the finding.

The children are where the risk lives. Apache 2.4.68 fixed thirteen CVEs including use-after-free and heap overflow conditions — all in request-handling code, all child-side. Whether such a bug is a contained compromise or a root shell is decided entirely by the User directive.

The document root should not be writable by the web user

Section titled “The document root should not be writable by the web user”

This is the part people skip, and it matters more than the User line on most servers, because the User line is usually already right.

If www-data can write to the directory it serves, then any file-upload bug, any path traversal, any vulnerable CMS plugin can drop a .php file into the web root — and Apache will happily execute it. That’s a web shell from a bug that would otherwise be a nuisance.

Terminal window
sudo chown -R root:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 750 {} +
sudo find /var/www/html -type f -exec chmod 640 {} +
# Only the directories that genuinely need writes:
sudo chown -R www-data:www-data /var/www/html/uploads
sudo chmod 750 /var/www/html/uploads

Serve-only, don’t-write is the default you want; carve out the exceptions.

And for the upload directory that must be writable, stop it executing anything:

<Directory /var/www/html/uploads>
Options -ExecCGI
php_admin_flag engine off
AddType text/plain .php .phtml .php5 .phar
</Directory>

That combination means a .php dropped there is served as plain text, not run.

The private key should not be readable by the workers

Section titled “The private key should not be readable by the workers”

The parent reads SSLCertificateKeyFile at startup while still root, so it does not need to be readable by www-data — and it shouldn’t be:

Terminal window
sudo chown root:root /etc/ssl/private/site.key
sudo chmod 600 /etc/ssl/private/site.key

A key readable by the worker user is a key readable by anything that compromises a worker.