Shami's Blog

DevOps because uptime is not optional

Running Older PHP Versions on FreeBSD 11

Why? You might ask yourself. Isn’t it just better to upgrade the web application and save yourself the trouble of all the security issues? True, but sometimes it’s just not possible or feasible. The other day I helped a friend of mine migreate from a VPS he got in 2008 to a brand new FreeBSD 11 droplet on DigitalOcean . His customer has still not updated their site, and they were paying the same rate they’ve been paying since 2008. So it was better and cheaper to move them to a new VPS even though we kept the same code. At least the OS and all other components in the stack were updated.

First thing’s first. I maintain my own repo using Poudriere . So all installed packages come from that. We’ll install everything from there except for PHP. I will be installing both PHP 4.4 and PHP 5.2 (That’s what we used for the droplet).

We’ll be using FreeBSD 11.1. Also, we’ll be using jails to keep any security issues with PHP from affecting the whole server. We’ll use NAT to provide internet access to the jails.

Add a private network to the server, this will be used for communication between the jails and the host

1# /etc/rc.conf
2cloned_interfaces="lo1"
3ipv4_addrs_lo1="192.168.0.1/24"
4gateway_enable="YES"
5pf_enable="YES"
6iocage_enable="YES"

Configure pf to NAT

 1# /etc/pf.conf
 2ext_if="MAIN_INTERFACE"
 3jail_if="lo1"
 4
 5IP_PUB="YOUR_PUBLIC_IP_ADDRESS"
 6
 7scrub in all
 8
 9# nat all jail traffic
10nat pass on $ext_if from 192.168.0.0/24 to any -> $IP_PUB
11
12# No firewall, just pass everything
13pass out
14pass in

Reboot your server. Once it’s back up, install and configure nginx, MySQL, … etc. Save your web application to /usr/local/www/ as if PHP was running on host. We’ll be using nullfs to mount the folder to the jails

Install IOCage to manage the jails

 1pkg install py36-iocage
 2
 3iocage activate zroot
 4
 5# Fetch the FreeBSD images
 6iocage fetch (Choose 11.1-RELEASE) 	# For PHP 5.2/5.3
 7iocage fetch (Choose 10.4-RELEASE)	# For PHP 4.4
 8
 9# Create jails for running PHP 5.2 and PHP 4.4 (I couldn't get PHP 4.4 to compile on 11.x, so we're using 10.4)
10iocage create --name php44 -r 10.4-RELEASE
11iocage create --name php52 -r 11.1-RELEASE
12
13# Set the IP addresses of the jails
14iocage set ip4_addr="lo1|192.168.0.2" php52
15iocage set ip4_addr="lo1|192.168.0.3" php44
16
17# Set the jails to start on boot
18iocage set boot=on php52
19iocage set boot=on php44
20
21# Start the jails
22service iocage start
23
24# Check jail status
25iocage list
26
27+-----+-------+-------+--------------+-------------+
28| JID | NAME  | STATE |   RELEASE    |     IP4     |
29+=====+=======+=======+==============+=============+
30| 1   | php52 | up    | 11.1-RELEASE | 192.168.0.2 |
31+-----+-------+-------+--------------+-------------+
32| 2   | php44 | up    | 10.4-RELEASE | 192.168.0.3 |
33+-----+-------+-------+--------------+-------------+
34
35mkdir -p /iocage/jails/php52/root/usr/local/www/example.com
36mkdir -p /iocage/jails/php44/root/usr/local/www/example.com

Set up the jails to mount the webroot

1# /iocage/jails/php52/fstab
2/usr/local/www/example.com /iocage/jails/php52/root/usr/local/www/example.com nullfs rw 0 0
3
4# /iocage/jails/php44/fstab
5/usr/local/www/example.com /iocage/jails/php44/root/usr/local/www/example.com nullfs rw 0 0

Nginx backend configuration

 1upstream php52 {
 2	least_conn;
 3	server 192.168.0.2:9000 max_fails=0;
 4	server 192.168.0.2:9001 max_fails=0;
 5	server 192.168.0.2:9002 max_fails=0;
 6	server 192.168.0.2:9003 max_fails=0;
 7	server 192.168.0.2:9004 max_fails=0;
 8}
 9
10upstream php44 {
11	least_conn;
12	server 192.168.0.3:9000 max_fails=0;
13	server 192.168.0.3:9001 max_fails=0;
14	server 192.168.0.3:9002 max_fails=0;
15	server 192.168.0.3:9003 max_fails=0;
16	server 192.168.0.3:9004 max_fails=0;
17}

Now that we have our jails ready, lets set up PHP

