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

Posted on

This tutorial is also available for CentOS 7.

PHP is everywhere and is, without a doubt, the most used programming language on the Web. However, PHP is not recognized for its performance, but rather for its flexibility and ease of integration with Apache and Nginx.

That said, there are several things you can do to improve the performance of PHP. The first thing to do is to install PHP-FPM, which stands for PHP FastCGI Process Manager. PHP-FPM is used to manage PHP requests received from the Web server.

PHP-FPM shines, especially when it comes time to handle a high volume of competing queries. Therefore, for a website with little traffic, the use of PHP-FPM may not present a significant gain.

In this tutorial, we will see how to install and configure Apache and PHP-FPM on an Ubuntu 19.04 server.

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

At first, disable AppArmor:

service apparmor stop
update-rc.d -f apparmor remove 
apt-get remove apparmor apparmor-utils

Update the operating system and installed packages:

apt update -y && sudo apt upgrade -y && sudo apt autoremove -y

Then install Apache, PHP 7.2, and PHP-FPM:

apt-get -y install apache2 apache2-doc apache2-utils libapache2-mod-php php7.2 php7.2-common php7.2-gd php7.2-mysql php7.2-imap php7.2-cli php7.2-cgi libapache2-mod-fcgid apache2-suexec-pristine php-pear mcrypt imagemagick libruby libapache2-mod-python php7.2-curl php7.2-intl php7.2-pspell php7.2-recode php7.2-sqlite3 php7.2-tidy php7.2-xmlrpc php7.2-xsl memcached php-memcache php-imagick php-gettext php7.2-zip php7.2-mbstring php-soap php7.2-soap php7.2-fpm php7.2-opcache php-apcu

Step # 2: Apache Web Server Configuration

To prevent HTTPOXY attacks, create the “httpoxy.conf” file:

nano /etc/apache2/conf-available/httpoxy.conf

Then insert this configuration:

<IfModule mod_headers.c> 
   RequestHeader unset Proxy early 
</IfModule>

Save the file and exit the editor. Enable the HTTPOXY configuration file:

a2enconf httpoxy

Then activate the necessary Apache modules:

a2enmod suexec rewrite ssl actions include cgi dav_fs dav auth_digest headers proxy_fcgi alias

If the firewall is active, add a rule allowing access to ports 80 and 443:

ufw allow 'Apache Full'
ufw delete allow 'Apache'

Then enable and restart the apache2 service:

systemctl enable apache2
systemctl restart apache2

Check that the web server is responding:

ubuntu apache2 default page

While you are there, take the opportunity to check that PHP is functional. Create a file named “info.php” in “/var/www/html”:

nano /var/wwww/html/info.php

Copy the following content to the file:

<?php phpinfo(); ?>

Save the file and access it from your web browser:

ubuntu phpinfo

As you can see, PHP is active; however, it is not handled by PHP-FPM but rather by the Apache module.

Step # 3: Enabling PHP-FPM

To make PHP-FPM the default PHP handler, type this command:

a2enconf php7.2-fpm

Enable and start the PHP-FPM daemon:

systemctl enable php7.2-fpm
systemctl start php7.2-fpm

Reload the Apache configuration:

systemctl reload apache2

Step # 4: Configure PHP-FPM for the default website

When you install Apache, the default Web site files are in “/var/www/html.” The Apache server uses the “www-data” user account to access these files.

Make sure the permissions on the folder are correct:

chown -R www-data.www-data /var/www/html

Then edit the default virtual host configuration file:

nano /etc/apache2/sites-enabled/000-default.conf

Insert these lines before the closing tag “</ VirtualHost>”:

[...]

<Directory /var/www/html>
        AllowOverride All
</Directory>
<IfModule proxy_fcgi_module> 
   # Enable http authorization headers 
   <IfModule setenvif_module> 
   SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 
   </IfModule> 
   <FilesMatch ".+\.ph(ar|p|tml)$"> 
       SetHandler "proxy:unix:/run/php/php7.2-fpm.sock|fcgi://localhost" 
   </FilesMatch> 
   <FilesMatch ".+\.phps$"> 
       # Deny access to raw php sources by default 
       # To re-enable it's recommended to enable access to the files 
       # only in specific virtual host or directory 
       Require all denied 
   </FilesMatch> 
   # Deny access to files without filename (e.g. '.php') 
   <FilesMatch "^\.ph(ar|p|ps|tml)$"> 
       Require all denied 
   </FilesMatch> 
</IfModule>

</VirtualHost>
</IfModule>

Reload the Apache configuration:

systemctl reload apache2

Refresh the “info.php” page and check that PHP-FPM is active:

ubuntu phpinfo php-fpm

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

In many cases, a single web server can host multiple sites that must be isolated from each other at the PHP layer. To prevent PHP scripts from one site accessing files from another site, you must use distinct PHP-FPM pools.

For this tutorial, we will create a virtual host for the “webhostinghero.home.lan” domain. Start by creating the user account:

adduser webhostinghero

Then create the directory that will contain the files of the website:

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

Then copy the PHP-FPM configuration file from the default site and edit it:

cp /etc/php/7.2/fpm/pool.d/www.conf /etc/php/7.2/fpm/pool.d/webhostinghero.home.lan.conf
nano /etc/php/7.2/fpm/pool.d/webhostinghero.home.lan.conf

