In a previous article from over 5 years ago, we advocated the use of Apache MPM Worker Threaded Server with fcgid over Apache's mod_php.

That was for serveral reasons, including faster handling of static files by Apache threaded server, and lower memory utilization since PHP is not embedded in every Apache process.

However, there were some drawbacks, mainly that APC opcache cache is not shared, and each process has to have its own copy.

But we don't have to settle for the above trade off anymore, because there has been a better alternative for some time now: Apache MPM Worker Threaded server + PHP FPM. This configuration is part of PHP 5.3 and 5.5 available on Ubuntu 12.04 and 14.04.

PHP FPM uses the Fast CGI interface to the web server, and therefore can be used with other web servers, like nginx.

But, we stick to Apache, which has very good performance when it is in MPM Worker, since the threaded server is much more efficient and light weight than the Pre-Fork server.

In the sections below, we describe how to setup and tune Apache2 and PHP FPM optimally for both Ubuntu 12.04 and 14.04, since some sites will stay for some time on the former because of some incompatibilities of some modules with the latter. The former has Apache 2.2, while the latter has Apache 2.4. Because of this and other changes, the locations of the files are different, and some parameters are different too.

We assume a VPS of modest size, 1 or 2 GB of RAM. The values should be adjusted for larger servers of 8GB or more.

Apache MPM Worker Configuration

aptitude install apache2-mpm-worker apache2-threaded-dev apache2-utils libapache2-mod-fastcgi php5-fpm

We then configure Apache MPM Worker. Note that in Ubuntu 12.04, the configuration goes in /etc/apache/conf.d/mpm-worker.conf. As for Ubuntu 14.04, the file should be: /etc/apache2/conf-enabled/mpm-worker.conf.

<IfModule mpm_worker_module>

ServerLimit 300

StartServers 3

MinSpareThreads 3

MaxSpareThreads 10

ThreadsPerChild 10

MaxClients 300

MaxRequestsPerChild 1000

</IfModule>

Then, we enable the required module for FastCGI to work:

sudo a2enmod fastcgi

Ubuntu 12.04 Configuration

On Ubuntu 12.04, it is better to stay with APC, rather than try with Zend OpCache. You can try running with Zend OpCache, but if you get segfaults, then stick with APC.

First, we tell Apache to send requests for files ending with .php to the PHP FPM server. This goes in the file: /etc/apache2/conf.d/php-fpm.conf, as follows:

<IfModule mod_fastcgi.c>

Alias /usr/sbin/php-fpm.fcgi /usr/sbin/php-fpm

AddHandler php-fastcgi .php

Action php-fastcgi /usr/sbin/php-fpm.fcgi

FastCGIExternalServer /usr/sbin/php-fpm -host 127.0.0.1:9000 -pass-header Authorization -idle-timeout 600

<Directory /usr/sbin>

Options ExecCGI FollowSymLinks

SetHandler fastcgi-script

Order allow,deny

Allow from all

</Directory>

</IfModule>

Then, in the file /etc/php5/fpm/pool.d/www.conf, you should have the following values, so that you do not exceed the available memory for the server:

[www]

user = www-data

group = www-data

chdir = /

listen = 127.0.0.1:9000

pm = dynamic

pm.max_children = 10

pm.start_servers = 4

pm.min_spare_servers = 2

pm.max_spare_servers = 6

pm.max_requests = 2000

And finally we increase the memory for PHP and Zend OpCache from the default, in the file: /etc/php5/fpm/conf.d/local.ini.

For fairly simple sites with a small number of modules and themes (e.g. 100 or less), shm_size of 64MB is sufficient. For sites with a large number of modules (~200 or so), you will need to increase that to 128MB or more. Likewise, the value for memory_limit needs to increase for complex sites as well, perhaps up to 256MB in some cases.

To know exactly how much memory APC is using, you need to copy the apc.php file from /usr/share/doc/php temporarily to web root and access it from a browser.

; You may need to increase the values below, depending on your site's complexity

memory_limit = 96M

apc.shm_size = 64M

Ubuntu 14.04 LTS

For Ubuntu 14.04, you should not use APC, but rather the built Zend OpCache.

First, we tell Apache to send requests for files ending with .php to the PHP FPM server. This goes in the file /etc/apache2/conf-enabled/php-fpm.conf

<IfModule mod_fastcgi.c>

Alias /php-fcgi /usr/lib/cgi-bin/php5

AddHandler php .php

Action php /php-fcgi

FastCgiExternalServer /usr/lib/cgi-bin/php5 -host 127.0.0.1:9000 -pass-header Authorization -idle-timeout 600

<Directory /usr/lib/cgi-bin>

AllowOverride All

Options +ExecCGI +FollowSymLinks

Require all granted

</Directory>

</IfModule>

Then we configure the maximum number of PHP processes that would provide good performance, but not exceed the server's memory. This goes in the file /etc/php5/fpm/pool.d/www.conf

[www]

user = www-data

group = www-data

chdir = /

listen = 127.0.0.1:9000

pm = dynamic

pm.max_children = 10

pm.start_servers = 4

pm.min_spare_servers = 2

pm.max_spare_servers = 6

pm.max_requests = 2000

And finally we increase the memory for PHP and Zend OpCache from the default, in the file: /etc/php5/fpm/conf.d/local.ini.

For fairly simple sites with a small number of modules and themes (e.g. 100 or less), memory_consumption of 64MB is sufficient. For sites with a large number of modules (~200 or so), you will need to increase that to 128MB or more. Likewise, the value for memory_limit needs to increase for complex sites as well, perhaps up to 256MB in some cases.

To know exactly how much memory Zend OpCache is using, you need to get the opcache.php script from Rasmus Lerdorf's GitHub, and copy it temporarily to web root and access it from a browser.

; You may need to increase the values below, depending on your site's complexity

memory_limit = 96M

opcache.memory_consumption = 64M

Enabling Required Modules

The final step before restarting the servers is to enable the following Apache modules. This ensures that Apache, PHP-FPM and Drupal work properly together:

sudo a2enmod fastcgi actions rewrite deflate expires

Restarting

Now, restart Apache and PHP, so the above configurations take effect:

sudo service php5-fpm restart

sudo service apache2 restart

Now, you have a very performant yet light weight setup.