Use separate systemd units for PHP-FPM pools

Normally PHP-FPM runs using a single master process that spawns child processes for each of the pools defined in the configuration.

This is problematic because reloading the configuration for one pool requires reloading them all, and so does adding or removing a pool from the configuration. If there's an error in the configuration of one pool, none of the pools will start.

Resource limits are also applied to all pools together, instead of per pool. For instance, if one users scripts keep forking, at some point the fork limit will be reached and other pools won't be able to spawn child processes anymore, which can lead to service unavailability.

In order to avoid this, we can use a separate systemd unit for each pool, so that they can be managed independently.

These steps were tested on Debian stretch, but should apply to other distributions. Make sure to replace the PHP version with the version you have installed. (I used 7.0.)

Have a look at the existing PHP-FPM systemd unit by running systemd cat php7.0-fpm:

# /lib/systemd/system/php7.0-fpm.service
[Unit]
Description=The PHP 7.0 FastCGI Process Manager
Documentation=man:php-fpm7.0(8)
After=network.target

[Service]
Type=notify
PIDFile=/run/php/php7.0-fpm.pid
ExecStart=/usr/sbin/php-fpm7.0 --nodaemonize --fpm-config /etc/php/7.0/fpm/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target

We'll want to create a similar template unit starting PHP-FPM for just one pool, with its own PID file. That can be done using this configuration:

cat > /etc/systemd/system/php7.0-fpm@.service <<'EOF'
[Unit]
After=network.target

[Service]
Type=notify
PIDFile=/run/php7-fpm-%i.pid
ExecStart=/usr/sbin/php-fpm7.0 --nodaemonize --fpm-config /etc/php/7.0/fpm/pool.d/%i.conf --pid /run/php7-fpm-%i.pid
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target
EOF

Now when you start php7.0-fpm@mypool it will write its PID file to /run/php7-fpm-mypool.pid and use the configuration file /etc/php/7.0/fpm/pool.d/mypool.conf.

Stop and disable the running PHP-FPM master instance, and enable, start the new per-pool units:

V=7.0
systemctl disable php${V}-fpm
systemctl stop php${V}-fpm
ls /etc/php/${V}/fpm/pool.d | grep -oP '^.+(?=\.conf$)' |
    xargs -tn1 -I{} systemctl enable php${V}-fpm@{}
ls /etc/php/${V}/fpm/pool.d | grep -oP '^.+(?=\.conf$)' |
    xargs -tn1 -I{} systemctl start php${V}-fpm@{}