CentOS7, ISPConfig3, and multiple PHP versions

Currently PHP developers face a great problem with PHP version - most OS repos already have outdated versions (CentOS has 5.4 which has passed its end of life!), but just swapping out versions is just not an option - especially with the version requirements of different frameworks / libraries. Furthermore, usually to have more than one version meant recompiling, and keeping up with updates - and no one wants that. Here's how to setup a server (virtual of physical), with ISPConfig3 hosting panel, multiple PHP versions, latest Apache and Mariadb in less than a half hour, with zero compiling. You can then manage your virtual hosts and their PHP version from a nice UI.

Part 1: Assumptions of what you have and where you want to go

First, assumptions! Here is what I assume you have already done:

  • Installed a minimal CentOS7 to a working condition
  • Have an IP or hostname for that machine
  • You can SSH into the machine, and become root
  • You can access the internet
  • Have run yum update right before you start
  • SELINUX IS DISABLED (read: the steps required for SELinux to run have not been included)

And this is where we want to go:

  • Apache 2.4.18 (not 2.4.6 which comes in CentOS base and has known vulnerabilities)
  • PHP 5.4 in mod_php, FastCGI, and FPM mode
  • PHP 5.6 in FastCGI and FPM mode
  • PHP 7.0 in FastCGI and FPM mode
  • Use firewalld to manage your firewall
  • ISPConfig 3 panel to manage virtual hosts, databases, and PHP versions

Conventions / Sample data:

  • Server hostname is test.hexblot.com
  • MariaDB root password will be testerson
  • FPM port for PHP5.4 will be 9000
  • FPM port for PHP5.6 will be 9006
  • FPM port for PHP7.0 will be 9007
You should change the above data, when you see them, to fit your own environment / server.

Still here? Great! Onto the works.

Part 2: Prep our environment

First, we need to get some repos in for extra packages, and setup our firewall (you can do the firewall bit at the end, I just like to get the generic things out of the way early):

yum install epel-release wget firewalld

Now let's get our firewall configured. We will allow traffic from http (port 80), https (port 443) and port 8080 (for our panel). We'll also remove the dhcp client for IPv6, since we want static IPs all around.

systemctl start firewalld
systemctl enable firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --remove-service=dhcpv6-client
firewall-cmd --reload

You can look at your fine work by using

firewall-cmd --list-all

With our firewall ready, let's get the extra repositories we'll need for our later steps:

First, the IUS repo by Rackspace -

wget https://centos7.iuscommunity.org/ius-release.rpm

Then the safe repository by Remi -

wget http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

And get them installed:

rpm -ivh ius-release.rpm remi-release-7.rpm

All set, on to the meat of things.

Part 3: Apache

Very vanilla things here, just install the packages from the IUS repo and start/enable the service. Most of the configuration will be done by ISPConfig later on.

yum install httpd24u mod24u_ssl mo24u_session mod_fcgid mod_xsendfile
systemctl start httpd
systemctl enable httpd

Part 4: MariaDB 10.1

To get the latest and greatest, both in terms of performance and least vulnerabilities, we choose MariaDB 10.1, again from the IUS repo. The trick here is that CentOS comes bundled with the mariadb-libspackage, which conflicts with any other version. Hence, we'll swap it out using the very helpful yum-replace-plugin provided by the IUS repo.

yum install yum-plugin-replace
yum replace mariadb-libs -replace-with=mariadb101u-libs
Do note it is normal for the replace plugin to whine about not finding all the needed bindings, just say yes )
yum install mariadb101u mariadb101u-server

At this point, I'd recommend you create a configuration file optimized for your server and usage before first starting MariaDB. Changing the config file later on is bound to cause issues! A good generator tool by Percona is available here. Paste the generated configuration at /etc/my.cnf , and then start MariaDB:

systemctl start mariadb
systemctl enable mariadb

Depending on a number of factors, starting MariaDB can take a while, be patient.

Be sure to run

mysql_secure_installation

to disable anonymous access to your databases!! Just remember the root password you set (in this example, testerson was used).

Part 5: PHP 5.4 (CentOS repos)

Not much really. This will simply install the required packages, and we're ready to go.

yum install php php-bcmath php-cli php-common php-gd php-intl php-mbstring php-mysqlnd php-pdo php-pear php-soap php-xml php-xmlrpc php-fpm
Of course you can add more of the php-* packages to enhance your PHP5.4 functionality.

Reload Apache to get mod_php and fcgi mode to work:

systemctl restart httpd

And start the FPM process

