Configure PHP on TurboStack

Select a PHP version per application on TurboStack and tune PHP-FPM, OPcache and ionCube through the supported YAML keys.

Each application chooses its own PHP version and, optionally, its PHP-FPM and OPcache tuning.

The PHP panel under Configure application > Technologies, enabled, with the Select PHP Version field and Advanced Settings expanded to show the PHP-FPM worker fields, the tmp dir option and Enhance Opcache
The PHP panel under Configure application > Technologies, enabled, with the Select PHP Version field and Advanced Settings expanded to show the PHP-FPM worker fields, the tmp dir option and Enhance Opcache

Where to configure it

PHP is configured per application:

  1. Open the application.
  2. Go to Configure application > Technologies > PHP.
  3. Select the PHP version (and adjust advanced settings if needed).

Installed versions and the host default come from the host-level php_versions and php_main_version settings.

YAML configuration

Required

Key Meaning
php_version PHP version for this application/vhost, e.g. "8.4".

Optional

A PHP-FPM worker is one PHP process that handles one request at a time, so the number of workers sets how many PHP requests the application can serve at once.

Key Meaning
php_fpm_pm_start_servers Number of PHP-FPM worker processes started initially.
php_fpm_pm_min_spare_servers Minimum number of idle PHP-FPM workers kept ready.
php_fpm_pm_max_spare_servers Maximum number of idle PHP-FPM workers kept ready.
php_fpm_pm_max_children The ceiling on workers this application may run at once. Inherited from the host unless you set it here.
php_fpm_pm_max_requests How many requests a worker handles before it is restarted. Inherited from the host (500) unless you set it here.
php_user_tmp_dir Gives the application its own temporary folder instead of the shared one. Off by default.
php_enhance Enable OPcache performance enhancements for the site.
php_opcache_preload_script Path to a script preloaded into OPcache at startup.
php_ioncube_enabled Enable the ionCube loader (for ionCube-encoded apps).
php_versions Host-level: PHP versions installed on the host.
php_main_version Host-level: default PHP version for the host.
# Per-application
php_version: "8.4"

# Optional PHP-FPM tuning
php_fpm_pm_start_servers: 5
php_fpm_pm_min_spare_servers: 3
php_fpm_pm_max_spare_servers: 6
# php_fpm_pm_max_children: 40      # ceiling on concurrent workers
# php_fpm_pm_max_requests: 500     # restart a worker after this many requests
# php_user_tmp_dir: true           # a private tmp folder for this application

# Optional OPcache + ionCube
php_enhance: true
php_opcache_preload_script: "/var/www/prod/preload.php"
php_ioncube_enabled: false

# Host-level
php_versions:
  - "8.3"
  - "8.4"
php_main_version: "8.4"

Worker ceiling and recycling

php_fpm_pm_max_children is the hard limit on how many requests this application can process at the same time. Every worker holds its own memory, so the ceiling multiplied by the memory a request uses is the worst case for this application. Set it too high and a traffic peak pushes the host out of memory; set it too low and requests queue and time out. See Out of memory and Performance tuning.

php_fpm_pm_max_requests restarts a worker after that many requests. Restarting reclaims whatever the process leaked, which keeps a slowly growing application stable without a scheduled restart.

Both are inherited from the host when you leave them out, so set them per application only when one site needs to differ from the rest.

A private temporary folder

With php_user_tmp_dir: true the application gets its own tmp folder under its home directory, owned by its own user, and PHP's sys_temp_dir points at it. Without it, applications share the system temporary folder. Turn it on when several applications run on one host and you do not want uploads, sessions or generated files landing in a place another application can read.

OPcache preloading

Normally PHP loads the parts of your framework it needs on every request. Preloading loads them once, when PHP starts, and keeps them in memory for every request after that. For a framework that supports it, such as Symfony or Laravel, that is a noticeable speed gain.

Point php_opcache_preload_script at the script your framework provides:

php_opcache_preload_script: "/var/www/prod/preload.php"

Three rules decide whether it works at all:

  • One application per PHP version. PHP loads exactly one preload script per PHP version, for the whole server. If two applications on the same PHP version both set the key, the deployment stops with an error. Give one of them a different php_version, or set the key on only one.

  • The file must exist when you publish, or the deployment fails.

  • Preloading is available on the platform's standard Linux hosts, not on control-panel hosts.

Applying a change

This is the part that surprises people, so it is worth being precise. Two different things can change, and they need different actions.

What changed What to do
The setting php_opcache_preload_script Nothing extra. Publish the host and TurboStack applies it.
The contents of the preload script Reload PHP yourself: sudo systemctl reload php<version>-fpm.service

Publishing does not help in the second case, because nothing in your host configuration changed - only a file on disk. And preloaded code is deliberately held outside the normal OPcache, so clearing that cache does not refresh it either.

# You edited /var/www/prod/preload.php. Apply it:
sudo systemctl reload php8.4-fpm.service

The reload takes about a tenth of a second and serves visitors throughout. It applies to every application on that PHP version - see Administrator access.

What does not work

This does not apply a preload change Why
tscli opcache clear It clears the ordinary OPcache. Preloaded code is kept separately and survives it.
Reloading or restarting Nginx Nginx passes requests to PHP. It holds no PHP code.
Publishing the host again Your configuration did not change, so nothing is applied.
tscli php kill It does work, but it stops all PHP on the host for roughly 15 to 20 seconds. The reload above does the same thing with no downtime.

Common tasks