Switch from mod_php to php-fpm on Apache

Before you start using PHP-FPM, let me briefly explain what CGI(Common Gateway Interface), mod_php, and FastCGI are:

  • CGI - Back in the day, CGI enabled a Web Server to execute programs like binaries or scripts(e.g bash, php, python). Upon each client request the server would have to spawned a new CGI process to execute a particular program, or script by calling its interpreter, then the CGI process will capture the result, send it to the server, and then the server will deliver the response. Creating a new process upon each request can be expensive. CGI could also be the entry point of a remote code execution, if you don’t know what you’re doing. A very popular one is the Shellshock bug.

  • mod_php - To overcome the drawbacks of CGI, mod_php was created for Apache. With mod_php enabled, PHP is embedded in Apache. The communication between Apache and PHP is much faster but still, there are some disadvantages. mod_php is called on each client request, even if the content is static or just plain HTML. Much more memory is being used without processing PHP. And it forces you to use MPM Pre-Fork. Even with a cache proxy, it’s not the ideal solution.

  • FastCGI: FastCGI is not a newer version of CGI, but a whole new protocol rewritten from scratch to address the limitations of CGI. It’s not embedded in the server anymore. It’s a standalone handler that can process multiple requests simultaneously. Since it’s a listener or handler of requests, you have to give your web server instruction where to locate it. These days, each Web Server(like Apache, Nginx) have their own version of FastCGI. The original one is not available anymore.

What is PHP-FPM and Event MPM

PHP-FPM or PHP FastCGI Process Manager is an implementation of the old FastCGI, designed specifically for PHP. And with the combination of MPM Event, high traffic endpoints are easier to handle while using less resources.

Apache will need mpm_event,mod_proxy, and mod_proxy_fcgi enabled in order to communicate with PHP-FPM.

Seting up the Environment

mpm_event, and mod_proxy is available by default. You’ll need to install php-fpm, and libapache2-mod-fcgid.

First, stop apache2, and disable php, and, mpm_prefork:

$ systemctl stop apache2
$ a2dismod php7.4 mpm_prefork 

Enable mpm_event:

$ a2enmod mpm_event

Install both php-fpm, and libapache2-mod-fcgid:

$ apt install php-fpm libapache2-mod-fcgid

Enable mod_proxy, and proxy_fcgi:

$ a2enmod proxy proxy_fcgi

php-fpm is not a module but a service or handler on its own. To make it available, we need to enable its configuration:

$ a2enconf php7.4-fpm

Upon the activation of the configuration file, you can see that php-fpm is already running:

root@debian:~# ls -l  /var/run/php/php*
lrwxrwxrwx 1 root     root     30 Aug 31 15:57 /var/run/php/php-fpm.sock -> /etc/alternatives/php-fpm.sock
-rw-r--r-- 1 root     root      5 Aug 31 15:57 /var/run/php/php7.4-fpm.pid
srw-rw---- 1 www-data www-data  0 Aug 31 15:57 /var/run/php/php7.4-fpm.sock

root@debian:~# ps aux | grep www-data
www-data   10088  0.0  0.3   7696  3780 ?        S    15:57   0:00 /usr/sbin/apache2 -k start
www-data   10090  0.0  0.6 753920  6420 ?        Sl   15:57   0:00 /usr/sbin/apache2 -k start
www-data   10091  0.0  0.6 753920  6420 ?        Sl   15:57   0:00 /usr/sbin/apache2 -k start
www-data   11162  0.0  0.8 196804  8572 ?        S    15:57   0:00 php-fpm: pool www
www-data   11163  0.0  0.8 196804  8572 ?        S    15:57   0:00 php-fpm: pool www

The handler is set automatically in /etc/apache2/conf-enabled/php7.4-fpm.conf:

SetHandler "proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost"

Now start apache2 and run a configtest:

root@debian:~# systemctl start apache2
root@debian:~#
root@debian:~#
root@debian:~# apache2ctl configtest
Syntax OK
root@debian:~#

Verify if the required modules are indeed enabled:

root@debian:~# apache2ctl -M | egrep -i "mpm|proxy"
 mpm_event_module (shared)
 proxy_module (shared)
 proxy_fcgi_module (shared)

Then restart apache2:

$ systemctl restart apache2

A simple start is not enough. A restart is required for the changes to take effect.

Verify with php_info()

Let’s call php_info(), and confirm if the Server API, and Loaded Configuration File is using FPM. Run the following:

root@debian:~# echo "<?php phpinfo(); ?>" > /var/www/html/info.php

Browse to yourIP/info.php or use curl:

$ curl -s localhost/info.php | egrep "Server API|Loaded" | grep -i fpm | sed 's/<[^>]*>//g'

Server API FPM/FastCGI
Loaded Configuration File /etc/php/7.4/fpm/php.ini

or lynx:

$ lynx localhost/info.php

PHP logo

PHP Version 7.4.21

   System Linux debian 5.10.0-8-amd64 #1 SMP Debian 5.10.46-4 (2021-08-03) x86_64
   Build Date Jul 2 2021 03:59:48
   Server API FPM/FastCGI
   Virtual Directory Support disabled
   Configuration File (php.ini) Path /etc/php/7.4/fpm
   Loaded Configuration File /etc/php/7.4/fpm/php.ini

Don’t forget to remove info.php once you’re done.

Act as if what you do makes a difference. It does. - William James