Skip to content

feat(roles/php): allow for PHP-FPM pools to be configured individually. - #248

Merged
NavidSassan merged 9 commits into
mainfrom
feat/php_fpm_pool
Sep 3, 2026
Merged

feat(roles/php): allow for PHP-FPM pools to be configured individually.#248
NavidSassan merged 9 commits into
mainfrom
feat/php_fpm_pool

Conversation

@ebuerki-lf

Copy link
Copy Markdown
Contributor

No description provided.

@ebuerki-lf
ebuerki-lf requested a review from NavidSassan May 12, 2026 17:03
@ebuerki-lf

ebuerki-lf commented May 13, 2026

Copy link
Copy Markdown
Contributor Author
  • support for Debian os family
  • update docs, examples
  • update template timestamps
  • use idiomatic paths for logs / socket, opcache / session cache for Debian
  • creation and cleanup of per-pool session.save_path
  • add validation logic

Comment thread tests/unit/plugins/modules/test_sqlite_query.py Fixed
Comment thread plugins/modules/sqlite_query.py Fixed
@ebuerki-lf

ebuerki-lf commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

the systemd service on debian (php 8.4, sury repo) contains ExecStartPost ExecStopPost entries that execute /usr/lib/php/php-fpm-socket-helper. it is not present on rocky (php 8.4, remi repo).

Debian

/usr/lib/systemd/system/php8.4-fpm.service

[Unit]
Description=The PHP 8.4 FastCGI Process Manager
Documentation=man:php-fpm8.4(8)
After=network.target

[Service]
Type=notify
ExecStart=/usr/sbin/php-fpm8.4 --nodaemonize --fpm-config /etc/php/8.4/fpm/php-fpm.conf
ExecStartPost=-/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/8.4/fpm/pool.d/www.conf 84
ExecStopPost=-/usr/lib/php/php-fpm-socket-helper remove /run/php/php-fpm.sock /etc/php/8.4/fpm/pool.d/www.conf 84
ExecReload=/bin/kill -USR2 $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target

Rocky

/usr/lib/systemd/system/php-fpm.service

# It's not recommended to modify this file in-place, because it
# will be overwritten during upgrades.  If you want to customize,
# the best way is to use the "systemctl edit" command.

[Unit]
Description=The PHP FastCGI Process Manager
After=network.target

[Service]
Type=notify
ExecStart=/usr/sbin/php-fpm --nodaemonize
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true
RuntimeDirectory=php-fpm
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target

@NavidSassan
NavidSassan force-pushed the feat/php_fpm_pool branch 2 times, most recently from 1d4e762 to 458f002 Compare September 2, 2026 16:27
ebuerki-lf and others added 9 commits September 3, 2026 12:20
One pool template replaces the per-family Debian-pool.conf.j2 and
RedHat-pool.conf.j2, and every pool carries its own user and group, process
manager tuning, timeouts and php_admin_value overrides, so several
applications can share a host without sharing a PHP process, a session store
or a memory limit.

Each pool gets an isolated session directory below the distribution session
base, its own error and slow log in the per-service log directory, and its
own socket. The role creates those directories, relabels them on SELinux
hosts, and ships a logrotate config on Debian, where the packaged one only
covers the single global log file.

pm.max_spawn_rate is only rendered from PHP 8.1 on. The directive does not
exist before that and php-fpm refuses to start with "unknown entry", which
would break RHEL 8 and RHEL 9 with their distribution PHP. Verified on
Rocky 9: rejected by 8.0, accepted by 8.1.32.

request_terminate_timeout defaults to 60s so a worker that outlives the web
server timeout is reclaimed instead of occupying its slot indefinitely.

The status and ping paths stay at /fpm-status and /fpm-ping for every pool:
the path never distinguished pools, the socket does, and the Monitoring
Plugins, their Director baskets and the localhost vHost of the apache_httpd
role all default to those paths.
Role entry now validates the user-facing variables and rejects unknown ones.
The numeric __ini_* and __fpm_pool_conf_* slots are declared as raw, since an
int spec would reject their empty default.

vars/Ubuntu.yml is an explicit copy of vars/Debian.yml, per CONTRIBUTING: it
keeps Ubuntu visible and gives later Ubuntu-specific drift a home.
A second pool with a static process manager and its own php_admin_value
memory limit is deployed alongside the default www pool, and both are asked
what they are actually running through their own sockets. That proves the
pool reached the running workers, that a pool cannot be raised past its
php_admin_value with ini_set(), and that each pool keeps its own private
session directory.
Both PHP-FPM URLs of the localhost vHost are served by the www pool. Document
how a host with further pools publishes them, one Location per pool socket,
keeping /fpm-status as the path sent to FPM.
…emplates

Every php__ini_*__role_var the templates reference is set in each
vars/<version>.yml, so the __combined_var always resolves and the inline
defaults never applied. Rendered output is unchanged, verified byte for byte
against a Rocky 9 host, hence no timestamp bump in the templates.
php_admin_value[session.save_handler] was hardcoded to files, which an
application cannot override via ini_set() since it is a php_admin_value.
A host that has to share sessions across machines, behind a load balancer
or a TLS-terminating proxy, needs redis or memcached instead.

A pool that stores its sessions elsewhere also gets no session directory:
its save_path is a connection string, not a path.
…both families

The template had two branches only because the two distribution default pool
files differ: Debian hands the socket to the webserver via listen.owner /
listen.group, RedHat grants an ACL entry via listen.acl_users. Both mechanisms
work on both families, verified on Debian 13 with php-fpm 8.4 and on Rocky 9,
so the role now uses one path.

acl_users decouples socket access from the pool own identity, which is what
per-pool users need: a pool running as its own user still hands the webserver
an explicit ACL entry on a root-owned socket. It also takes a list, so a second
webserver user is a value change rather than a template change.

On Debian the socket therefore changes from www-data:www-data to root:root plus
an ACL entry. Nothing in LFOps reads it: apache_httpd addresses the socket by
path, and php-fpm-socket-helper parses the `listen =` line out of www.conf.
…d pool file

Following the "Deviating from an Upstream Default" section of CONTRIBUTING.md,
the packaged pool files are now vendored under vars/vendor/ as the baseline
they are measured against, every remaining deviation carries an "upstream
default" comment where the value is defined and a "Deviates from" bullet in
the README, and the review turned up three changes worth making:

listen.acl_users becomes a per-pool list. The RedHat package grants
apache,nginx; the role grants only the webserver LFOps deploys and lets a host
serving through another user add it, instead of editing the template.

listen.allowed_clients is no longer rendered. php-fpm applies it to tcp
sockets only, and every pool here listens on a unix socket, so the line looked
like an access restriction while enforcing nothing.

soap.wsdl_cache_dir is set again, per pool. Dropping it left the SOAP
extension caching parsed WSDL files in /tmp, which on RedHat is the unit
PrivateTmp namespace and therefore lost on every restart, and on Debian the
shared /tmp. A cached WSDL carries the internal endpoints of the service it
describes, so it gets the same per-pool treatment as the session directory.
Verified on Rocky 9 with php-soap installed: the running worker reports the
per-pool directory.

Also removes a duplicated php__fpm_pools entry: the README documented it in two
sections with two different defaults.
The php molecule scenario passes on rocky10-vm, converge, verify and
idempotence, alongside the four targets already marked proven.
@NavidSassan
NavidSassan merged commit f62662f into main Sep 3, 2026
12 checks passed
@NavidSassan
NavidSassan deleted the feat/php_fpm_pool branch September 3, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants