Option: Configure PHP as CGI

Apache’s PHP module works fine by default and it’s very easy to set up. But, we have several drawbacks:

  • Apache PHP module will be loaded every single request, so our RAM usage is higher.
  • Prefork has higher CPU usage than Worker. Also prefork has higher RAM usage

So we will attend more clients with less resources, but we will have some trouble with some modules or configurations, like APC, or the number of mysql opened connections (it will increase as the persistent connections will be by thread) but will notice the difference.

First of all, as I say on every page of this tutorial, I’ve tested it in Ubuntu Server 12.04, so it may vary if you use another Linux OS, but the important things I think are similar. You may notice I’m using apt-get to install packages and sudo to execute statements as root, also the name of the packages will vary if you use another distribution.

Installation

We’ve to install apache Worker MPM, Fcgid module and php-cgi, so:

$ sudo apt-get install apache2-mpm-worker libapache2-mod-fcgis php5-cgi php-apc

It may ask you to uninstall libapache2-mod-php5 or apache-mpm-prefork if it’s installed. On a fresh install it shouldn’t complain.
We are also installing php-apc, it’s an opcode cache to make our server run a little faster. It’s always a good idea, even if we are using Apache Prefork.

Enable FCGId and configure PHP

The next step is to enable mod_fcgid:

$ sudo a2enmod fcgid

After that, we should create a php wrapper script to put there some basic configuration to launch the CGI processes. The file could be located in /usr/bin, /usr/local/bin or even inside our document root (but it’s not reccomended), but we can locate it one level before. In this example, I will put it in /usr/local/bin/php-wrapper with this contents:

#!/bin/sh

PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS
PHP_FCGI_CHILDREN=5
export PHP_FCGI_CHILDREN

exec /usr/lib/cgi-bin/php5-cgi -d apc.shm_size=50M

The last part: “-d apc.shm_size=50M” is to use 50Mb opcode cache per user. We should tune it depending on the APC Cache usage in our site.
We are also defining PHP_FCGI_MAX_REQUESTS, that is the number of requests before restarting each child process (each child can attend several clients), but it’s a good idea to restart processes to clean up memory from leaks (these leaks may be caused by PHP or by specific scripts causing PHP not to cleanup properly)
PHP_FCGI_CHILDREN is the number of children this instance of php should spawn, it depends on our system resources, we can increase this number depending on our available CPU and RAM and so, we can attend more clients at a time.
/usr/bin/php-fcgi is our php cgi executable path, let’s find

And then, tell Apache to use this configuration. So, in our virtualhost configuration (in the example was /etc/apache2/sites-available/totaki.com, we must insert the following changes (in bold):

<VirtualHost *:80>
        ServerAdmin info@totaki.com
        ServerName totaki.com
        ServerAlias www.totaki.com
        DocumentRoot /home/cloud/www/totaki.com/www
        <Ifmodule mod_fcgid.c>
                # See /etc/apache2/mods-available/fcgid.conf for (fcgid-script)
                AddHandler fcgid-script .php .php5 .phtml
                FcgidWrapper /usr/local/bin/php-wrapper .php
                FcgidWrapper /usr/local/bin/php-wrapper .php5
                FcgidWrapper /usr/local/bin/php-wrapper .phtml
        </IfModule>
<Directory />
                Options FollowSymLinks
                AllowOverride All</Directory>
<Directory /home/cloud/www/totaki.com/www/>
                Options FollowSymLinks MultiViews +ExecCGI
                AllowOverride All
                Order allow,deny
                allow from all</Directory>
        ErrorLog    "/home/cloud/www/totaki.com/logs/error.log"
        LogLevel warn
        CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined</VirtualHost>

Just restarting the server, we can have it working with PHP-CGI, as we can see creating a sample info script:

<?php phpinfo(); ?>

Screenshot 21-03-2014-070318

Custom PHP.INI file for each Virtualhost

We cannot use php_value in .htaccess with this configuration, but we can set a custom php.ini file for each VirtualHost, setting PHPRC in our VirtualHost configuration or in our PHP Wrapper. In this example, I show you the VirtualHost configuration:

<VirtualHost *:80>
        ServerAdmin info@totaki.com
        ServerName totaki.com
        ServerAlias www.totaki.com
        DocumentRoot /home/cloud/www/totaki.com/www
        <Ifmodule mod_fcgid.c>
                # See /etc/apache2/mods-available/fcgid.conf for (fcgid-script)
                AddHandler fcgid-script .php .php5 .phtml
                FcgidInitialEnv PHPRC "/home/cloud/www/totaki.com/php/"
                FcgidWrapper /usr/local/bin/php-wrapper .php
                FcgidWrapper /usr/local/bin/php-wrapper .php5
                FcgidWrapper /usr/local/bin/php-wrapper .phtml
        </IfModule>
        <Directory />
                Options FollowSymLinks
                AllowOverride All
         </Directory>
    <Directory /home/cloud/www/totaki.com/www/>
                Options FollowSymLinks MultiViews +ExecCGI
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>
        ErrorLog    "/home/cloud/www/totaki.com/logs/error.log"
        LogLevel warn
        CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined
</VirtualHost>

Then we put a php.ini file in /home/cloud/www/totaki.com/www. Remember each VirtualHost can have a different PHPRC configuration, just if the have a different ServerName.

System wide CGI configuration

It’s recommended to have some common settings outside the VirtualHost configuration. We can see all available Fcgid settings here, but I will post here what I use more frequently. Some of these configurations can be also set in the VirtualHost. But I will create /etc/apache2/conf.d/cgisettings.conf:

<IfModule mod_fcgid.c>
        FcgidBusyScanInterval 10
        FcgidMaxProcesses 20
        FcgidMaxRequestLen 1073741824
</IfModule>

Here:

  • FcgidBusyScanInterval: is the time the process look for busy childs.
  • FcgidMaxProccesses: is the number of total CGI processes to launch
  • FcgidMaxRequestLen: is the total size of a request. It is useful if you have applications which upload files, for example. In the past, it had a big value but now don’t

We can also use the directive: FcgidMaxProcessesPerClass which set the maximum number of processes that will be launch per VirtualHost.

Shellshock bug

It’s important to have the latest bash installed. Because Shellshock bug is easy to exploit with this configuration.

Leave a Reply

Your email address will not be published. Required fields are marked *