Apache2, FastCGI & Multiple PHP Versions (Ubuntu/Lucid-10.04)

Posted: May 21, 2010 in Apache2, Linux
Tags: , , , , ,

Update # Some minor mistakes solved, tnx a lot for the emails #

A little guide I’ve made for those who would like to develop with multiple PHP versions on a local server without restarting the Apache server every time you wish to change the PHP version. If you would like to read more about FastCGI, take a look here.

I’m still perfecting this guide bit by bit, any suggestions or comments are welcome.

I’m using Lucid 10.04 (2.6.32-21-generic). This guide would surely work on most Debian based systems. If not, for testing purposes, Sun’s Virtualbox is ideal for setting up a testing environment that equals this guide.

This guide is terminal-based. In Lucid the terminal is bound by default under the shortcut CTRL+ALT+T or located in the menu under Accessories->Terminal

  • Preparation

I assume you have Apache2, MySQL-5.0/5.1 and PHP5 already installed and working, if not, go find another guide ;). Create a file on the http root (mine is the default /var/www) and name it phpinfo.php with the following source:

<?php phpinfo(); // ?> ending is not needed, it's pure PHP

You will use this file over and over again to test if the PHP module is loaded through the FastCGI handler. I will install two different PHP versions. The latest 5.2.13 and 5.3.2. phpfarm will be used to install PHP from source because this will save me a lot of time explaining how to build something from source.

First we need to get phpfarm from the repository, you need to use SVN (subversion). If you do not have subversion installed (or svn command is not recognized), simply run:

sudo apt-get install subversion

I’ve made a seperate directory for all the different php versions in the /etc/php/. When using svn co command, the files will be stored in the directory where you are currently located. So when you want these phpfarm files to be saved in /etc/php/, you have to first create /etc/php/ (if it does not exist) and then cd into it. You can ofcourse choose any location of your likings, but just remember to change every path to /etc/php/ during the course of this guide:

sudo mkdir /etc/php/ && sudo chmod 0775 /etc/php/ && cd /etc/php/

Now get phpfarm from the repository:

svn co http://svn.php.net/repository/pear/ci/phpfarm/trunk/ phpfarm

To install PHP 5.2.x with fastcgi support, we have to change some settings in the options.sh file located in /etc/php/phpfarm/src/. cd into the directory and use nano to edit options.sh or the custom-options.sh:

cd /etc/php/phpfarm/src

Because the configuration for 5.2 and 5.3 are different, I suggest creating two files, one 5.2 (for all 5.2.x versions you install) and 5.3 (for all 5.3.x versions you install). If you need a specific options file for a certain version, you can just create another file, for example custom-options-5.2.1.sh which only gets included when running ./compile.sh 5.2.1. This makes it very easy to customize group or individual configurations.

I added MySQL support, which needs the libmysql++-dev package for the mysql_config binary.

sudo apt-get install libmysql++-dev

I suggest to create the two custom-options-5.2.sh and custom-options-5.3.sh files and place only the options you need to add.
Create a custom-options-$version.sh file in /etc/php/phpfarm/src/ where version can be either 5.2 or 5.3, e.g (assuming you are in the /etc/php/phpfarm/src/ directory):

sudo nano custom-options-5.2.sh

and give it the following content (or any prefix you like)

configoptions="\
  --with-mysql=/usr/bin/mysql_config \
  --with-mysqli \
  --with-pdo-mysql \
  --enable-fastcgi \
  --enable-force-cgi-redirect \
"

To save and quit nano, press CTRL+X, press Y, enter 😉
For the 5.3 file, I added:

configoptions="\
  --with-mysql=/usr/bin/mysql_config \
  --with-mysqli=shared,mysqlnd \
  --with-pdo-mysql=shared,mysqlnd \
"

In PHP 5.3.x FastCGI is enabled by default. You can specifiy additional configuration parameters, I only added mysql support. You can always reconfigure and recompile the PHP installation afterwards using ./compile $version where version is again the version you wish to recompile.

  • PHP Installation

For this demonstration I’m going to install two PHP versions with phpfarm. The PHP 5.3.x will install without any problems. The 5.2.x may stop at the ./configure process because of some default libxml2 config that isn’t set up right (I have no clue why). The fastest and simplest workaround I found was installing libxml2-dev:

sudo apt-get install libxml2-dev

Now we simply run (assuming you are still in the /etc/php/phpfarm/src/ directory):

./compile.sh 5.3.2

This will start downloading, configure and compile PHP 5.3.2. After completion (or simultaneously in a separate terminal), install 5.2.13:

./compile.sh 5.2.13

Both PHP versions are installed, and ready to be used. The installations are located in /etc/php/phpfarm/inst/php-$version where $version is the version you installed; e.g. 5.2.13 You can check on the PHP 5.2.13 binary if cgi-fcgi is enabled by running:

/etc/php/phpfarm/inst/php-5.2.13/bin/php-cgi -v

This should output something like:

PHP 5.2.13 (cgi-fcgi) (built: Dec 12 2128 12:12:12) (DEBUG)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies

Notice the (cgi-fcgi), this means it’s enabled and ready to be used in a FastCGI/Apache configuration. Same goes for PHP 5.3.2. Just change the version number you have installed and the output would be similar. I suggest completing this guide first before installing any additional versions. You can do so and repeat the configuration for every PHP version you wish to install (it’s almost a copy/paste job).

  • FastCGI installation & configuration

Installing the FastCGI module (and suexec, which will be explained later on):

sudo apt-get install libapache2-mod-fastcgi apache2-suexec

After the installation, we have to enable & disable a few modules in Apache. This is done with the commands a2enmod (apache2 enable module) and a2dismod (apache2 disable module):

sudo a2enmod fastcgi actions suexec && sudo a2dismod php5

From this point on, two things are needed. We have to make a script alias for the fastcgi-script and we have to modify the default fastcgi.conf file to wrap the PHP instance with suexec instead of the default handler. First we are going to modify fastcgi.conf in /etc/apache2/mods-enabled/

sudo nano /etc/apache2/mods-enabled/fastcgi.conf

and make the content look like this:

<IfModule mod_fastcgi>
  FastCgiWrapper /usr/lib/apache2/suexec
  FastCgiConfig -idle-timeout 110 -killInterval 120 -pass-header
     HTTP_AUTHORIZATION -autoUpdate
  FastCgiIpcDir /var/lib/apache2/fastcgi
</IfModule>

Next step is creating a script alias which is a simple .conf file. You can just create one in Apache’s root directory (default /etc/apache2/) and include it in the apache2.conf file.  I called mine php-fastcgi.conf.

We have several possibilities on how the PHP application can be executed (the binary php-cgi). First is setting the PHP application as a dynamic application. This is done automatically if not specified differently. The second option is defining the PHP application statically.

To be honest, I do not know the real difference between the two, if it is a performance issue, or something else. You can read more details here.

To configure the PHP application statically you can use FastCgiServer. php-fastcgi-.conf should have the following content in which you can comment out FastCgiServer making it statically. If you wish to use FastCgiServer, do use it for all PHP versions installed. That means you have to copy/paste the commented FastCgiServer line for each PHP version installed:

# /php-fcgi/php-cgi-5.3.2 will be the same as /var/www/cgi-bin/ or which directory
# you choose (or perhaps change) to load the shell scripts.

# comment this out to load the PHP application statically.
#FastCgiServer /var/www/cgi-bin/php-cgi-5.2.13
#FastCgiServer /var/www/cgi-bin/php-cgi-5.3.2
ScriptAlias /php-fcgi/ /var/www/cgi-bin/

Include the php-fastcgi.conf in Apache’s apache2.conf file, before the comment lines:

# include FastCGI conf
Include /etc/apache2/php-fastcgi.conf

# Include of directories <..etc..>
# see README.Deabian for details

Now create the shell scripts in /var/www/cgi-bin/.

sudo mkdir /var/www/cgi-bin

Create for every PHP version you install a scripe file, e.g php-cgi-5.2.13, php-cgi-5.3.2, etc.

sudo nano /var/www/cgi-bin/php-cgi-5.2.13

Make the content look similar to this and change the version number to the corresponding PHP version:

#!/bin/sh
# you can change the PHP version here.
version="5.2.13"
# php.ini file location, */php-5.2.13/lib equals */php-5.2.13/lib/php.ini.
PHPRC=/etc/php/phpfarm/inst/php-${version}/lib/php.ini
export PHPRC

PHP_FCGI_CHILDREN=3
export PHP_FCGI_CHILDREN

PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS

# which php-cgi binary to execute
exec /etc/php/phpfarm/inst/php-${version}/bin/php-cgi
  • Configuring Apache2/VirtualHosts

I have configured my setup that every PHP version resembles a sub-domain. For example PHP 5.3.2 resembles 532.localhost and PHP 5.2.13 resembles 5213.localhost, etc.

I also wanted to maintain the default mod_php5 handler to keep the PHP performance at normality. Though for development, the load on the server is minimal, but still I could notice a small degree of performance loss when loading some heavy PHPUnit tests. Second, I develop in only one version and check for backward compatibility on all other versions. This makes it very easy to test backward compatibility by just changing the sub-domain.

I added the VirtualHosts .conf files in /etc/apache2/sites-enabled/. In here they will load automatically. So for every PHP version installed, add a .conf file that looks similar like this one:

<VirtualHost *:80>
  ServerName 5213.localhost
  DocumentRoot /var/www
  <Directory "/var/www">
    AddHandler php-cgi .php
    Action php-cgi /php-fcgi/php-cgi-5.2.13
  </Directory>
</VirtualHost>

We have to do one last thing. 5213.localhost will of course not be resolved by any DNS. We have to add this statically (or if by change you have a local DNS server, add the record for *.localhost, which you probably already did :D):

sudo nano /etc/hosts

and add after the 127.0.0.1 line all the sub-domains resembling a PHP version:

127.0.0.1        localhost 532.localhost 5213.localhost

Now we can restart apache2:

sudo /etc/init.d/apache2 restart

If everything went well, meaning it restarted without any fatal errors, you can open a browser and test the configuration http://5213.localhost/phpinfo.php 🙂

  • Enabling mod_php5

To work with the mod_php5, you can just enable it with a2enmod.

Enable php5 again:

a2enmod php5

Edit the /etc/apache2/mods-enabled/php5.conf and comment every line between <IfModule .. > and </IfModule>.

Then restart apache:

sudo /etc/init.d/apache2 restart

Apache should restart without any problems. Open the http://localhost/phpinfo.php and you’ll notice at Server API that is says Apache 2.0 Handler instead of CGI/FastCGI

Happy programming .. 😀

