Install PHP5.2, PHP5.6 and PHP7.0 as Apache + FCGI on AlmaLinux8 / Centos8

This might sound very strange in 2023, but here are HOW-TO instructions on how to install Apache with FCGI and various number of old PHP versions, starting with PHP5.2 and up to PHP8.0.

In our company reason for such setup was an internal (and very important) CRM system, that we wrote ourselves and still keep maintaining, but never had time and resources to make it compatible with at least PHP7. Up to recent time everything was running on Centos6 server, but the need to migrate to different data center put us (read – me) into situation, where I had to migrate that old system to newer OS.

Over the years my personal preference has shifted to Debian, but after failing to compile old code on the latest Debian – I gave up and gave AlmaLinux8 a try.

Drop me a message, if you find this article interested and helpful!

P.S: this article is not intended for newbies, but for system administrators, who actually understand it. Of course, if you need, I can help, just drop me a line.

Update 6.August: turns out, PHP5.2 can be compiled with openSSL 1.0.2 and with that version it will support much broader range of ciphers and features.
Update 7.August: added –with-freetype-dir=/usr to PHP5.2 compilation to support GD TTF related functions for adding smooth texts to images.
Update 8.September: added instructions for PHP7.4 compilation and added –with-external-gd option to PHP8.0


Let’s assume we are on a clean AlmaLinux8 setup.

First of all – disable selinux, it will make things easier. After all – you should be careful this setup, but you don’t want extra problems. The best security for such setup is to limit PHP using open_basedir.
– disable selinux in /etc/sysconfig/selinux

# install large group of all kind of useful things
yum groupinstall "Development Tools"

# I suppose you will want MySQL / MariaDB server
# AlmaLinux8 comes with nice MariaDB 10.3
yum install mariadb-common mariadb-server mariadb mariadb-devel mariadb-server-utils

# Also let's not forget about install Apache and mod_fcgi
yum install httpd httpd-devel httpd-tools mod_fcgid spawn-fcgi fcgi fcgi-devel 

# this is place, where we will be compiling things
mkdir /root/install


# First we will install old libGD
# Old PHP do not like latest GD...
# install PNG, JPG, FreeType, XML and ZIP packages
yum install wget libpng-devel libjpeg-turbo-devel freetype-devel fontconfig-devel libxml2-devel sqlite sqlite-devel sqlite-libs libsqlite3x libsqlite3x-devel libzip libzip-devel

# now head to install GD 2.0.33 - lovely old version
cd /root/install
wget https://src.fedoraproject.org/lookaside/extras/gd/gd-2.0.33.tar.gz/be0a6d326cd8567e736fbc75df0a5c45/gd-2.0.33.tar.gz
tar -zxf gd-2.0.33.tar.gz
cd gd-2.0.33
./configure --prefix=/opt/libgd --with-jpeg --with-png --with-freetype
make && make install
cd /opt/libgd
ln -s lib lib64


# Also we need library and includes for MySQL.
# Unfortunately old PHP don't recognize MariaDB's development package
# We download MySQL source and just use it for compilation
cd /root/install
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.42-linux-glibc2.12-x86_64.tar.gz
tar -zxf mysql-5.7.42-linux-glibc2.12-x86_64.tar.gz
cd mysql-5.7.42-linux-glibc2.12-x86_64
mkdir -p /opt/mysql-5.7
mv bin /opt/mysql-5.7/
mv include /opt/mysql-5.7/
mv lib /opt/mysql-5.7/
mv share /opt/mysql-5.7/
cd /opt/mysql-5.7
ln -s lib lib64


# main issue with old PHP are incompatibility with newest OpenSSL and Curl
# that's why we are going to install old versions

###
### PHP 5.2
###

# update 6.AUGUST.2023 - PHP5.2 can be installed with openSSL 1.0.2
# follow steps for openSSL + curl for 1.0.2 described below
cd /root/install
wget https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz
tar -zxf openssl-1.0.2u.tar.gz
cd openssl-1.0.2u
./config --prefix=/opt/openssl-1.0.2 shared zlib
make -j 8
make install
cd /opt/openssl-1.0.2
ln -s lib lib64

# and compile another version of LibCurl, that uses openSSL 1.0.2
cd /root/install
rm -rf curl-8.2.1*
# download source from https://curl.se/download.html
wget https://curl.se/download/curl-8.2.1.tar.gz
tar -zxf curl-8.2.1.tar.gz
cd curl-8.2.1
./configure --prefix=/opt/libcurl-ssl-1.0.2 --enable-http --enable-ftp --disable-ldap --disable-dict --disable-telnet --disable-tftp --enable-thread --enable-crypto-auth --enable-cookies --with-zlib --with-openssl=/opt/openssl-1.0.2
make && make install
cd /opt/libcurl-ssl-1.0.2
ln -s lib lib64

