PHP-FPM on Amazon’s Linux

Update (Oct 1, 2011): The release notes for the newest version of Amazon’s Linux (2011.09) state that “PHP scripts have the option of using PHP-FPM.” PHP-FPM is now included in the amzn-main repository, and can be installed via yum install php-fpm (it is installed to /usr/sbin).

As a point of mention, if you want to use ‘php-fpm’ without apache (e.g. with nginx), do not install the package ‘php’, but only php-fpm. The php package installs mod_php, which, being an apache module needs apache. For instance, my standard install is:

yum install php-fpm php-bcmath php-gd php-mbstring php-mcrypt php-mysql php-pdo php-pecl-apc php-tidy php-xml php-xmlrpc php-imap php-intl

The basis for the init script (for PHP 5.3.6) is available from the PHP source. Modify prefix, exec_prefix, php_fpm_BIN, php_fpm_CONF, and php_fpm_PID. Also ensure your php-fpm.conf file (located in /etc) is setup correctly.

I found that I was getting a blank page when loading php files. This resulted from the default nginx.conf file having the root directives set inside the location blocks instead of directly under the main server block. As such, the $document_root variable was incorrectly set in the php block (but the request was passed to php-fpm). Unfortunately, neither the nginx nor php-fpm error logs showed anything (even when set to the debug/info levels). Once the fastcgi_param SCRIPT_FILENAME is set correctly, it is probably a good idea to set the fastcgi_intercept_errors directive to on (otherwise 404 errors on the php-fpm side will yield the aforementioned blank page, which is unlikely to be the expected outcome).

Original article (mostly obsoleted by the update):
I have been running Amazon’s Linux distribution on my EC2 instances for some time now, and have consistently been pleased with it. It has a low memory footprint, and has been stripped of many unnecessary components. Furthermore, I expect that Amazon has optimized the distribution for their EC2 platform, and in terms of performance, it would certainly appear to be the case.

Amazon provides its own repository (amzn) for use with this distribution, and has been quite good at keeping it up to date and adding new packages. One package currently missing that is rather difficult to replace is the PHP FastCGI Process Manager (php-fpm), which has been bundled with PHP since v5.3.3. While it is possible to obtain this specific package from other repositories, invariably the dependencies require installing all of PHP from those repositories. Since I would like to continue using the amzn repository (and actually try not to add any others), I provide below the steps necessary to generate the full set of PHP RPMs, including php-fpm on Amazon’s Linux, using Remi Collet’s spec files which are available on GitHub.

PHP-FPM provides some distinct advantages over the typical FastCGI, including daemonization, adaptive process spawning, and different uids (like suPHP). It also works with Nginx a popular light weight webserver.

Prerequisites

To start, we need the ‘Development Tools’ so we can compile and build the RPMs. (Installing these are not recommended on a production machine.)

yum groupinstall "Development Tools"

We will need to download some files, so I am going to use /usr/local/src as my working directory.

cd /usr/local/src

Spec Files

wget https://github.com/remicollet/remirepo/tarball/master

The command above downloads all of Remi’s spec and configuration files, and we now extract them:

tar -xzvf remicollet-remirepo-*.tar.gz

We will now copy the files to the SOURCES directory, and change to that directory:

cp remicollet-remirepo-*/php/* /usr/src/rpm/SOURCES/
cd /usr/src/rpm/SOURCES/

Dependencies

To build PHP there are quite a few dependencies we must satisfy. For the most part, these are development headers that we need to compile PHP against other packages.

Most of the dependencies are available in the amzn repository, and we will install them with yum.

yum install -y bzip2-devel curl-devel db4-devel gmp-devel httpd-devel pam-devel openssl-devel sqlite-devel zlib-devel libedit-devel krb5-devel libc-client-devel cyrus-sasl-devel openldap-devel mysql-devel postgresql-devel unixODBC-devel libxml2-devel net-snmp-devel libxslt-devel libxml2-devel libjpeg-devel libpng-devel freetype-devel xorg-x11-devel libmcrypt-devel libtidy-devel freetds-devel aspell-devel recode-devel libicu-devel libXpm-devel t1lib-devel pcre-devel libtool-ltdl-devel libevent-devel

There are a few other packages that Remi’s spec file requires, specifically sqlite2 and recode, which we can install as below.

Install the GPG Keys for the EPEL and Remi repositories:

rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi
rpm --import http://download.fedora.redhat.com/pub/epel/RPM-GPG-KEY-EPEL

Download and install sqlite2 and recode, as well the development headers:

yum install http://rpms.famillecollet.com/enterprise/6/remi/x86_64/sqlite2-devel-2.8.17-5.el6.remi.x86_64.rpm   http://rpms.famillecollet.com/enterprise/6/remi/x86_64/sqlite2-2.8.17-5.el6.remi.x86_64.rpm   http://download.fedora.redhat.com/pub/epel/5/x86_64/recode-devel-3.6-24.el5.x86_64.rpm   http://download.fedora.redhat.com/pub/epel/5/x86_64/recode-3.6-24.el5.x86_64.rpm

We need to make a few modifications to the spec file, in order for things to work:

edit php.spec:

add: %global rhel 6
set: with_enchant 0
set: runselftest 0

The items above let the compiler know that we are running something akin to RHEL 6. We also disable the Enchant spelling library, and turn off the self-tests (they increase the compile time significantly).

Before building, a few quick comments. On a t1.micro instance, it took 9 hours to compile plus 3 hours for tests (load average typically 1.15, with ~99% CPU usage), so I would suggest a larger instance for this. The c1.medium would be ideally suited to compiling (best price/performance) however, it is a 32-bit only platform (and compiling the 64-bit RPMs would require a bit of extra work). I decided to try for something a bit faster than half a day, and went with a c1.xlarge instance. The compiling task did not appear to fully utilize the 20 ECUs of the c1.xlarge instance (load avg peaked at 5). Given this, the m1.large may offer better price/perforance. Spot instances are definitely the way to go for this kind of task. On the c1.xlarge, I needed 10 minutes of prep time (editing files, etc), and the total compile took under 10 minutes.

Finally, we build:

rpmbuild -ba php.spec

 

When done, you will have a complete set of PHP RPMs, that are compatible with the amzn repository. For me, I ended up with the following (PHP 5.3.6):

  • php-5.3.6-4.amzn1.x86_64.rpm
  • php-bcmath-5.3.6-4.amzn1.x86_64.rpm
  • php-cli-5.3.6-4.amzn1.x86_64.rpm
  • php-common-5.3.6-4.amzn1.x86_64.rpm
  • php-dba-5.3.6-4.amzn1.x86_64.rpm
  • php-debuginfo-5.3.6-4.amzn1.x86_64.rpm
  • php-devel-5.3.6-4.amzn1.x86_64.rpm
  • php-embedded-5.3.6-4.amzn1.x86_64.rpm
  • php-fpm-5.3.6-4.amzn1.x86_64.rpm
  • php-gd-5.3.6-4.amzn1.x86_64.rpm
  • php-imap-5.3.6-4.amzn1.x86_64.rpm
  • php-intl-5.3.6-4.amzn1.x86_64.rpm
  • php-ldap-5.3.6-4.amzn1.x86_64.rpm
  • php-mbstring-5.3.6-4.amzn1.x86_64.rpm
  • php-mcrypt-5.3.6-4.amzn1.x86_64.rpm
  • php-mssql-5.3.6-4.amzn1.x86_64.rpm
  • php-mysql-5.3.6-4.amzn1.x86_64.rpm
  • php-odbc-5.3.6-4.amzn1.x86_64.rpm
  • php-pdo-5.3.6-4.amzn1.x86_64.rpm
  • php-pgsql-5.3.6-4.amzn1.x86_64.rpm
  • php-process-5.3.6-4.amzn1.x86_64.rpm
  • php-pspell-5.3.6-4.amzn1.x86_64.rpm
  • php-recode-5.3.6-4.amzn1.x86_64.rpm
  • php-snmp-5.3.6-4.amzn1.x86_64.rpm
  • php-soap-5.3.6-4.amzn1.x86_64.rpm
  • php-sqlite-5.3.6-4.amzn1.x86_64.rpm
  • php-tidy-5.3.6-4.amzn1.x86_64.rpm
  • php-xml-5.3.6-4.amzn1.x86_64.rpm
  • php-xmlrpc-5.3.6-4.amzn1.x86_64.rpm
  • php-zts-5.3.6-4.amzn1.x86_64.rpm

Install

For a common install (with php-fpm), consider the following (we need the –nogpgcheck since we have not signed the RPMs):

yum install --nogpgcheck php-5.3.6-4.amzn1.x86_64.rpm php-bcmath-5.3.6-4.amzn1.x86_64.rpm php-cli-5.3.6-4.amzn1.x86_64.rpm php-common-5.3.6-4.amzn1.x86_64.rpm php-fpm-5.3.6-4.amzn1.x86_64.rpm php-gd-5.3.6-4.amzn1.x86_64.rpm php-mbstring-5.3.6-4.amzn1.x86_64.rpm php-mcrypt-5.3.6-4.amzn1.x86_64.rpm php-mysql-5.3.6-4.amzn1.x86_64.rpm php-pdo-5.3.6-4.amzn1.x86_64.rpm php-soap-5.3.6-4.amzn1.x86_64.rpm php-sqlite-5.3.6-4.amzn1.x86_64.rpm php-tidy-5.3.6-4.amzn1.x86_64.rpm php-xml-5.3.6-4.amzn1.x86_64.rpm php-xmlrpc-5.3.6-4.amzn1.x86_64.rpm php-imap-5.3.6-4.amzn1.x86_64.rpm php-intl-5.3.6-4.amzn1.x86_64.rpm

If you run the above on another machine, remember that you will need to install sqlite2 before you can use php-sqlite.

You can, of course, also install other PHP packages using Remi’s spec files (again, adding ‘%global  rhel 6’ to them), for instance, APC or suhosin.

Once you have php-fpm installed, you will want to edit the php-fpm.conf file as per http://php-fpm.org/wiki/Configuration_File and start php-fpm (the init script should have been installed):

service php-fpm start

By cyberx86

Just a random guy who dabbles with assorted technologies yet works in a completely unrelated field.

4 comments

  1. Hi, thanks for this tutorial. By the way, is there anyway that you can upload php-fpm-5.3.6-4.amzn1.x86_64.rpm to somewhere? would be nice if others can install php-fpm RPM without waiting for the compiling process, it’s taking real long on EC2 micro.

    1. Thanks for reading and the comment. I would suggest launching a spot instance of m1.large. That is the cheapest (non-micro) instance that runs a 64-bit operating system (I think it is around $0.11/hr for the spot instance), and the compile time should be about 15 minutes. At the moment, I unfortunately, am not in a position to make rpms publicly available (keep in mind that you would need all the PHP dependencies of the same version, not just PHP-FPM). I might suggest asking Amazon to add the package to its repository though, since it is a rather common component to use now-a-days. Alternatively, you could try installing it from Remi’s repository, but the dependencies are likely to significantly affect future upgrades and package installations.

  2. Hi, thanks for an excellent blog post – I have managed to create the rpm’s for both i386 and x86_64 for php 5.3.8 and it works really well. The compiling hint was a huge help (i.e. used a large instance)
    I notice Amazon’s latest release as of 16th Sept 2011 includes APC (php-pecl-apc-3.1.3p1-1.2.4.amzn1) and php 5.3.5 yet still no php-fpm 🙁
    It is on the wishlist here: https://forums.aws.amazon.com/thread.jspa?messageID=208170

    You have “You can, of course, also install other PHP packages using Remi’s spec files (again, adding ‘add: %global rhel 6′ to them), for instance, APC or suhosin.”
    How do I do that exactly ?
    Thanks

    1. Glad you found it useful. PHP-FPM has been a desired item for quite some time (at least since it became part of the mainstream PHP package, if not before) – however, AWS has, seemingly, had some difficulty producing the RPM. From the looks of it, they have produced a package and have released it to some testers – hopefully it will be part of their repository in the near future.

      Remi’s spec files are fairly consistent at typically (not always as I mention below) work as is (just specifying the operating system version, since Amazon’s Linux does not identify itself as RHEL). The inclusion of the word ‘add:’ was a typo – it should have read: “again, adding ‘%global rhel 6′ to them” (which I have updated in the post).

      With APC, you may be better off installing it from PECL, which would be easier to maintain, should be the most up to date source, and should offer the most options (e.g. installing a beta release, etc.).

      On the other hand, I have sometimes run into problems installing APC from PECL, but the YUM/RPM install has worked without issue. As you mentioned, the amzn repository does provide php-pecl-apc (3.1.3p1-1.2.4.amzn1), but you can still make your own RPM and install it, if you wish. Currently Remi’s spec file is for APC v3.1.9 (which is also the latest version on PECL).

      The current version of Remi’s APC spec file (3.1.9-3) has been altered to also create a ZTS extension, which gave me a bit of trouble. Instead, I used an earlier version (3.1.9-1) which did not create the ZTS extension, and worked without issue.

      I had to download the actual APC source (which is a bit unusual), but not too much extra work. The steps I followed are reproduced below:

      mkdir /usr/local/src/apc
      cd /usr/local/src/apc
      wget https://raw.github.com/remicollet/remirepo/1be4d90fb8920d1b4712e441d2e34cbb1d8fe7fd/php-pecl-apc/php-pecl-apc.spec
      wget https://github.com/remicollet/remirepo/raw/master/php-pecl-apc/Makefile
      wget -O /usr/src/rpm/SOURCES/APC-3.1.9.tgz http://pecl.php.net/get/APC-3.1.9.tgz
      sed -i 1i"%global rhel 6" php-pecl-apc.spec
      rpmbuild -ba php-pecl-apc.spec

      The RPMS were created in /usr/src/rpm/RPMS/i686/ (I ran it on an x86 instance, not an x86_64). Total build time on t1.micro was about 1-2 min.

      Hopefully you can adapt this for use with Suhosin or any other extension that Remi has spec files for, if you wish to do so.

Leave a Reply to cyberx86 Cancel reply

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