Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Per-customer users and pools

The concrete setup that gives each customer's Exponential site its own operating-system user, its own PHP-FPM pool or Velocity instance, its own crontab and its own database user, with ownership and modes for code, var/…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/hosting/security/per-customer-users-and-pools.md

On this page

Per-customer users and pools

This page is for the system administrators of a host who build the per-customer setup on a shared machine. It turns the principle of Multi-tenant isolation into users, pools, crontabs and file modes. The procedure behind it is Chapter 8, File permissions and ownership and 13.11.

Contents

  1. The target
  2. The user
  3. Ownership and modes
  4. A PHP-FPM pool per customer
  5. A Velocity instance per customer
  6. Cron and console as the customer's user
  7. When two users must write
  8. Database users
  9. Checks
  10. Checklist

The target

customer A                               customer B
  user  site-a, group site-a               user  site-b, group site-b
  PHP-FPM pool "site-a" (or Velocity)      PHP-FPM pool "site-b" (or Velocity)
  crontab of site-a                        crontab of site-b
  database "a", database user "a"          database "b", database user "b"
  /var/www/vhosts/<domain-a>/              /var/www/vhosts/<domain-b>/

"Problems with permissions almost always come from two users writing the same files" (8.7.2). So one user writes each site: the pool or the Velocity workers, the cronjobs and the console scripts all run as that customer's user.

The user

One operating-system user and group per customer installation, created by your provisioning or your panel (panels usually create one per subscription; check your panel's documentation). Shell access for the customer is a plan decision (Cron and shell access).

Ownership and modes

PathOwnerWritable by the site's userWhy
var/ and belowsite user, site groupyescaches, logs, uploads, autoloads
settings/, settings/override, settings/siteaccesssite user, site groupyes, while administrators change settings in the browsersettings written by the administration
design/, extension/another user (deploy user), or the site user during package installsonly while packages are installed from the administrationpackage installation
kernel/, lib/, vendor/, index.phpanother usernoa compromised PHP process cannot change code
settings/override/*.ini.append.phpsite user or root, group the site's group0640 or strictersecrets

Set the hardened modes that site.ini recommends instead of the shipped 0777/0666:

# settings/override/site.ini.append.php
[FileSettings]
StorageDirPermissions=0770
StorageFilePermissions=0660
TemporaryPermissions=0770
LogFilePermissions=0660

and fix existing files once, with the site's group on everything (13.11):

find var -type d -exec chmod 2770 {} +
find var -type f -exec chmod 0660 {} +

Give each site its own TemporaryDir below var/ instead of the shared /tmp/.

A PHP-FPM pool per customer

"The pool runs PHP as the site's user" (8.5.2). Per pool set the user and group, and the PHP values Exponential needs (memory_limit at least 256M, max_execution_time, upload_max_filesize, post_max_size, OPcache on). Where pools live and how to reload the right master: PHP selection and FPM pools. On machines with several PHP versions, exp:velocity deploy finds the master serving the site ([DeploySettings] PhpFpmService=auto).

Keep session files, upload_tmp_dir and any auto_prepend_file (for example request-shield) per pool, so nothing of one customer lands in another's directory.

A Velocity instance per customer

One Velocity per site, each as the customer's user, bound to 127.0.0.1 behind a proxy that routes by host name (Velocity beside Apache or nginx):

php bin/php/console exp:velocity config set --apply ServerSettings User site-a --allow-root-user
php bin/php/console exp:velocity config set --apply ServerSettings Group site-a --allow-root-user
php bin/php/console exp:velocity restart --allow-root-user
  • Who the workers become: [ServerSettings] User and Group, else VC_RUN_USER and VC_RUN_GROUP, else the owner of the document root. A document root owned by root with nothing configured leaves the workers as root; the start says so (8.3.5).
  • AllowRootWorkers=disabled (the default) refuses root as the worker user.
  • Each instance needs its own ports; the per-site file /etc/vc/sites-available/<site>.conf is mode 0600.
  • Workers and pool sizes per plan: Velocity workers and pools.

Cron and console as the customer's user

Cronjobs from that user's crontab, or with sudo -u:

crontab -u site-a -e
# */5 * * * * cd /var/www/vhosts/<domain-a>/<installation> && php runcronjobs.php -q frequent
sudo -u site-a php bin/php/ezcache.php --clear-tag=ini

Exponential's command-line scripts refuse to run as root unless --allow-root-user is given; use it only for the documented root tasks, and check afterwards that files in var/ still belong to the site's user (Security hardening).

When two users must write

If the users must differ (for example the web server's PHP user and a deploy user), give them a common group, make the writable directories group-writable and setgid so new files inherit the group, and use the group-preserving modes above (8.7.2):

sudo chgrp -R site-a design extension settings var
sudo find var settings -type d -exec chmod 2775 {} +

When Apache (PHP-FPM) and Velocity serve the same installation side by side, they share var/, the caches and the sessions: give them the same user or this group setup, and look at the owner of new files in var/ after a few requests.

Database users

One database and one database user per installation, with rights on that database only; the connection is written to settings/override/site.ini.append.php. Per-engine notes, in the official order 1. SQLite 3 · 2. PostgreSQL · 3. MongoDB · 4. MariaDB · 5. Oracle · 6. MySQL: Databases and users and Databases in the official order. With SQLite 3 there is no database user: the file below var/storage/sqlite3/ is protected by the site user's file permissions.

Checks

# no world-writable settings files
find settings extension/*/settings -perm -o+w
# who owns new files after some traffic (expect the site's user and group)
find var -newer index.php -not -user site-a | head
# which user each PHP-FPM pool runs as
ps -eo user,cmd | grep 'php-fpm: pool' | grep -v grep

The first must print nothing (13.11).

Checklist

  • To do: One operating-system user and group per installation.
  • To do: Pool or Velocity workers, cron and console all run as that user.
  • To do: Code owned by another user and read-only to the site's user.
  • To do: Hardened [FileSettings]; no world-writable files; settings/override 0640 or stricter.
  • To do: Per-site TemporaryDir, session directory and upload directory.
  • To do: Velocity: User, Group set; bound to 127.0.0.1 behind the proxy; own ports per instance.
  • To do: One database and database user per installation.
  • To do: The checks above run after provisioning and after every deploy.

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x