Skip to main content
Skip to main content

PHP Runtime Tuning on Zerops

Override php.ini via PHP_INI_* env vars, FPM via PHP_FPM_*. Both require restart (not reload). Zerops defaults: upload/post = 1024M, FPM dynamic 20/2/1/3. Upload bottleneck is L7 balancer (50MB subdomain), not PHP.

PHP Configuration (PHP_INI_*)

Override any php.ini directive via PHP_INI_{directive} env vars in run.envVariables or via zerops_env API.

Requires restart to take effect. Reload writes config files (/etc/php*/conf.d/overwrite.ini) but FPM master does not re-read INI on reload.

Zerops Platform Defaults

Zerops overrides several stock PHP values for production use:

DirectiveZerops defaultStock PHPWhy
upload_max_filesize1024M2MGenerous upload limit (L7 balancer is the real gate)
post_max_size1024M8MMatches upload limit
display_errorsoffonProduction: errors to logs, not browser
error_reporting2252732767E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors10Errors go to log files
output_buffering40960Buffered output for performance
date.timezoneUTC(empty)Consistent timezone
sendmail_path/usr/sbin/sendmail -t -i(empty)System sendmail wired

Example

zerops:
- setup: app
run:
base: php-nginx@8.4
envVariables:
PHP_INI_upload_max_filesize: 10M
PHP_INI_post_max_size: 12M
PHP_INI_memory_limit: 256M
PHP_INI_max_execution_time: 60
PHP_INI_max_input_vars: 5000

PHP-FPM (PHP_FPM_*)

Configure FPM process management via PHP_FPM_* env vars. Requires restart — same as PHP_INI.

Config files are written to /etc/php*/php-fpm.d/www.conf by zerops-zenv at container startup.

Dynamic Mode (default)

Pre-forks a pool of workers. Good for consistent traffic.

VariableDefault
PHP_FPM_PMdynamic
PHP_FPM_PM_MAX_CHILDREN20
PHP_FPM_PM_START_SERVERS2
PHP_FPM_PM_MIN_SPARE_SERVERS1
PHP_FPM_PM_MAX_SPARE_SERVERS3
PHP_FPM_PM_MAX_SPAWN_RATE32
PHP_FPM_PM_MAX_REQUESTS500

High-traffic example:

envVariables:
PHP_FPM_PM_MAX_CHILDREN: 50
PHP_FPM_PM_START_SERVERS: 10
PHP_FPM_PM_MIN_SPARE_SERVERS: 5
PHP_FPM_PM_MAX_SPARE_SERVERS: 15
PHP_FPM_PM_MAX_REQUESTS: 1000

Ondemand Mode

Spawns workers only when requests arrive. Saves memory for low-traffic sites.

envVariables:
PHP_FPM_PM: ondemand
PHP_FPM_PM_MAX_CHILDREN: 20
PHP_FPM_PM_PROCESS_IDLE_TIMEOUT: 60s
PHP_FPM_PM_MAX_REQUESTS: 500

Available parameters for ondemand:

  • PHP_FPM_PM_MAX_CHILDREN -- maximum child processes
  • PHP_FPM_PM_PROCESS_IDLE_TIMEOUT -- idle timeout before termination (default: 60s)
  • PHP_FPM_PM_MAX_REQUESTS -- requests per process before recycling (default: 500)

Upload Limits (3-layer chain)

File uploads pass through three layers -- ALL must allow the size:

  1. L7 Balancer: client_max_body_size = 512m (custom domain) / 50MB fixed (subdomain)
  2. PHP: upload_max_filesize = 1024M (Zerops default)
  3. PHP: post_max_size = 1024M (Zerops default)

Zerops pre-configures generous PHP limits, so the L7 balancer is typically the bottleneck:

  • Subdomain (zerops.app): hard 50MB cap, cannot be changed
  • Custom domain: 512m default, configurable via custom Nginx template

Extensions (Alpine)

Install via sudo apk add --no-cache php84-<ext> — version prefix must match PHP major+minor (e.g. php84- for PHP 8.4). Sudo required — containers run as zerops user.

Build and runtime are separate containers with separate images. The build base (php@X) is Alpine-minimal. The runtime base (php-nginx@X, php-apache@X) bundles more extensions but not all.

If a Composer dependency requires an extension that's missing from the build image:

  • Install it in build.prepareCommands so Composer validates platform requirements properly
  • If also needed at runtime, install in run.prepareCommands too (separate container, separate image)
  • Never use --ignore-platform-reqs — it suppresses all platform checks, hiding real problems that crash at runtime

Common extensions not in the build base: ext-pcntl, ext-posix (needed by Horizon), ext-gd, ext-intl.

build:
base: php@8.4
prepareCommands:
- sudo apk add --no-cache php84-pcntl php84-posix
buildCommands:
- composer install --no-dev --optimize-autoloader
run:
base: php-nginx@8.4
prepareCommands:
- sudo apk add --no-cache php84-pcntl php84-posix

Gotchas

  • Reload does NOT apply changes -- PHP_INI_* and PHP_FPM_* both require restart. Zerops reload rewrites config files via zerops-zenv but does not signal FPM to re-read them.
  • Upload fails at 50MB on subdomain -- this is the L7 balancer limit, not PHP. Use a custom domain for larger uploads.
  • post_max_size must be >= upload_max_filesize -- PHP silently drops the POST body if it exceeds post_max_size, even if the file itself is under upload_max_filesize.