systemctl start php-fpm
systemctl enable php-fpm

Do note that currently you need special configuration to send bit to FPM - this will be handled by ISPConfig later on though, so no need to do anything yet.

Note: your php.ini for PHP5.4 is located at /etc/php.ini

Part 6: PHP 5.6 (Remi-safe repos)

Here's where it starts getting interesting. Remi-safe repo provides alternate version of PHP and support packages, in a no-conflict mode by using the php version as a prefix to everything. This means that your FPM service will be php56-php-fpm , your php.ini will be different, and your cli will be php56 .

yum install php56-php-bcmath php56-php-cli php56-php-common php56-php-fpm php56-php-gd php56-php-intl php56-php-mbstring php56-php-mcrypt php56-php-mysqlnd php56-php-opcache php56-php-pdo php56-php-pear php56-php-pecl-uploadprogress php56-php-soap php56-php-xml php56-php-xmlrpc

Again, feel free to add more php56-php-* packages to enhance your PHP5.6 functionality.

One thing to pay attention to at this point is that we cannot start our FPM process, since it will conflict with the already installed PHP (they both start at the same port). To fix that, use your favorite command line editor, and edit /opt/remi/php56/root/etc/php-fpm.d/www.conf so that

listen = 127.0.0.1:9000

is changed to something like

listen = 127.0.0.1:9006

You can use any port number with the following limitations:

  • 9000 is currently used by our PHP5.4 process
  • 9010 is the base port that ISPConfig will use (each site gets its own pool, starting at 9010. Next site will be at 9011, and so on)

After you save your changes, you can move on to start the PHP56 FPM service

systemctl start php56-php-fpm
systemctl enable php56-php-fpm

And you're done with this part.

Note: Your php.ini for all PHP56 settings is located at /opt/remi/php56/root/etc/php.ini

Part 7: PHP 7.0 (Remi-safe repos)

As with before, we'll be installing PHP7.0 in no-conflict mode. This means that your FPM service will be php70-php-fpm, your php.ini will be different, and your cli will be php70.

yum install php70-php-bcmath php70-php-cli php70-php-common php70-php-fpm php70-php-gd php70-php-intl php70-php-json php70-php-mbstring php70-php-mcrypt php70-php-mysqlnd php70-php-opcache  php70-php-pdo php70-php-pear php70-php-pecl-uploadprogress php70-php-pecl-zip php70-php-soap php70-php-xml php70-php-xmlrpc
Once more, feel free to install more php70-php-* packages to enhance your PHP70 installation.

As with PHP56, we need to change the port for our FPM service. This time, the configuration file we need is located at /etc/opt/remi/php70/php-fpm.d/www.conf . Open the file in your favorite editor, and change:

listen = 127.0.0.1:9000

to:

listen = 127.0.0.1:9007

Same port restrictions as with PHP56 (you cannot obviously use 9006 or any port you chose in the previous step - needs to be a different port). Save and start/enable:

systemctl start php70-php-fpm
systemctl enable php70-php-fpm

And you're done once more.

Note: Your php.ini for all PHP70 settings is located at /etc/opt/remi/php70/php.ini

Part 8: Installing ISPConfig

