Documentation

Server 3.x

PHP Tuning#

Unfortunately, if your service becomes more popular, your server may get more requests than allowed by the default PHP (FPM) configuration.

The defaults are documented here and are used by Debian (and Ubuntu) out of the box. On Fedora and Enterprise Linux, they are updated to be more realistic for real world load and documented here.

In particular we care about the pm.* (Process Manager) variables which are the most relevant.

The default PHP project and Debian / Ubuntu values:

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

On Fedora / Enterprise Linux:

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

Until now (2024-07-08) we used the values of Fedora / Enterprise Linux on Debian / Ubuntu as well. On Debian / Ubuntu we create the file /etc/php/PHP_VERSION/fpm/pool.d/www_vpn.conf that contained the update values, where PHP_VERSION is the installed PHP version, which can be found on Debian / Ubuntu by running /usr/sbin/phpquery -V.

Unfortunately, these values can result in trouble on the default installation, and actually make it easy to DoS the server. The problem is that, if not enough memory is available for these configuration values, the PHP process can get nominated by the OOM killer.

In order to solve this, it is important to tweak these values to the actual system configuration.

From 2024-07-08, on new deploys we will tweak these values automatically based on the system configuration using this script. If you installed your system before that date, you can use its output, when running it on your portal/controller to tweak the values for your setup.

On Fedora / Enterprise Linux, the configuration is written to /etc/php-fpm.d/www_vpn.conf, on Debian / Ubuntu it is written to /etc/php/PHP_VERSION/fpm/pool.d/www_vpn.conf, where PHP_VERSION is the installed PHP version, which can be found on Debian / Ubuntu by running /usr/sbin/phpquery -V.

Local Accounts#

When using “Local Accounts”, the default, PHP needs (a lot) more memory than without it. The reason for this is that the password hashing function used, Argon2id, requires a lot (64 MB) of memory. This is to make it harder to retrieve the password from the hash.

Our analysis resulted in PHP needing about ~7 MB maximum during normal operation to handle a request. We rounded this up to 16 MB to have a bit extra memory available. So for the situation where “Local Accounts” are used, we could imagine requiring 64 + 16 = 80 MB. This is the value that is used when the --local flag is specified to the php_fpm_limits.sh script. Without it, 16 MB is used.

Configuration#

You can run the php_fpm_limits.sh script on your controller/portal. It will help you print the values that are (as of this moment) most appropriate for your setup.

For example, when running this on a VM with 2GB of memory and 1 CPU core with the --local flag which indicates you are using “Local Accounts”:

$ sh ./php_fpm_limits.sh --local
; PHP tuning for VPN server
; #CPUs: 1
; #Total Memory: 1967
; #Process Memory: 80
; See: https://docs.eduvpn.org/server/v3/php-tuning.html
[www]
pm = dynamic
pm.max_children = 18
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4

You probably want to re-run this script if you change your system configuration, e.g. add more CPU cores or add more memory, or switch from “Local Accounts” to e.g. LDAP or SAML. In the latter case, without the --local flag.

Open Questions#

We probably also have to update the Apache (MPM) configuration, the default values, as configured in /etc/apache2/mods-available/mpm_event.conf on Debian may not be appropriate after we modify the PHP configuration. More work (and understanding) is needed here. If you can help, please contact us!

Some other components, for example php-saml-sp can also use additional PHP memory, for example to read/parse the SAML metadata during authentication. This also MUST be considered when big(ger) metadata files are used.

Resources#

We tried to find good resources for configuring PHP. Unfortunately there is no one “right answer”, but these resources were still very helpful in trying to understand how to properly configure PHP.