I am setting up a new CentOS 7 server, in 2019, because I want a long life public facing WordPress host that I can update easily. For example when the “Heartbleed” security bug, in the OpenSSL cryptography library, was discovered you needed to update your SSL install. This proved to be a major problem for me because my O/S was Fedora and quite old so updating was difficult.
The problem for me in setting up a WordPress install on CentOS 7 is that like RedHat 7 it comes with PHP 5 and Python 2. Both quite dated. In addition it was not made easy to update to PHP 7 and Python 3.
The “correct” and “official” way to resolve this is via RedHat’s “Software Collections”:
Looking around for how to run CentOS/RHEL 7 with Apache httpd 2.4, PHP 7.x and Python 3.x I found a multitude of solutions, but mostly mixes of using scl and downloading modules from other repos. It became a minefield and it was really looking like not the right way to do it.
I have come to the conclusion the answer is to run all of Apache, PHP and Python via scl. The problem seems to be how to run all of these things together. In particular if Apache is running from scl how do you get PHP installed within that particular.
To quote the Software Collections site:
Software Collections give you the power to build and concurrently install multiple versions of the same components on your system, without affecting the system versions of the packages installed from your distribution.
The intent of SoftwareCollections.org is to give projects and third parties the ability to:
- Create and distribute multiple versions of software for major RPM-based Linux distributions.
- Package software that may not be easy to distribute in upstream distributions.
- Allow projects to move at a different pace than the upstream distribution release cycle.
- Give users more flexibility and choice in software selection for their chosen distributions.
- Provide a flexible format for admins and users to package their own software.
To stop any confusion and ensure we are using the right versions first ensure you don’t have either Apache httpd or PHP isntalled:
rpm -qa | grep http
rpm -qa | grep php
rpm -qa | grep python
Python should return a bunch of bunch of RPM but they should be mostly v2. So now run:
This should return:
php: command not found…
Which should return:
So we should be all and ready to begin.
You should probably install the REmi and EPEL repos. Run the following:
wget -q http://rpms.remirepo.net/enterprise/remi-release-7.rpm
wget -q https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -i remi-release-7.rpm epel-release-latest-7.noarch.rpm
Enable software collections
To enable software collections run:
yum install centos-release-scl
yum install scl-utils-build
Now install the scl httpd24 package and all http24 modules. One thing that got me about this is it is simply called “httpd24” not something like “rh-httpd24”:
sudo yum install httpd24 httpd24-httpd-devel httpd24-mod\*
This includes httpd24-httpd-devel which is required when we install mod_wsgi for Python
Now enable the http24 collection, enable the service:
scl enable httpd24 bash
systemctl enable httpd24-httpd.service
systemctl restart httpd24-httpd
The thing with software collections is that it moves everything from a folder perspective. So the config folders for http are no longer under “/etc/http” but are now buried much deeper in:
Additionally the document root has moved and is now:
So now create a test file:
echo “<?php phpinfo(); ?>” > /opt/rh/httpd24/root/var/www/html/test.php
So if you try to get to this page, http://centos7-base/test.php it won’t work and most likely you will see a blank page. This is because PHP is still not enabled in Apache, neither is it installed on the VM. In fact if you “View page source” it will just show “<?php phpinfo(); ?>”.
If you are still in the bash shell from starting httpd then exit. You need to install PHP, install the following:
systemctl stop httpd24-httpd.service
yum install rh-php72 rh-php72-php rh-php72-php-mysqlnd
service httpd24-httpd restart
You should now find when you go to http://centos7-base/test.php this should now bring back the full PHP info:
[root@centos7-base /]# repoquery -l rh-php72-php /opt/rh/httpd24/root/etc/httpd/conf.d/rh-php72-php.conf /opt/rh/httpd24/root/etc/httpd/conf.modules.d/15-rh-php72-php.conf /opt/rh/httpd24/root/usr/lib64/httpd/modules/librh-php72-php7.so /opt/rh/httpd24/root/usr/share/httpd/icons/rh-php72-php.gif /opt/rh/rh-php72/register.content/var/opt/rh/rh-php72/lib/php/session /opt/rh/rh-php72/register.content/var/opt/rh/rh-php72/lib/php/wsdlcache /var/opt/rh/rh-php72/lib/php/opcache /var/opt/rh/rh-php72/lib/php/session /var/opt/rh/rh-php72/lib/php/wsdlcache
To finish of PHP lets install some more useful packages and restart:
yum install rh-php72-php-gd rh-php72-php-mbstring rh-php72-php-intl rh-php72-php-pecl-apcu
service httpd24-httpd restart
You can optionally restart the host to prove Apache auto starts – probably a good idea.
Before you start run “python –version” which should show you are running Python 2.7.
Now install Python 3.6:
sudo yum install rh-python36
Test by running
scl enable rh-python36 bash
- Enable httpd24 and python36 together
- Upgrade pip
- Install mod-wsgi
scl enable rh-python36 httpd24 bash
pip install –upgrade pip
pip install mod-wsgi
If pip installs mod-wsgi successfully you will see:
[root@centos7-base ~]# [root@centos7-base ~]# pip install mod-wsgi Collecting mod-wsgi Using cached https://files.pythonhosted.org/packages/26/03/a3ed5abc2e66c82c40b0735c2f819c898d136879b00be4f5537126b6a4a4/mod_wsgi-4.6.7.tar.gz Installing collected packages: mod-wsgi Running setup.py install for mod-wsgi ... done Successfully installed mod-wsgi-4.6.7
When trying to install “mod-wsgi” you will get the following error if you have not installed “httpd24-httpd-devel”:
RuntimeError: The ‘apxs’ command appears not to be installed or is not executable.
To put the new mod_wsgi module into the Apache httpd modules folder run:
To check it is there run:
You should see the mod_wsgi listed as:
Add the following into the apache config along with the other modules by creating a one line conf file:
echo “LoadModule wsgi_module modules/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so” > /opt/rh/httpd24/root/etc/httpd/conf.modules.d/16-mod-wsgi.conf
Ensure the highlighted bit matches the name of the module that you listed earlier in the Apache httpd “/modules” folder. In our case “mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so”.
Create a file called “mod_wsgi-py36.conf”:
echo “WSGIScriptAlias /wsgi/ /opt/rh/httpd24/root/var/www/wsgi-scripts/” > /opt/rh/httpd24/root/etc/httpd/conf.d/mod_wsgi-py36.conf
Yes need the trailing forward slashes “/”.
systemctl restart httpd24-httpd.service
Logs folder is: /opt/rh/httpd24/root/etc/httpd/logs
Create the folder for the scripts and cd to it:
mkdir -p /opt/rh/httpd24/root/var/www/wsgi-scripts/
Create a test php file in this folder called “test.wsgi” and put the following in it:
# # Sample WSGI Python script from Zoyinc # import datetime import sys def application(environ, start_response): status = '200 OK' currDateTime = datetime.datetime.now().strftime("%b %d %Y %H:%M:%S") outputStr = ''' <html> <head><title>Test Python Script from Apache</title></head> <body> </br> <h2>Today is: ''' + currDateTime + '''</h2> </br> This is a test page generated by Python based on instructions from <a href='http://www.zoyinc.com'>Zoyinc</a></br> Python version is ''' + str(sys.version) + ''' </body> </html> ''' response_headers = [('Content-type', 'text/html'), ('Content-Length', str(len(outputStr)))] start_response(status, response_headers) return [bytes(outputStr, encoding= 'utf-8')]
There are a number of important points to this script.
- By the fact that it outputs the time we know it is via Python and not a static page
- WSGI has been hard coded to use ‘application as the entry point, so unless you change the WSGI build you need to use ‘def application()’
- The ‘status’ is the response sent back to the browser
- WSGI expects a byte string with the correct encoding this is why we use ‘bytes()’ and also “encoding=’utf-8′”
- If you don’t set the header to be ‘text/html’ then in a browser it will be just text not html
- If it’s not working tail the “error_log” file in “/opt/rh/httpd24/root/etc/httpd/logs”
To get to the page use: http://centos7-base/wsgi/test.wsgi
You should see:
As it has been a bit of a log journey I would restart the host and then go to both the php and python pages. That way you know Apache auto start and also that both PHP and Python are working at the correct versions after restart:
Read the docs: mod_wsgi documentation
Python Package Index: mod-wsgi
Red Hat Developers Blog: Software Collections on Red Hat Enterprise Linux
Excellent explanation from 2013, by Marcela Maslanova, about when it was created and why it was created. Gives great insight to motivations and history.