*The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.*

Introduction

The Apache web server uses virtual hosts to manage multiple domains on a single instance. Similarly, PHP-FPM uses a daemon to manage multiple PHP versions on a single instance. Together, you can use Apache and PHP-FPM to host multiple PHP web-applications, each using a different version of PHP, all on the same server, and all at the same time. This is useful because different applications may require different versions of PHP, but some server stacks, like a regularly configured LAMP stack, can only manage one. Combining Apache with PHP-FPM is also a more cost-efficient solution than hosting each application on its own instance.

PHP-FPM also offers configuration options for stderr and stdout logging, emergency restarts, and adaptive process spawning, which is useful for heavy-loaded sites. In fact, using Apache with PHP-FPM is one of the best stacks for hosting PHP applications, especially when it comes to performance.

In fact, using Apache with PHP-FPM is one of the best stacks for hosting PHP applications, especially when it comes to performance. PHP-FPM not only allows you run to multiple PHP versions simultaneously, it also provides numerous extra features like adaptive process spawning, which is useful for heavy-loaded sites.

In this tutorial you will set up two PHP sites on a single instance. Each site will use its own domain, and each domain will deploy its own version of PHP. The first, <^>site1.your_domain<^>, will deploy PHP 7.2. The second, <^>site2.your_domain<^>, will deploy PHP 7.3.

Prerequisites

php illustration for: Prerequisites

Step 1 — Installing PHP Versions 7.2 and 7.3 with PHP-FPM

With the prerequisites completed, you will now install PHP versions 7.2 and 7.3, as well as PHP-FPM and several additional extensions. But to accomplish this, you will first need to add the Ondrej PHP repository to your system.

Execute the apt-get command to install software-properties-common:

				
					
sudo apt-get install software-properties-common -y

				
			

The software-properties-common package provides apt-add-repository command-line utility which you will use to add the ondrej/php PPA (Personal Package Archive) repository.

Now add the ondrej/php repository to your system. The ondrej/php PPA will have more up-to-date versions of PHP than the official Ubuntu repositories, and it will also allow you to install multiple versions of PHP in the same system:

				
					
sudo add-apt-repository ppa:ondrej/php

				
			

Update the repository:

				
					
sudo apt-get update -y

				
			

Next, install php7.2, php7.2-fpm, php7.2-mysql, libapache2-mod-php7.2, and libapache2-mod-fcgid with the following commands:

				
					
sudo apt-get install php7.2 php7.2-fpm php7.2-mysql libapache2-mod-php7.2 libapache2-mod-fcgid -y

				
			
  • php7.2 is a metapackage used to run PHP applications.
  • php7.2-fpm provides the Fast Process Manager interpreter that runs as a daemon and receives Fast/CGI requests.
  • php7.2-mysql connects PHP to the MySQL database.
  • libapache2-mod-php7.2 provides the PHP module for the Apache webserver.
  • libapache2-mod-fcgid contains a mod_fcgid that starts a number of CGI program instances to handle concurrent requests.

Now repeat the process for PHP version 7.3. Install php7.3, php7.3-fpm, php7.3-mysql, and libapache2-mod-php7.3.

				
					
sudo apt-get install php7.3 php7.3-fpm php7.3-mysql libapache2-mod-php7.3 -y

				
			

After installing both PHP versions, start the php7.2-fpm service:

				
					
sudo systemctl start php7.2-fpm

				
			

Next, verify the status of php7.2-fpm service:

				
					
sudo systemctl status php7.2-fpm

				
			

You'll see the following output:

				
					
[secondary_label Output]

● php7.2-fpm.service - The PHP 7.2 FastCGI Process Manager

     Loaded: loaded (/lib/systemd/system/php7.2-fpm.service; enabled; vendor preset: enabled)

     Active: &lt;^&gt;active&lt;^&gt; (running) since Fri 2020-06-05 11:25:07 UTC; 1min 38s ago

       Docs: man:php-fpm7.2(8)

   Main PID: 13703 (php-fpm7.2)

     Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"

      Tasks: 3 (limit: 2353)

     Memory: 6.2M

     CGroup: /system.slice/php7.2-fpm.service

             ├─13703 php-fpm: master process (/etc/php/7.2/fpm/php-fpm.conf)

             ├─13719 php-fpm: pool www

             └─13720 php-fpm: pool www



Jun 05 11:25:07 ubuntu systemd[1]: Starting The PHP 7.2 FastCGI Process Manager...

Jun 05 11:25:07 ubuntu systemd[1]: Started The PHP 7.2 FastCGI Process Manager.



				
			

Repeating this process, now start the php7.3-fpm service:

				
					
sudo systemctl start php7.3-fpm

				
			

Next, verify the status of php7.3-fpm service:

				
					
sudo systemctl status php7.3-fpm

				
			

You'll see the following output:

				
					
[secondary_label Output]

● php7.3-fpm.service - The PHP 7.3 FastCGI Process Manager

     Loaded: loaded (/lib/systemd/system/php7.3-fpm.service; enabled; vendor preset: enabled)

     Active: &lt;^&gt;active&lt;^&gt; (running) since Fri 2020-06-05 11:26:33 UTC; 56s ago

       Docs: man:php-fpm7.3(8)

    Process: 23470 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/7.3/fpm/pool.d/www.conf 73 (code=ex&gt;

   Main PID: 23452 (php-fpm7.3)

     Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"

      Tasks: 3 (limit: 2353)

     Memory: 7.1M

     CGroup: /system.slice/php7.3-fpm.service

             ├─23452 php-fpm: master process (/etc/php/7.3/fpm/php-fpm.conf)

             ├─23468 php-fpm: pool www

             └─23469 php-fpm: pool www



Jun 05 11:26:33 ubuntu systemd[1]: Starting The PHP 7.3 FastCGI Process Manager...

Jun 05 11:26:33 ubuntu systemd[1]: Started The PHP 7.3 FastCGI Process Manager.



				
			

Lastly, you must enable several modules so that your Apache2 service can work with multiple PHP versions:

				
					
sudo a2enmod actions fcgid alias proxy_fcgi

				
			
  • actions is used for executing CGI scripts based on media type or request method.
  • fcgid is a high performance alternative to mod_cgi that starts a sufficient number of instances of the CGI program to handle concurrent requests.
  • alias provides for the mapping of different parts of the host filesystem in the document tree, and for URL redirection.
  • proxy_fcgi allows Apache to forward requests to PHP-FPM.

Now restart the Apache service to apply your changes:

				
					
sudo systemctl restart apache2

				
			

At this point you have installed two PHP versions on your server. Next, you will create a directory structure for each website you want to deploy.

Step 2 — Creating Directory Structures for Both Websites

In this section, you will create a document root directory and an index page for each of your two websites.

First, create document root directories for both <^>site1.your_domain<^> and <^>site2.your_domain<^>:

				
					
sudo mkdir /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;

sudo mkdir /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;

				
			

By default, the Apache webserver runs as a <^>www-data<^> user and <^>www-data<^> group. To ensure that you have the correct ownership and permissions of your website root directories, execute the following commands:

				
					
sudo chown -R www-data:www-data /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;

sudo chown -R www-data:www-data /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;

sudo chmod -R 755 /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;

sudo chmod -R 755 /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;

				
			

Next you will create an info.php file inside each website root directory. This will display each website's PHP version information. Begin with <^>site1<^>:

				
					
sudo nano /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;/info.php

				
			

Add the following line:

				
					
[label /var/www/site1.your_domain/info.php]

&lt;?php phpinfo(); ?&gt;

				
			

Save and close the file. Now copy the info.php file you created to <^>site2<^>:

				
					
sudo cp /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;/info.php /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;/info.php

				
			

Your web server should now have the document root directories that each site requires to serve data to visitors. Next, you will configure your Apache web server to work with two different PHP versions.

Step 3 — Configuring Apache for Both Websites

In this section, you will create two virtual host configuration files. This will enable your two websites to work simultaneously with two different PHP versions.

In order for Apache to serve this content, it is necessary to create a virtual host file with the correct directives. Instead of modifying the default configuration file located at /etc/apache2/sites-available/000-default.conf, you'll create two new ones inside the directory /etc/apache2/sites-available/.

First create a new virtual host configuration file for the website <^>site1.your_domain<^>. Here you will direct Apache to render content using php7.2:

				
					
sudo nano /etc/apache2/sites-available/&lt;^&gt;site1.your_domain&lt;^&gt;.conf

				
			

Add the following content. Make sure the website directory path, server name, and PHP version match your setup:

				
					
[label /etc/apache2/sites-available/site1.your_domain.conf]



&lt;VirtualHost *:80&gt;

     ServerAdmin admin@&lt;^&gt;site1.your_domain&lt;^&gt;

     ServerName &lt;^&gt;site1.your_domain&lt;^&gt;

     DocumentRoot /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;

     DirectoryIndex info.php



     &lt;Directory /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;&gt;

        Options Indexes FollowSymLinks MultiViews

        AllowOverride All

        Order allow,deny

        allow from all

     &lt;/Directory&gt;



    &lt;FilesMatch \.php$&gt;

        # From the Apache version 2.4.10 and above, use the SetHandler to run PHP as a fastCGI process server

         SetHandler "proxy:unix:/run/php/&lt;^&gt;php7.2&lt;^&gt;-fpm.sock|fcgi://localhost"

    &lt;/FilesMatch&gt;



     ErrorLog ${APACHE_LOG_DIR}/&lt;^&gt;site1.your_domain&lt;^&gt;_error.log

     CustomLog ${APACHE_LOG_DIR}/&lt;^&gt;site1.your_domain&lt;^&gt;_access.log combined

&lt;/VirtualHost&gt;

				
			

In this file you updated the <^>DocumentRoot<^> to your new directory and <^>ServerAdmin<^> to an email that the <^>your_domain<^> site administrator can access. You’ve also updated <^>ServerName<^>, which establishes the base domain for this virtual host configuration, and you’ve added a <^>SetHandler<^> directive to run PHP as a fastCGI process server.

Save and close the file.

Next, create a new virtual host configuration file for the website <^>site2.your_domain<^>. You will specify this subdomain to deploy php7.3:

				
					
sudo nano /etc/apache2/sites-available/&lt;^&gt;site2.your_domain&lt;^&gt;.conf

				
			

Add the following content. Again, make sure the website directory path, server name, and PHP version match your unique information:

				
					
[label /etc/apache2/sites-available/site2.your_domain.conf]

&lt;VirtualHost *:80&gt;

     ServerAdmin admin@&lt;^&gt;site2.your_domain&lt;^&gt;

     ServerName &lt;^&gt;site2.your_domain&lt;^&gt;

     DocumentRoot /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;

     DirectoryIndex info.php



     &lt;Directory /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;&gt;

        Options Indexes FollowSymLinks MultiViews

        AllowOverride All

        Order allow,deny

        allow from all

     &lt;/Directory&gt;



    &lt;FilesMatch \.php$&gt;

        # 2.4.10+ can proxy to unix socket

         SetHandler "proxy:unix:/run/php/&lt;^&gt;php7.3&lt;^&gt;-fpm.sock|fcgi://localhost"

    &lt;/FilesMatch&gt;



     ErrorLog ${APACHE_LOG_DIR}/&lt;^&gt;site2.your_domain&lt;^&gt;_error.log

     CustomLog ${APACHE_LOG_DIR}/&lt;^&gt;site2.your_domain&lt;^&gt;_access.log combined

&lt;/VirtualHost&gt;

				
			

Save and close the file when you are finished. Then, check the Apache configuration file for any syntax errors:

				
					
sudo apachectl configtest

				
			

You'll see the following output:

				
					
[secondary_label Output]

Syntax OK

				
			

Next, enable both virtual host configuration files with the following commands:

				
					
sudo a2ensite &lt;^&gt;site1.your_domain&lt;^&gt;

sudo a2ensite &lt;^&gt;site2.your_domain&lt;^&gt;

				
			

Now disable the default site, since you won't need it.:

				
					
sudo a2dissite 000-default.conf

				
			

Finally, restart the Apache service to implement your changes:

				
					
sudo systemctl restart apache2

				
			

Now that you have configured Apache to serve each site, you will test them to make sure the proper PHP versions are running.

Step 4 — Testing Both Websites

At this point, you have configured two websites to run two different versions of PHP. Now test the results.

Open your web browser and visit both sites http://<^>site1.your_domain<^> and http://<^>site2.your_domain<^>. You will see two pages that look like this:

Note the titles. The first page indicates that <^>site1.your_domain<^> deployed PHP version 7.2. The second indicates that <^>site2.your_domain<^> deployed PHP version 7.3.

Now that you've tested your sites, remove the info.php files. Because they contain sensitive information about your server and are accessible to unauthorized users, they pose a security vulnerability. To remove both files, run the following commands:

				
					
sudo rm -rf /var/www/&lt;^&gt;site1.your_domain&lt;^&gt;/info.php

sudo rm -rf /var/www/&lt;^&gt;site2.your_domain&lt;^&gt;/info.php

				
			

You now have a single Ubuntu 20.04 server handling two websites with two different PHP versions. PHP-FPM, however, is not limited to this one application.

Conclusion

You have now combined virtual hosts and PHP-FPM to serve multiple websites and multiple versions of PHP on a single server. The only practical limit on the number of PHP sites and PHP versions that your Apache service can handle is the processing power of your instance.

From here you might consider exploring PHP-FPM's more advanced features, like its adaptive spawning process or how it can log sdtout and stderr Alternatively, you could now secure your websites. To accomplish this, you can follow our tutorial on how to secure your sites with free TLS/SSL certificates from Let's Encrypt.