So you have a custom PHP binary that you wish to distribute across multiple servers.
The “old” way to do this is to create a bash script in order to pull down the source code, run
./configure and then
make; make install. But this is 2013, we have a much more civilized way to create this package now, so that you can distribute that RPM across multiple nodes or even include it in your own yum repository.
We’re going to use FPM (Effing Package Manager) to do the job for this. It is a little bit confusing because PHP also includes the acronym FPM for FastCGI Process Manager. Our package manager FPM is a ruby gem, so install the prerequisites first (CentOS 6 directions here), along with fpm:
# yum install ruby ruby-devel rubygems
# gem install fpm
To start, compile PHP the way you normally would, ie:
'./configure' '--program-prefix=' '--prefix=/usr' \
'--exec-prefix=/usr' '--bindir=/usr/bin' '--enable-ftp' \
'--enable-calendar' '--with-libxml-dir=/usr' '--enable-mbstring' \
'--enable-mbregex' '--with-gd' '--enable-zip' '--with-mcrypt' \
'--with-mhash' '--with-libdir=lib64' '--enable-fpm' '--with-fpm-user=www' \
'--with-fpm-group=www' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd'
make it as normal.
... Lots of output
Now instead of running
make install like normal, we tell it to output to another directory, just some temporary directory on the server:
(Note, if compiling another program, the switch to make it install into another directory may be different, such as DESTDIR=/tmp/installdir)
make install INSTALL_ROOT=/tmp/installdir
Installing PHP SAPI module: fpm
Installing PHP CLI binary: /tmp/installdir/usr/bin/
Installing PHP CLI man page: /tmp/installdir/usr/share/man/man1/
Installing PHP FPM binary: /tmp/installdir/usr/sbin/
Installing PHP FPM config: /tmp/installdir/etc/
Installing PHP FPM man page: /tmp/installdir/usr/share/man/man8/
Installing PHP FPM status page: /tmp/installdir/usr/share/fpm/
Installing build environment: /tmp/installdir/usr/lib/build/
Installing header files: /tmp/installdir/usr/include/php/
Installing helper programs: /tmp/installdir/usr/bin/
Installing man pages: /tmp/installdir/usr/share/man/man1/
/usr/local/src/php-5.3.25/build/shtool install -c ext/phar/phar.phar /tmp/installdir/usr/bin
ln -s -f /usr/bin/phar.phar /tmp/installdir/usr/bin/phar
Installing PDO headers: /tmp/installdir/usr/include/php/ext/pdo/
Now PHP is happily installed in /tmp/installdir. Which is great, but we can’t use it until it we package it up for regular installation. Run the FPM command to pack it all up:
# fpm -s dir -t rpm -n php-fpm -v 5.3.25 -C /tmp/installdir \
-p php-fpm_VERSION_ARCH.rpm -d openssl -d pcre -d bzip2 -d curl \
-d libjpeg -d libpng -d freetype -d gmp -d libmcrypt -d libmhash \
-d libxml2 usr/bin usr/share/man/man1 usr/sbin etc \
usr/share/man/man8 usr/share/fpm usr/lib/build usr/include/php
What do the options mean?
I’ll go through these options:
- -s dir: source is a directory
- -t rpm: we are creating an rpm
- -n php-fpm: we are creating a package with the name php-fpm
- -v 5.3.25: the version of the rpm (so you can manage upgrades)
- -C /tmp/installdir: the base location to take the files from
- -p php-fpm_VERSION_ARCH.rpm: fpm will replace the VERSION and ARCH macros automatically with your version number and architecture
- -d openssl -s pcre …: these are all of the rpm dependencies that you’ll want on the machines installing the package. If you don’t include the proper ones (to match your source system, and which are included in ./configure, you’ll get library errors when you try to launch the program.
- usr/bin usr/share/man/man1 usr/sbin etc usr/share/man/man8 usr/share/fpm usr/lib/build usr/include/php: the directories you wish to include in your package file
When all is done, you should have your rpm file located in /tmp/installdir. You can install it directly on any system with
rpm -i <rpm name>
Before you package up your files, you can include any other files you want. For example, you could include the init script or php.ini file. But if you are managing the system using puppet or chef, it would be better to manage this configuration file through there rather than from the rpm file. This works really well as a ‘building block’ for your programs when you add these custom rpms into your own repository. That way, you can have your system install custom versions of the binaries where applicable but still have the niceties that come from an systems automation with puppet or chef.