Installation of ISPConfig is quite straight forward:

  1. Download the ISPConfig package from http://www.ispconfig.org/ispconfig/download/ . At the time of writing, latest version was 3.0.5.4p9. Assuming that's still the case, you can use the direct download link to get the package
     
    wget http://downloads.sourceforge.net/project/ispconfig/ISPConfig%203/ISPConfig-3.0.5.4p9/ISPConfig-3.0.5.4p9.tar.gz
    
  2. Extract the contents of the downloaded file
     
    tar zxvf ISPConfig-3.0.5.4p9.tar.gz
    
  3. Run the installer
     
    php -q ispconfig3_install/install/install.php
    
  4. Select options as desired. For this example, we'll be using the following options (I am not including all of them):
    1. Language: en
    2. Installation mode: expert
    3. Fully Qualified hostname (FQDN): your hostname or IP if you don't have one
    4. MySQL server hostname: localhost
    5. MySQL root username: root
    6. MySQL root password: whatever you chose in Part4
    7. MySQL database to create: dbispconfig
    8. MySQL charset: utf8
    9. ISPConfig mysql username: ispconfig
    10. ISPConfig mysql database password: accept the generated hash
    11. Shall this server join an existing ISPConfig multiserver setup? N
    12. Configure mail? N (unless you have followed a guide for adding email capabilities to the system)
    13. Configure JailKit? N (unless you have followed a guide for adding jailkit)
    14. Configure FTP server? N (unless you have followed a guide for adding an FTP server
    15. Configure Apache Server? Y
    16. Configure Firewall? N
    17. Install ISPConfig Web Interface? Y
    18. ISPConfig Port? 8080
    19. Enable SSL? Y - accept defaults for the CSR of your self-signed certificate, or fill up any data you want. Just make sure NOT to include a challenge password.
    20. Installation complete! ( you'll get a warning about date() and setting a timezone in php.ini , which is beyond the scope of this tutorial, and can be ignored ).

Part 9: Configuring Additional PHP version in ISPConfig

Congratulations for reaching this far! Now on to configuring ISPConfig to be able to use all the nice stuff we just installed.

First off , head to your panel to login - you should be able to see the interface at https://your-hostname.com:8080 - in our example, https://test.hexblot.com:8080 and login with the default credentials ( username admin, password admin ).

First things first - change the admin account credentials!

  1. Go to the System tab from the top horizontal menu
  2. Click on CP Users from the left side menu
  3. Change the username and password of the admin user
    Personally, I also uncheck most of the modules there, since I do not use them (eg dns, dashboard, mail, help, vm)

Now, on to configuring additional PHP versions!

  1. Go to the System tab from the top horizontal menu if you aren't already there (which you really should!)
  2. Click on Additional PHP Versions from the left side menu
  3. Click on Add new PHP version
  4. Add control panel identification data in the Name tab
    1. Server should already be selected - if this were a multiserver setup, you could select another server.
    2. Client should be left blank, unless you want this PHP version to be only available for a specific client
    3. PHP Name is what you'll see in the panel to refer to this PHP version. Type in PHP5.6
  5. Switch to the FastCGI Settings tab (no need to click save, the panel auto saves when moving between tabs).Here type:
    • Path to the PHP FastCGI binary : /opt/remi/php56/root/usr/bin/php-cgi
    • Path to the php.ini directory : /opt/remi/php56/root/etc
  6. Switch to the PHP-FPM Settings tab. Here type:
    • Path to the PHP-FPM init script : php56-php-fpm
    • Path to the php.ini directory : /opt/remi/php56/root/etc
    • Path to the PHP-FPM pool directory : /opt/remi/php56/root/etc/php-fpm.d
  7. Click Save - you are done with PHP5.6! (Don't try until we're done with Part10, since FPM won't properly work until then!)
  8. Repeat the process for PHP7 with the following settings:
    • Name tab
      • Name: PHP70
    • FCGI tab
      • Path to the PHP FCGI binary: /opt/remi/php70/root/usr/bin/php-cgi
      • Path to the php.ini directory: /etc/opt/remi/php70
    • PHP FPM tab
      • Path to the PHP-FPM init script: php70-php-fpm
      • Path to the php.ini directory: /etc/opt/remi/php70
      • Path to the PHP-FPM pool directory: /etc/opt/remi/php70/php-fpm.d
  9. All done with PHP7!

You should now be able to go to the Sites horizontal tab, and click on Add New Website, and under PHP see Fast CGI and PHP FPM ( with proper version options - default is 5.4, and the rest have the names we've given them ).

But wait? I chose PHP FPM with version PHP 5.6 and nothing happened!!! What's going on? Read on!

Part 10: Fixing a CentOS 7 specific misbehavior of ISPConfig

For some reason (probably earlier version compatibility), ISPConfig under CentOS7 will always try to reload the base php-fpm service instead of the one selected. This is an override for reasons unknown to me, and my simple patch for that has been accepted for ISPConfig 3.1. It's so simple that we'll apply it right now!

Use your favorite text editor to edit the file /usr/local/ispconfig/server/mods-available/web_module.inc.php

Comment out lines 255 and 267, changing both from

$initcommand = 'systemctl restart php-fpm.service';

to

// $initcommand = 'systemctl restart php-fpm.service';

This is an inefficient but simple way around the issue, but will do the job just fine. A better way would be to comment out the blocks that do the whole override thing, and the easiest way to describe that is to show you the diff for it here .

Either way works, and ISPConfig will happily work after this with your FPM versions!

Note: ISPConfig applies all changes every minute -- once you save something, it may take up to a bit over a minute to process the changes given. Make sure to give it a couple of minutes before searching for errors!
If, understandably, you don't like waiting about you can manually trigger this process by running
/usr/local/ispconfig/server/server.sh
Need any further clarifications? Got ideas to make this better? Found bugs? Let me know in the comments!