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”:
https://www.softwarecollections.org/
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.
Software collections
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.
Steps
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:
php
This should return:
php: command not found…
Then run
python –version
Which should return:
Python 2.7.5
So we should be all and ready to begin.
Repos
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 update
yum install centos-release-scl
yum install scl-utils-build
Apache http
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:
/opt/rh/httpd24/root/etc/httpd
Additionally the document root has moved and is now:
/opt/rh/httpd24/root/var/www/html
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(); ?>”.
PHP 7.2
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:
The lesson I learned was that installing “rh-php72”, while necessary wasn’t the one that made it work, it was “rh-php72-php” that did the magic. Listing the contents of “rh-php72-php” shows:
[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.
Python 3.6
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
python –version
exit
Need to:
- 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:
mod_wsgi-express install-module
To check it is there run:
cd /opt/rh/httpd24/root/etc/httpd/modules
ls -la
You should see the mod_wsgi listed as:
mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so
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 “/”.
Restart Apache:
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:
Final check
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:
http://centos7-base/test2.php
http://centos7-base/wsgi/test.wsgi
Resources
Read the docs: mod_wsgi documentation
https://modwsgi.readthedocs.io/en/develop/index.html
Python Package Index: mod-wsgi
https://pypi.org/project/mod-wsgi/
Software Collections
https://www.softwarecollections.org/en/
Red Hat Developers Blog: Software Collections on Red Hat Enterprise Linux
https://developers.redhat.com/blog/2013/01/28/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.