# Now let's build PHP 5.2
# There was some requirement to patch original version, I could not find original
# post about it, but had patched version laying around.
cd /root/install
wget aleksandrov.eu/php-5.2.17.patched.tar.gz
tar -zxf php-5.2.17.patched.tar.gz
cd php-5.2.17
make clean
rm -f config.log
rm -f config.cache
./configure  --prefix=/opt/php-5.2 --enable-fastcgi --enable-force-cgi-redirect --with-zlib --with-curl=/opt/libcurl-ssl-1.0.2 --enable-exif --with-gd=/opt/libgd --with-gettext --enable-mbstring --with-mysql=/opt/mysql-5.7 --enable-zip --with-pear --with-openssl=/opt/openssl-1.0.2 --with-libxml-dir=/usr --with-pdo-mysql --libdir=lib64 --enable-embedded-mysqli --with-mysql-sock=/var/lib/mysql/mysql.sock  --enable-sockets --with-freetype-dir=/usr
make && make install
# don't forget to copy php.ini file to /opt/php-5.2/lib/php.ini and configure it

# configuration examples for Apache and FCGI will be shown later.

# Head to compiling PHP5.6
# PHP5.6 also requires OpenSSL 1.0.2

# compiling PHP5.6
cd /root/install
wget https://www.php.net/distributions/php-5.6.40.tar.gz
tar -zxf php-5.6.40.tar.gz
cd php-5.6.40
make clean
rm -f config.log
rm -f config.cache
./configure --prefix=/opt/php-5.6 --disable-fileinfo --disable-posix --enable-bcmath --enable-calendar --enable-exif --enable-ftp --enable-gd-native-ttf --enable-libxml --enable-mbstring --enable-pdo --enable-soap --enable-sockets --enable-zip --with-curl=/opt/libcurl-ssl-1.0.2 --with-freetype-dir=/usr --with-gd --with-pear --with-gettext --with-mysql=/opt/mysql-5.7 --with-openssl=/opt/openssl-1.0.2 --with-pdo-mysql --with-zlib --enable-embedded-mysqli --enable-opcache 
make && make install
# do not forget to copy php.ini to /opt/php-5.6/lib/php.ini

# compiling PHP7.0
# Now we don't need any special openSSL, therefore we use system OS packages
cd /root/install
wget https://www.php.net/distributions/php-7.0.33.tar.gz
tar -zxf php-7.0.33.tar.gz
cd php-7.0.33
make clean
rm -f config.log
rm -f config.cache
./configure --prefix=/opt/php-7.0 --enable-mysqlnd --disable-fileinfo --disable-posix --enable-bcmath --enable-calendar --enable-exif --enable-ftp --enable-gd-native-ttf --enable-libxml --enable-mbstring --enable-pdo --enable-sockets --enable-zip --with-curl --with-freetype-dir=/usr --with-gd --with-pear --with-gettext --with-openssl --with-pdo-mysql=mysqlnd --with-zlib --with-openssl
make && make install
# do not forget to copy php.ini to /opt/php-7.0/lib/php.ini

# compiling PHP7.2
cd /root/install
wget https://www.php.net/distributions/php-7.2.34.tar.gz
tar -zxf php-7.2.34.tar.gz
cd php-7.2.34
make clean
rm -f config.log
rm -f config.cache
./configure --prefix=/opt/php-7.2 --enable-mysqlnd --disable-fileinfo --disable-posix --enable-bcmath --enable-calendar --enable-exif --enable-ftp --enable-libxml --enable-mbstring --enable-pdo --enable-sockets --enable-zip --with-curl --with-gd --with-pear --with-gettext --with-openssl --with-pdo-mysql=mysqlnd --with-zlib --with-openssl --with-mysqli
make && make install
# do not forget to copy php.ini to /opt/php-7.2/lib/php.ini

# compiling PHP 7.4
# PHP7.4+ requires oniguruma. 
# Precompiled oniguruma package for unknown reason is not being recognized
# therefore we are installing it manually.
cd /root/install
git clone https://github.com/kkos/oniguruma.git
cd oniguruma
./autogen.sh
./configure --prefix=/usr --libdir=/usr/lib64
make && make install

# install PHP7.4
cd /root/install
wget https://www.php.net/distributions/php-7.4.33.tar.gz
tar -zxf php-7.4.33.tar.gz
cd php-7.4.33
make clean
rm -f config.log
rm -f config.cache
'./configure' '--prefix=/opt/php-7.4' '--enable-mysqlnd' '--disable-fileinfo' '--disable-posix' '--enable-bcmath' '--enable-calendar' '--enable-exif' '--enable-ftp' '--enable-mbstring' '--enable-pdo' '--enable-sockets' '--with-zip' '--with-curl' '--enable-gd' '--with-pear' '--with-gettext' '--with-openssl' '--with-pdo-mysql=mysqlnd' '--with-zlib' '--with-openssl' '--with-mysqli' '--with-external-gd'
make -j 8 && make install