Comments
  1. […] is a part of the “Setting up your local development environment” series. It is based on this article while keeping in mind that in previous apache tutorial we compiled apache from source. So I’m […]

  2. […] time where php-5.2.x serve cgi script. i have decided go for the second optioni have followed this tutorial and i can get most of it working however except execution of shell script which selects php-cgi […]

  3. NADJI Sidali says:

    Hi,
    I’d like to thank you for this tuto, it was very usefull for me bue I think
    ./compile 5.3.2 would be ./compile.sh 5.3.2

    Thx

    • dbforch says:

      Indeed, it should be ./compile.sh, thanks for the notice and I’m glad the rest worked for you 😀

      • omg says:

        Hi!

        I tried to follow this tutorial but when php configuring I got this error:
        configure: error: Cannot find libmysqlclient under /usr/local.

        I tried to create a symlink from /usr/lib64 to /usr/local for libmysqlclient.so and using –with-libdir=lib64, but it didnt help. Also…I’m changing the –with-mysql=… path but the configure always search for libmysql in /usr/local…

        What do you think what’s wrong? (on Debian Lenny)

      • dbforch says:

        Are you using a custom-options.sh script? If none of these options work and always return to default, make sure the custom-options script is being used when compiling with php-farm. You will see a small notification that it is using the custom-options script for some version. Make sure when using the custom-options.sh script, it is exactly written as in this tutorial, and give this file overall permission chmod 0777 custom-options-5.2.6.sh.

        When using these parameters, can you verify that the mysqlclient is under /usr/lib64?

  4. mizanur says:

    hi,

    thanks for the tutorial, it is exactly what i want to do. i have followed your instruction so that i can run php5.2.6 however i cannot be sure if php5.2.6 is running on cgi-bin. i have php 5.3.2 installed on my ubuntu server.

    when i run http://526.localhost/phpinfo.php and http://526.localhost/cgi-bin/phpinfo.php,i get same “php5.3.2” header and sever api “Apache2.0 Handler”

    isn’t it meant to be php5.3.2 in my root directory and php5.2.6 in my cgi-bin? can you help?

    • dbforch says:

      Hi Mizanur,

      No, all PHP versions using FCGI will use the same www directory as the default handler, e.g. /var/www/.
      The “cgi-bin” directory is not meant to be used to store .PHP files, or any other files except the ones defined in
      this tutorial.

      If you followed this tutorials directory structure, what does the following command say

      /etc/php/phpfarm/inst/php-5.2.6/bin/php-cgi -v

      Second, how are your permissions set in the /var/www/ directory? Could you post the output
      of the following?

      ls -l /var/www/cgi-bin

      • mizanur says:

        Thanks for the reply dbforch,

        > /etc/php/phpfarm/inst/php-5.2.6/bin/php-cgi -v
        PHP 5.2.6 (cgi-fcgi) (built: Jan 3 2011 13:56:18) (DEBUG)
        Copyright (c) 1997-2008 The PHP Group
        Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies

        > ls -l /var/www/cgi-bin
        -rwxrwxr-x 1 root root 400 2011-01-03 20:49 php-cgi-5.2.6

        Okay I figured out the problem while typing this email. Php5.3 is executed instead of php5.2 even if ‘Action’ directive is defined in apache default.conf file. To get it working I need it to do a2dismod php5 and presto, phpinfo.php is showing php5.2.6 header.

        To make both work simultaneously, I have had to change cgi execution file extension to .cgi for php5.2.6 and .php for php5.3. Now I can run both php5.2 and php5.3 at same time.

        I have a new question, is it possible to run php5.2 in /var/www and php5.3 in ~/public_html/www with the same extension?

        I’m using ubuntu 10.04.

  5. mizanur says:

    > I have a new question, is it possible to run php5.2 in /var/www and php5.3 in > ~/public_html/www with the same extension?

    to run both compilers simultaneously in different directories, you need to add the following to the virtualhost with document root /var/www

    SetHandler php-cgi

    now, document root /var/www will execute php5.2.6 while ~/public/www will execute php5.3

    • Zis says:

      Hello guys,

      Since I have not found a way to run at the same time, one version like a module and the other version like a fcgi… with the same extension, of course.

      At the moment i enable de php5 module, all of the virtualhosts load the php module and ignore de Action or SetHandler….

      I try everything.

      I have Apache 2.2 and a Debian Squeeze…

      Any ideas?

    • GeorgeHuynh says:

      Add this one –with-libdir=/lib/x86_64-linux-gnu \

  6. Andrey says:

    Hello!

    Thank you very much for that article!
    I were looking for something useful about subject long time but only here I met something what I did and it works! (I have tried many cases from different articles before)

    Thanks for phpfarm and that little but important detail: “Notice the (cgi-fcgi), this means it’s enabled and ready to be used in a FastCGI/Apache configuration.”

  7. Difference between static vs dynamic explained:

    http://serverfault.com/questions/26337/whats-the-difference-between-fastcgi-static-and-dynamic-applications-in-term

    Basically if you’re in development machine you’re always better off using dynamic 😉

  8. hectorh30 says:

    Thanks man! Very very useful..

    I just have one question: what would you need to change in order to have xslt support on the 5.2.13 version? I already tried adding –with-xsl and –enable-libxml in the custom-options-5.2.sh, but I get: ‘configure errorr: xslt-config not found’.

    Thanks in advance!

  9. kartoshin says:

    First, I would like to thank you for this post, because it helped me to run multiple versions of php.

    But you’ve got some blank spaces and errors, so it will take more time to configure fastcgi for those who configure it for the very first time (like me =)

    1. Mention, that
    FastCgiConfig -idle-timeout 110 -killInterval 120 -pass-header
    HTTP_AUTHORIZATION -autoUpdate
    should be one line

    2. We should make executable /var/www/cgi-bin/php-cgi-5.2.13

    3. In the end you write, that if we want to work with mod_php5 we should edit the /etc/apache2/mods-enabled/php5.conf but we didn’t edited it before. Perhaps, should be fastcgi.conf?

    Thanks again.

    • dbforch says:

      I’ve totally abandoned Linux for the moment, I’m developing on OSX now for some time. I’m going to bring a little Debian server back to life so I’ll check the statements and re-write this tutorial for all later Ubuntu versions and/or Debian.

  10. Celso says:

    Can compile php 5.2.17 with openssl..

    Have anyone been successful compiling?

  11. F. Poirotte says:

    Please note that the official repository for phpfarm is now located at http://sourceforge.net/p/phpfarm/.

  12. scoumbourdis says:

    Thanks. It works for me.

    You just have to follow step by step your tutorial and everything will work fine at the end 🙂

  13. […] una y otra vez, e incluso reinicie la pc, pero nada. Alguna pista? El tutorial en cuestion es este: https://dbforch.wordpress.com/2010/05…tulucid-10-04/ o similar. Fuente : […]

  14. mohd taheer says:

    Thanks for the guide. Its really very useful.
    But I am facing one issue after configuring all the steps describe above. I am getting an response from the server based on the different virtual hosts but the content is static. The server response has only

    Can you please help me in this problem.

    Thanks in advance

  15. achu68 says:

    checking for MySQL UNIX socket location… no
    configure: error: Cannot find libmysqlclient under /usr.
    Note that the MySQL client library is not bundled anymore!
    configure.sh failed.

    Even after installed “libxml2-dev” on Ubuntu 12.04 any idea?

    Thanks,

  16. […] The simplest is to try with another version. There’s some good extra info on how to use PHPFarm here. PHPFarm messes up the paths slightly for the CLI version of PHP on Macs, but that shouldn’t […]

Leave a reply to mizanur Cancel reply