How to Install Apache, PHP 7, and PHP-FPM on CentOS 7

Posted on

This tutorial is also available for Ubuntu 18.x and 19.04.

PHP-FPM, or PHP FastCGI Process Manager, is an alternative implementation of PHP FastCGI that can handle a high volume of queries. Combined with PHP 7, PHP-FPM achieves a higher performance level than any previous version of PHP.

In this tutorial, we’ll see how to install and configure Apache, PHP 7.2, and PHP-FPM on a CentOS server.

Step # 1: Preparations

At first, disable SELinux:

setenforce 0

Edit the SELinux configuration file:

vi /etc/selinux/config

Change the value of the “SELINUX” parameter to “disabled”:

# This file controls the state of SELinux on the system.
# SELINUX = can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX = disabled
# SELINUXTYPE = can take one of three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE = Targeted

Before you begin the installation, update the operating system and installed packages:

yum update -y

Import the GPG key that is needed to validate the software packages:

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY*

Add the EPEL repository. It contains most of the packages we will install later:

yum install -y epel-release

Finally, install the “Development Tools” group and the “yum-utils” package:

yum -y groupinstall 'Development Tools'
yum -y install yum-utils

Step # 2: Installing Apache, PHP 7.2, and PHP-FPM

On CentOS 7, PHP version 5.6 is installed by default. You must add and activate the REMI repository to install PHP 7.

yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum-config-manager --enable remi-php72

Then install Apache, PHP, and PHP-FPM, as well as some needed packages:

yum -y install httpd mod_ssl php php-zip php-fpm php-devel php-gd php-imap php-ldap php-mysql php-odbc php-pear php-xml php-xmlrpc php-pecl-apc php-mbstring php-mcrypt php-soap php-tidy curl curl-devel perl-libwww-perl ImageMagick libxml2 libxml2-devel mod_fcgid php-cli httpd-devel php-fpm php-intl php-imagick php-pspell wget

Step # 3: Apache Service Configuration

Add the following HTTP header rule to the Apache configuration. This security rule prevents attacks that exploit HTTPOXY vulnerability:

echo "RequestHeader unset Proxy early" >> /etc/httpd/conf/httpd.conf

Enable and start the httpd service:

systemctl enable httpd
systemctl restart httpd

Verify that the web server responds as it should:

centos apache test page

Step # 4: Configure PHP-FPM for the Main Website

On a new CentOS installation, the main website files are located in “/var/www/html”. The Apache service accesses this folder as the “apache” user, which is the user account of the service.

By default, PHP is configured as an Apache module. To verify this, create a file named “info.php” in /var/www/html:

vi /var/www/html/info.php

Copy the following content to the file:

<?php phpinfo(); ?>

Access this file through your web browser:

php apache handler

The Apache 2.0 Handler module currently manages PHP processes. We will now change that for PHP-FPM.

PHP-FPM configuration

For PHP requests to be handled by PHP-FPM, create two directories to hold the configuration files:

mkdir /etc/php-fpm.d/sites-enabled
mkdir /etc/php-fpm.d/sites-available

Then modify the PHP-FPM configuration file:

vi /etc/php-fpm.conf

Change the following line:

include=/etc/php-fpm.d/*.conf

For:

include=/etc/php-fpm.d/sites-enabled/*.conf

Then move the file “www.conf” into the subdirectory “sites-available”:

mv /etc/php-fpm.d/www.conf /etc/php-fpm.d/sites-available

Next, create a symbolic link to “www.conf” in “sites-enabled”:

ln -s /etc/php-fpm.d/sites-available/www.conf /etc/php-fpm.d/sites-enabled/www.conf

Create a directory to host PHP-FPM sockets files:

mkdir /var/run/php-fpm

Then modify the configuration file “www.conf”:

vi /etc/php-fpm.d/sites-available/www.conf

For performance reasons, we will use a UNIX socket rather than a TCP socket for communications between Apache and PHP-FPM services. Find the “listen” setting:

listen = 127.0.0.1:9000

And change it as follows:

listen = /var/run/php-fpm/default.sock

You must now specify which user will listen on the “socket.” Find the following lines:

;listen.owner = nobody 
;listen.group = nobody 
;listen.mode = 0660

Remove the semicolon in front of each parameter and change them as follows:

listen.owner = apache
listen.group = apache
listen.mode = 0660

While you’re there, scroll to the bottom of the file “www.conf” and enable the OPCache module :

php_value[opcache.file_cache]  = /var/lib/php/opcache

Save the file and exit the editor. Activate the “php-fpm” service and start it:

systemctl enable php-fpm
systemctl start php-fpm

Apache configuration

To use PHP-FPM on the main Web site, you must configure a default virtual host on port 80. Create a file named “default.conf”:

vi /etc/httpd/conf.d/default.conf

Copy the following directives to the file:

<VirtualHost _default_:80> 
       DocumentRoot "/var/www/html" 

       <Directory "/var/www/html"> 
               # allow from all 
               Order deny,allow 
               Options FollowSymLinks SymLinksIfOwnerMatch 
               Require all granted 
               AllowOverride All 
               php_admin_value open_basedir /var/www/html 
       </Directory> 

       ErrorLog logs/default-error_log 
       LogLevel warn 
       TransferLog logs/default-access_log 
       CustomLog logs/default-request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" 

       SuexecUserGroup apache apache 

       <Proxy "unix:/var/run/php-fpm/default.sock|fcgi://php-fpm"> 
               ProxySet disablereuse=off 
        </Proxy> 

       <FilesMatch \.php$> 
               SetHandler proxy:fcgi://php-fpm 
       </FilesMatch> 
</VirtualHost>

Save the file and exit the editor.

When installing the package mod_ssl, a file named “ssl.conf” is created to enable the SSL module for Apache. This file contains directives for the default virtual host running on port 443 (HTTPS). Edit this file:

vi /etc/httpd/conf.d/ssl.conf

At the end of the file, insert the instructions for PHP-FPM, before closing the “VirtualHost” section:

# [...]
#   Per-Server Logging: 
#   The home of a custom SSL log file. Use this when you want a 
#   compact non-error SSL logfile on a virtual host basis. 
CustomLog logs/ssl_request_log \ 
         "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" 

SuexecUserGroup apache apache 
<Proxy "unix:/var/run/php-fpm/default.sock|fcgi://php-fpm"> 
  ProxySet disablereuse=off 
</Proxy> 
<FilesMatch \.php$> 
  SetHandler proxy:fcgi://php-fpm 
</FilesMatch> 

</VirtualHost>

Then restart the “http” service:

systemctl restart httpd

Refresh the “info.php” page to check that PHP-FPM is working:

phpinfo php-fpm fastcgi

Step # 5: Configuring PHP-FPM for a Virtual Host

It is common for a web server to host multiple sites, and often each of these sites belongs to a different user. ToIn order to prevent PHP from accessing everyone’s files, different instances of PHP-FPM (called “pool”) must be run under different user accounts.

For this tutorial, we’ll be creating a virtual host for the “webhostinghero.home.lan” domain.

PHP-FPM configuration

First, create a user account and a directory for the new website:

adduser webhostinghero
sudo -u webhostinghero mkdir /home/webhostinghero/public_html
chmod -R +s /home/webhostinghero
chmod -R 0755 /home/webhostinghero

It is also better to create a folder to isolate the PHP session files:

sudo -u webhostinghero mkdir -p /home/webhostinghero/var/lib/php/session

Copy the default configuration file for PHP-FPM and edit the new file:

cp /etc/php-fpm.d/sites-available/www.conf /etc/php-fpm.d/sites-available/webhostinghero.conf
vi /etc/php-fpm.d/sites-available/webhostinghero.conf

Change the name of the instance:

; Start a new pool named 'www'. 
; the variable $pool can we used in any directive and will be replaced by the 
; pool name ('www' here) 
[webhostinghero] 

Enter the user name and the group that PHP-FPM will use to execute the PHP scripts:

; Unix user/group of processes 
; Note: The user is mandatory. If the group is not set, the default user's group 
;       will be used. 
; RPM: apache user chosen to provide access to the same directories as httpd 
user = webhostinghero 
; RPM: Keep a group allowed to write in log dir. 
group = webhostinghero

Change the name of the socket file:

listen = /var/run/php-fpm/webhostinghero.sock

The value of the parameters “listen.owner” and “listen.group” must remain the same:

listen.owner = apache 
listen.group = apache 
listen.mode = 0660

At the very end of the file, change the “session.save_path” setting:

php_value[session.save_path] = /home/webhostinghero/var/lib/php/session

Save the file. Quit the editor and create a symbolic link to the file in “sites-enabled”:

ln -s /etc/php-fpm.d/sites-available/webhostinghero.conf /etc/php-fpm.d/sites-enabled/webhostinghero.conf 

Restart the PHP-FPM service:

systemctl restart php-fpm

Then check that the new pool is active:

ps ax | grep php-fpm
13746 ?        Ss     0:00 php-fpm: master process (/etc/php-fpm.conf) 
13747 ?        S      0:00 php-fpm: pool webhostinghero 
13748 ?        S      0:00 php-fpm: pool webhostinghero 
13749 ?        S      0:00 php-fpm: pool webhostinghero 
13750 ?        S      0:00 php-fpm: pool webhostinghero 
13751 ?        S      0:00 php-fpm: pool webhostinghero 
13752 ?        S      0:00 php-fpm: pool www 
13753 ?        S      0:00 php-fpm: pool www 
13754 ?        S      0:00 php-fpm: pool www 
13755 ?        S      0:00 php-fpm: pool www 
13756 ?        S      0:00 php-fpm: pool www 
13760 pts/0    S+     0:00 grep --color=auto php-fpm

Virtual Host Configuration File

With the new PHP-FPM pool ready, create a configuration file for the virtual host:

vi /etc/httpd/conf.d/webhostinghero.org.conf

Insert the following configuration:

<VirtualHost *:80> 
       DocumentRoot "/home/webhostinghero/public_html" 
       ServerName webhostinghero.home.lan 
       ServerAlias www.webhostinghero.home.lan 

       <Directory "/home/webhostinghero/public_html"> 
               # allow from all 
               Order deny,allow 
               Options FollowSymLinks SymLinksIfOwnerMatch 
               Require all granted 
               AllowOverride All 
               php_admin_value open_basedir /home/webhostinghero 
       </Directory> 

       ErrorLog logs/webhostinghero.home.lan-error_log 
       LogLevel warn 
       TransferLog logs/webhostinghero.home.lan-access_log 
       CustomLog logs/webhostinghero.home.lan-request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" 

       SuexecUserGroup webhostinghero webhostinghero 

       <Proxy "unix:/var/run/php-fpm/webhostinghero.sock|fcgi://php-fpm"> 
               ProxySet disablereuse=off 
        </Proxy> 

   <FilesMatch \.php$> 
       SetHandler proxy:fcgi://php-fpm 
   </FilesMatch> 

</VirtualHost>
<VirtualHost *:443> 
       DocumentRoot "/home/webhostinghero/public_html" 
       ServerName webhostinghero.home.lan        
       ServerAlias www.webhostinghero.home.lan 

       <Directory "/home/webhostinghero/public_html"> 
               # allow from all 
               Order deny,allow 
               Options FollowSymLinks SymLinksIfOwnerMatch 
               Require all granted 
               AllowOverride All 
               php_admin_value open_basedir /home/webhostinghero 
       </Directory> 

       ErrorLog logs/webhostinghero.home.lan-ssl_error_log 
       LogLevel warn 
       TransferLog logs/webhostinghero.home.lan-ssl_access_log 
       CustomLog logs/webhostinghero.home.lan-ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" 

       SuexecUserGroup webhostinghero webhostinghero 

       <Proxy "unix:/var/run/php-fpm/webhostinghero.sock|fcgi://php-fpm"> 
           ProxySet disablereuse=off 
       </Proxy> 

       <FilesMatch \.php$> 
          SetHandler proxy:fcgi://php-fpm 
       </FilesMatch> 

   # SSLEngine on 
   # SSLCertificateFile /etc/pki/tls/webhostinghero.org/webhostinghero.org.pem 
   # SSLCertificateKeyFile /etc/pki/tls/webhostinghero.org/webhostinghero.org.key 
   # SSLCertificateChainFile /etc/pki/tls/webhostinghero.org/chain.pem 

</VirtualHost>

Save the file and exit the editor.

Note that this virtual host configuration will generate an SSL certificate error since a valid certificate is not configured.

Restart the Apache service:

systemctl restart httpd

Copy the “info.php” file created in step # 4 into the virtual host’s public directory:

cp /var/www/html/info.php /home/webhostinghero/public_html
chown -R webhostinghero:webhostinghero /home/webhostinghero

Now access “info.php” from your web browser. Make sure that FPM / FastCGI is now in charge of PHP processes:

apache virtualhost php-fpm

Scroll down to the “Environment” section and check “User” and “Home” variables for the user created for this virtual host:

centos php-fpm phpinfo environment

Thus, it will be impossible for PHP scripts to access anything outside of “/home/webhostinghero” and files created by PHP will belong to the user “webhostinghero.”

One Reply to “How to Install Apache, PHP 7, and PHP-FPM on CentOS 7”!

  • Thank you so much for this, I once had to convert a Nextcloud instance from regular PHP to PHP-FPM but it was relatively recent for apache I guess bc most help was for NGINX. I did it but I felt like it was still to slow so I scratch it and I sort of regretted it when I realized I had to start over then I setup the basic CentOS server and added my root to it and DuckDuck-went to “install httpd with php-fpm” and this was literally the first result!

    Everything went textbook. Now I hope I don’t screw it up when it’s time to get a certificate–if it is I’ll just cheat with HAProxy. :) Thanks!

Leave a Reply

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