Moving from mod_php to PHP-FPM

After running PHP on Apache httpd for many years with mod_php, I think there is now a clear reason to switch to PHP-FPM:

  1. mod_php only works well with Apache’s Prefork MPM. (Why shouldn’t I use Apache2 with a threaded MPM?)
  2. Starting with httpd 2.4.27, Prefork does not support HTTP/2. (From the httpd 2.4.27 release notes: “mod_http2: Disable and give warning when using Prefork.”)

Using PHP-FPM means we can use for Apache’s Worker or Event MPM, which in turn means we can support HTTP/2.

Moving away from Prefork has other benefits, see: How do I select which Apache MPM to use?

Making the Switch (as per Fedora 26)

Check if you’re using any of PHP’s Apache Functions, as these won’t be available once you stop using mod_php.

Move any PHP settings to .user.ini

If you’re currently changing any PHP settings in Apache configuration files, move these to a .user.ini file which is picked up by PHP-FPM. So e.g., if you have .htaccess file with:

php_value include_path ".:/php_lib"
php_value auto_prepend_file "autoload.php"

Change it to this equivalent .user.ini file (note the syntax is different):

include_path = '.:/php_lib'
auto_prepend_file
= 'autoload.php'

Switch PHP package

Run the following as root:

dnf install php-fpm
dnf remove php
systemctl start php-fpm
systemctl enable php-fpm

NB: in the 2nd line, dnf remove php, package php is actually mod_php: this is what we’re removing.

Tweak the default httpd configuration

Add an <If "-f %{SCRIPT_FILENAME}"> in /etc/httpd/conf.d/php.conf, otherwise PHP-FPM gets called for files that don’t exist. So:

<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</FilesMatch>

becomes:

<FilesMatch \.php$>
<If "-f %{SCRIPT_FILENAME}">
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</If>
</FilesMatch>

If you don’t do this, you’ll get errors in the httpd logs like AH01071: Got error ‘Primary script unknown\n’ whenever someone goes fishing for the likes of wp-login.php. Hat tip: William Astle.

Switch MPM, enable HTTP/2

Select which MPM to use in /etc/httpd/conf.modules.d/00-mpm.conf, e.g. comment out:

# LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

and uncomment:

LoadModule mpm_event_module modules/mod_mpm_event.so

Enable HTTP/2 if desired.

Restart httpd

Finally, if apachectl configtest says Syntax OK, run

systemctl restart httpd

And note that your PHP logs are now available in /var/log/php-fpm.