PHP 5.2:

 1# Switch to the PHP 5.2 jail, This is the exact same process as PHP 5.3, except for one step
 2jexec 1
 3
 4# Set up your pkgng repo
 5
 6# Install build dependencies
 7pkg update
 8pkg install -y gcc-6 patch libxml2 curl jpeg png freetype2 mcrypt mariadb100-client libxslt
 9
10# Download PHP
11fetch http://museum.php.net/php5/php-5.2.17.tar.gz
12tar zxvf php-5.2.17.tar.gz
13cd php-5.2.17
14
15# This patch is needed for PHP 5.2 to compile on FreeBSD 11.x, not needed for PHP 5.3
16feth https://shami.blog/2018/02/running-older-php-versions-on-freebsd-11/libxml29_compat.patch
17gpatch -p0 < libxml29_compat.patch
18
19# Build PHP
20./configure --with-layout=GNU \
21	--with-regex=php \
22	--with-zend-vm=CALL \
23	--enable-zend-multibyte \
24	--build=FreeBSD-amd64 \
25	--prefix=/usr/local/php52 \
26	--exec-prefix=/usr/local/php52 \
27	--with-config-file-scan-dir=/usr/local/php52/etc/php \
28	--enable-mod-charset \
29	--enable-fastcgi \
30	--enable-libgcc \
31	--with-libxml-dir=/usr/local/include/libxml2/libxml/ \
32	--enable-ftp \
33	--with-mysql=/usr/local/include/mysql/ \
34	--with-xsl=/usr/local/include/libxslt/ \
35	--with-pdo-mysql \
36	--enable-mbstring \
37	--with-curl \
38	--disable-short-tags \
39	--disable-ipv6 \
40	--enable-bcmath \
41	--with-curl=/usr/local/include/curl/ \
42	--with-bz2 \
43	--enable-exif \
44	--enable-ftp \
45	--with-gd \
46	--with-png-dir \
47	--with-jpeg-dir \
48	--with-zlib-dir \
49	--with-freetype-dir \
50	--with-gettext \
51	--enable-mbstring \
52	--with-mcrypt \
53	--with-mhash \
54	--with-mysqli \
55	--with-xmlrpc \
56	--enable-soap \
57	--enable-sockets \
58	--enable-zip \
59	--enable-calendar \
60	--with-gmp \
61	--with-openssl \
62	--enable-pcntl \
63	--with-readline \
64	--enable-shmop \
65	--enable-wddx
66
67make
68make install
69cp php.ini-recommended /usr/local/etc/php.ini

PHP 4.4:

 1# Switch to the PHP 4.4 jail
 2jexec 2
 3
 4# Set up your pkgng repopkg update
 5pkg update
 6pkg install mariadb100-client
 7
 8# Download PHP
 9fetch http://museum.php.net/php4/php-4.4.9.tar.gz
10tar zxvf php-4.4.9.tar.gz
11cd php-4.4.9
12
13# Build PHP
14./configure --enable-fastcgi
15make
16cp php.ini-recommended /usr/local/etc/php.ini

PHP will now be installed to /usr/local/php52. Now we’ll use Supervisord to keep PHP CGI running since 5.2 didn’t have FPM

PHP 5.2:

 1pkg install py27-supervisor
 2
 3$CAT >> /usr/local/etc/supervisord.conf <<EOF
 4[program:php52]
 5process_name=%(program_name)s_%(process_num)02d
 6command=/usr/local/php52/bin/php-cgi -b 192.168.0.2:90%(process_num)02d -c /usr/local/etc/php.ini
 7autostart=true
 8autorestart=true
 9user=USER
10numprocs=5
11redirect_stderr=true
12EOF
13
14echo supervisord_enable=YES > /etc/rc.conf.d/supervisord
15service supervisord start

PHP 4.4:

 1pkg install py27-supervisor
 2
 3$CAT >> /usr/local/etc/supervisord.conf <<EOF
 4[program:php44]
 5process_name=%(program_name)s_%(process_num)02d
 6command=/root/php-4.4.9/sapi/cgi/php -b 192.168.0.3:90%(process_num)02d -c /usr/local/etc/php.ini
 7autostart=true
 8autorestart=true
 9user=USER
10numprocs=5
11redirect_stderr=true
12EOF
13
14echo supervisord_enable=YES > /etc/rc.conf.d/supervisord
15service supervisord start

Now that you have PHP running, you can set up nginx to use one of the upstreams defined above.

About Me

Dev gone Ops gone DevOps. Any views expressed on this blog are mine alone and do not necessarily reflect the views of my employer.

Categories