Make the changes identified in red:

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

; Per pool prefix 
; It only applies on the following directives: 
; - 'access.log' 
; - 'slowlog' 
; - 'listen' (unixsocket) 
; - 'chroot' 
; - 'chdir' 
; - 'php_values' 
; - 'php_admin_values' 
; When not set, the global prefix (or /usr) applies instead. 
; Note: This directive can also be relative to the global prefix. 
; Default Value: none 
;prefix = /path/to/pools/$pool 

; Unix user/group of processes 
; Note: The user is mandatory. If the group is not set, the default user's group 
;       will be used. 
user = webhostinghero 
group = webhostinghero 

; The address on which to accept FastCGI requests. 
; Valid syntaxes are: 
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on 
;                            a specific port; 
;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on 
;                            a specific port; 
;   'port'                 - to listen on a TCP socket to all addresses 
;                            (IPv6 and IPv4-mapped) on a specific port; 
;   '/path/to/unix/socket' - to listen on a unix socket. 
; Note: This value is mandatory. 
listen = /run/php/php7.2-fpm-webhostinghero.sock 

php_admin_value[open_basedir] = /home/webhostinghero

; Set listen(2) backlog. 
; Default Value: 511 (-1 on FreeBSD and OpenBSD) 
;listen.backlog = 511

Save the configuration and restart the PHP-FPM service:

systemctl restart php7.2-fpm

You can then verify that the new PHP-FPM pool is active:

root@ubuntu-server:/etc/php/7.2/fpm# ps ax | grep fpm             
30000 ?        Ss     0:00 php-fpm: master process (/etc/php/7.2/fpm/php-fpm.conf) 
30020 ?        S      0:00 php-fpm: pool webhostinghero 
30021 ?        S      0:00 php-fpm: pool webhostinghero 
30022 ?        S      0:00 php-fpm: pool www 
30023 ?        S      0:00 php-fpm: pool www 
30028 pts/0    S+     0:00 grep --color=auto fpm

Now copy the default virtual host configuration file and edit it:

cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/webhostinghero.home.lan.conf
nano /etc/apache2/sites-available/webhostinghero.home.lan.conf

Edit the file as follows:

<VirtualHost *:80> 
       # The ServerName directive sets the request scheme, hostname and port that 
       # the server uses to identify itself. This is used when creating 
       # redirection URLs. In the context of virtual hosts, the ServerName 
       # specifies what hostname must appear in the request's Host: header to 
       # match this virtual host. For the default virtual host (this file) this 
       # value is not decisive as it is used as a last resort host regardless. 
       # However, you must set it for any further virtual host explicitly. 
       ServerName webhostinghero.home.lan

       ServerAdmin webmaster@localhost 
       DocumentRoot /home/webhostinghero/public_html 

       # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 
       # error, crit, alert, emerg. 
       # It is also possible to configure the loglevel for particular 
       # modules, e.g. 
       #LogLevel info ssl:warn 

       ErrorLog ${APACHE_LOG_DIR}/webhostinghero.home.lan-error.log 
       CustomLog ${APACHE_LOG_DIR}/webhostinghero.home.lan-access.log combined 

       <Directory /home/webhostinghero/public_html> 
               AllowOverride All
               Require all granted
       </Directory> 
       <IfModule proxy_fcgi_module>  
          # Enable http authorization headers  
          <IfModule setenvif_module>  
          SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1  
          </IfModule>  
          <FilesMatch ".+\.ph(ar|p|tml)$">  
              SetHandler "proxy:unix:/run/php/php7.2-fpm-webhostinghero.sock|fcgi://localhost"  
          </FilesMatch>  
          <FilesMatch ".+\.phps$">  
              # Deny access to raw php sources by default  
              # To re-enable it's recommended to enable access to the files  
              # only in specific virtual host or directory  
              Require all denied  
          </FilesMatch>  
          # Deny access to files without filename (e.g. '.php')  
          <FilesMatch "^\.ph(ar|p|ps|tml)$">  
              Require all denied  
          </FilesMatch>  
       </IfModule> 

       # For most configuration files from conf-available/, which are 
       # enabled or disabled at a global level, it is possible to 
       # include a line for only one particular virtual host. For example the 
       # following line enables the CGI configuration for this host only 
       # after it has been globally disabled with "a2disconf". 
       #Include conf-available/serve-cgi-bin.conf 
</VirtualHost>

Save the configuration and exit the editor. Then activate the new virtual host:

ln -s /etc/apache2/sites-available/webhostinghero.home.lan.conf /etc/apache2/sites-enabled/webhostinghero.home.lan.conf

Restart the apache2 service:

systemctl reload apache2

Copy the info.php file created previously:

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

Go now to “info.php” with your web browser. Check that PHP-FPM is active:

ubuntu php-fpm virtual host 

Scroll to the “Environment” section and verify that PHP-FPM uses the account specified in the configuration:

ubuntu php-fpm environment user

Also, check the value of the “open_basedir” parameter to make sure PHP scripts are restricted to the user’s home directory:

ubuntu php fpm open_basedir

If you need to change the PHP configuration for a virtual host, know the PHP settings applied in the Apache configuration files do not affect. You must always modify the PHP-FPM pool configuration file.

2 Comments on “How to Install Apache, PHP 7, and PHP-FPM on Ubuntu”!

Leave a Reply

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