Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/wikioasis/salt/llms.txt

Use this file to discover all available pages before exploring further.

The php state installs a specific PHP version and a curated set of extensions required by MediaWiki, then writes the PHP-FPM pool configuration from a Jinja template controlled entirely by pillar. Process manager settings such as pm.max_children, start servers, spare server counts, and request limits are all tunable per environment without modifying any template files. The service is managed by Salt and automatically reloads whenever the pool configuration changes.

Package installation

The state reads php:version, php:extensions, and php:extra_packages from pillar to build a single pkg.installed call:
install_php:
  pkg.installed:
    - pkgs:
      - php8.4
      - php8.4-fpm
      - php8.4-mysql
      - php8.4-xml
      - php8.4-mbstring
      - php8.4-intl
      - php8.4-curl
      - php8.4-gd
      - php8.4-zip
      - php8.4-apcu
      - php8.4-igbinary
      - php8.4-redis
      - php-excimer
      - php-luasandbox
The php:version prefix is prepended to each extension name automatically. extra_packages (like php-excimer and php-luasandbox) are installed as-is since they are version-independent.

Pillar keys

KeyDefaultDescription
php:version8.3PHP version to install (e.g. 8.4)
php:extensions[fpm, mysql, xml, mbstring, intl, curl, gd, zip, apcu, igbinary]Extension suffixes appended to php<version>-
php:extra_packages[php-excimer]Additional packages installed without a version prefix
php:fpm:poolwwwFPM pool name and config filename
php:fpm:listen(derived)Listen address; defaults to unix:/run/php/php<version>-fpm.sock
php:fpm:pmdynamicProcess manager mode: dynamic, static, or ondemand
php:fpm:pm_max_children10Maximum number of child processes
php:fpm:pm_start_servers2Servers started at launch (dynamic mode)
php:fpm:pm_min_spare_servers1Minimum idle servers kept alive (dynamic mode)
php:fpm:pm_max_spare_servers3Maximum idle servers to keep alive (dynamic mode)
php:fpm:pm_max_requests500Requests per worker before respawn (memory leak prevention)
php:fpm:request_terminate_timeout60Seconds before a worker is hard-killed

Production pillar

# pillar/php/init.sls
php:
  version: "8.4"
  extensions:
    - fpm
    - mysql
    - xml
    - mbstring
    - intl
    - curl
    - gd
    - zip
    - apcu
    - igbinary
    - redis
  extra_packages:
    - php-excimer
    - php-luasandbox
  fpm:
    pool: www
    listen: ""
    pm: dynamic
    pm_max_children: 10
    pm_start_servers: 6
    pm_min_spare_servers: 6
    pm_max_spare_servers: 8
    pm_max_requests: 500
    request_terminate_timeout: 60
  monitoring:
    queue_warn: 5
    queue_crit: 10
pm_start_servers, pm_min_spare_servers, and pm_max_spare_servers are only written to www.conf when pm is dynamic. They are omitted for static or ondemand modes.

www.conf.jinja template

The pool configuration is written to /etc/php/<version>/fpm/pool.d/<pool>.conf from this template:
; Managed by Salt — do not edit manually.

[{{ pool }}]

user = www-data
group = www-data

listen = {{ listen }}
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
listen.acl_users = www-data,nagios

pm = {{ fpm.get('pm', 'dynamic') }}
pm.max_children = {{ fpm.get('pm_max_children', 10) }}
{%- if fpm.get('pm', 'dynamic') == 'dynamic' %}
pm.start_servers = {{ fpm.get('pm_start_servers', 2) }}
pm.min_spare_servers = {{ fpm.get('pm_min_spare_servers', 1) }}
pm.max_spare_servers = {{ fpm.get('pm_max_spare_servers', 3) }}
{%- endif %}
pm.max_requests = {{ fpm.get('pm_max_requests', 500) }}

request_terminate_timeout = {{ fpm.get('request_terminate_timeout', 60) }}

ping.path = /ping
ping.response = pong
pm.status_path = /status

Notable settings

listen.acl_users

The socket is readable by www-data and nagios, allowing the monitoring agent to check the FPM status page without a dedicated listen address.

pm.max_requests

Workers are recycled after 500 requests by default. This acts as a safety valve against PHP memory leaks in long-running extensions.

ping / status

The /ping and /status paths are enabled on all pools for health-check and monitoring use.

request_terminate_timeout

Requests running longer than 60 seconds are hard-killed. This prevents runaway maintenance scripts from blocking the pool.

Service management

The PHP-FPM service is declared as php<version>-fpm and is set to watch the pool config file:
php8.4-fpm:
  service.running:
    - enable: True
    - watch:
      - file: /etc/php/8.4/fpm/pool.d/www.conf
Any change to the pool configuration automatically triggers a service reload on the next state.apply.

Applying the state

salt 'mw*' state.apply php
To check the PHP-FPM status on all web servers after applying:
salt 'mw*' cmd.run 'php-fpm8.4 -t'
When tuning pm_max_children for a new server class, start conservative (e.g. 10) and monitor the FPM status page at http://127.0.0.1/status to observe active/idle worker counts under real load before increasing.

Build docs developers (and LLMs) love