Skip to content

How to set up PHP-FPM

As mentioned on the official website, PHP-FPM (FastCGI Process Manager) is is an alternative PHP FastCGI implementation with some additional features (mostly) useful for heavy-loaded sites.

It allows PHP to run as its own process under its own user, separate from Apache, unlike mod_php. It also makes it possible to use multiple PHP versions from the same Apache setup.

In order to use php-fpm to serve a website, follow the steps below.

System service

You will need to have one system service for each version of php-fpm you may want to run concurrently (e.g. PHP5 and PHP7). The SysV-style init script is bundled with your PHP. For instance, for a phpbrew-based installation of PHP 7.2.15 in /opt/phpbrew:

sudo cp /opt/phpbrew/build/php-7.2.15/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm-7.2.15
sudo chmod +x /etc/init.d/php-fpm-7.2.15

You may want to tweak the code of the script so it prints php-fpm-7.2.15 rather than just php-fpm, but it is not necessary.

Before you can run this, you have to tweak the php-fpm.conf file, which is usually close to where the relevant php.ini is. For this phpbrew-based install, it would be in /opt/phpbrew/php/php-7.2.15/etc/php-fpm.conf. Make sure you uncomment the line mentioning the pid variable, so that a PID file is created.

You will also need to ensure that both user and group are set to the appropriate one in the php-fpm.d/www.conf file. It would be even better if you used an app-specific user, to isolate PHP applications from each other.

Once these tweaks are ready, start the service manually and check it started correctly with:

sudo /etc/init.d/php-fpm-7.2.15 start
sudo /etc/init.d/php-fpm-7.2.15 status

Make sure you register the service to be started on boot:

sudo systemctl enable php-fpm

Reloading the PHP OPCACHE

When a new version of a website is deployed via FPM, PHP does not automatically flush its OPCODE cache, which means that users will see the old version of the application. In order to force this to happen, the following needs to be added to the project.sh file:

# Ensure PHP FPM is reloaded (picks up new code)
if test -x /usr/sbin/service; then
  sudo -n /usr/sbin/service php7.2-fpm reload
fi

This means that gitlab-runner, which runs as an unprivileged user, needs to call sudo. To make this happen, on Ubuntu servers, run sudo visudo and add this to the sudoers file:

gitlab-runner ALL = (root) NOPASSWD: /usr/sbin/service php7.2-fpm reload

Note that the command itself is run with sudo -n, so it will never prompt for a password and just fail if it were to ask for a password. See this guide for more details on editing sudoers on Ubuntu.

Apache virtual host (UNIX socket-based)

To switch from mod_php to php-fpm, go to your <VirtualHost> and change it to use ProxyPassMatch for any .php files:

ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/opt/phpbrew/php/php-7.2.15/var/run/php-fpm.sock|fcgi://localhost/path/to/document/root

This must be done at the <VirtualHost> level: it cannot be done from a <Directory>.

Apache virtual host (TCP socket-based)

On SELinux-happy environments, it may be easier to tweak the php-fpm.d/www.conf file to listen on a TCP port:

listen = 127.0.0.1:port

You can then tell Apache to use that TCP socket, with a slightly different syntax. This used to be necessary on CentOS servers - it may not be necessary on Ubuntu servers.

By the way, this syntax can be used to forward specific subfolders in a <VirtualHost> to specific versions of PHP (as done in the Industry Club website):

ProxyPassMatch "^/folder/(.*\.php(/.*)?)$" fcgi://127.0.0.1:9007/path/to/folder/$1