# compiling PHP8.0
cd /root/install
wget https://www.php.net/distributions/php-8.0.28.tar.gz
tar -zxf php-8.0.28.tar.gz
cd php-8.0.28
make clean
rm -f config.log
rm -f config.cache
./configure --prefix=/opt/php-8.0 --enable-mysqlnd --disable-fileinfo --disable-posix --enable-bcmath --enable-calendar --enable-exif --enable-ftp --enable-mbstring --enable-pdo --enable-sockets --with-curl --with-pear --with-gettext --with-openssl --enable-mysqlnd --with-pdo-mysql --with-zlib --with-openssl --with-mysqli --with-zip --enable-gd --with-external-gd
make && make install
# do not forget to copy php.ini to /opt/php-8.0/lib/php.ini

PHP settings, that I always check and change

open_basedir = /home:/opt:/tmp
expose_php = Off
max_execution_time = 180
max_input_vars = 4000
memory_limit = 512M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE & ~E_WARNING
post_max_size = 100M
; default_charset = "UTF-8"
cgi.force_redirect = 1
upload_max_filesize = 100M
mysqli.default_socket = /var/lib/mysql/mysql.sock
pdo_mysql.default_socket=/var/lib/mysql/mysql.sock
mysqlnd.collect_statistics = Off
date.timezone = Europe/Oslo

Apache settings to check and set

in file /etc/httpd/conf.modules.d/10-fcgid.conf add

AddHandler fcgid-script .php
FcgidMinProcessesPerClass 1
FcgidIdleScanInterval 60
FcgidIdleTimeout 300
FcgidMaxProcessesPerClass 30
FcgidMaxProcesses 200
FcgidMaxRequestsPerProcess 300
FcgidIOTimeout 3600
FcgidProcessLifeTime 900
FcgidMaxRequestLen 1073741824
FcgidIOTimeout 300
FcgidBusyTimeout 3600
FcgidFixPathinfo 1

in file /etc/httpd/conf.modules.d/00-mpm.conf
– disable mod_mpm_event
– enable mod_mpm_worker

in file /etc/httpd/conf.modules.d/00-base.conf
– make sure, that suexec module is enabled


FCGI script example

Very important note: all FCGI scripts must reside under /var/www folder due to precompiled permission / setting in the mod_suexec module. I have spent several days trying to figure this out. I usually put website files in appropriate user’s home folder, for example: /home/user1/public_html – but FCGI starter scripts must still be under /var/www. I put them in /var/www/php-wrappers/user1/ folder – basically you must have separate folder for each user’s FCGI scripts. Also for configuration flexibility I always put php.ini

Example of FCGI script for PHP5

Assume we have user “randweb“.
– make folder for his FCGI scripts – /var/www/php-wrappers/randweb
– copy php.ini from PHP5.2 installation to this folder, call it “php-5.2.ini”, just in case you might need to have several different versions running for the same user (yes, this is possible!)
– create file /var/www/php-wrappers/randweb/php52
– put the following content into that file:

#!/bin/sh

PHPRC="/opt/php-5.2/lib"
export PHPRC

PHP_FCGI_MAX_REQUESTS=500
export PHP_FCGI_MAX_REQUESTS

exec /opt/php-5.2/bin/php-cgi -c /var/www/php-wrappers/randweb/php-5.2.ini

Important: Now remember to change owner of the FCGI folder and all the files inside. Also you must make FCGI script executable.

chmod +x /var/www/php-wrappers/randweb/php52
chown randweb:randweb /var/www/php-wrappers/randweb -R

Example of VirtualHost

Please note paths to FCGI script and user folders. As I mentioned, I put all user webfiles in /home/username/public_html. Apache’s configuration is usually laying in /etc/httpd/virtual-hosts (right, you need to make and include that folder!)

<VirtualHost *:80>
ServerName randweb.hosting.guru
DocumentRoot /home/randweb/public_html
ServerAdmin [email protected]
UseCanonicalName Off
<Directory /var/www/php-wrappers/>
    SetHandler fcgid-script
    Options +ExecCGI

    # Customize the next two directives for your requirements.
    Order allow,deny
    Allow from all
</Directory>
<Directory /home/randweb/public_html>
    FCGIWrapper /var/www/php-wrappers/randweb/php52 .php

    Require all granted
    AllowOverride All

    Options All -Indexes
    Options +ExecCGI

    Order allow,deny
    Allow from all
</Directory>

SuexecUserGroup randweb randweb
</VirtualHost>

For other PHP versions steps are very similar. You just need to set path to correct PHP version in the FCGI script. And if you want to have different PHP version for a subfolder – you can have it by adding <Directory> block and creating FCGI script with different PHP version.


Where to check for errors

PHP / Apache errors are in:
/var/log/httpd/error_log

SuEXEC errors are in:
/var/log/secure


I think that is so far, what I can share with you. If you have questions of find some mistakes – please drop me a line. Happy 2023!

Leave a Reply

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