How to Run Multiple PHP Versions on Ubuntu with PHP-FPM, Apache, and NGINX

Running multiple PHP versions on one Ubuntu server is a common requirement when you host several applications with different compatibility needs. One site may still require PHP 7.4, while another runs best on PHP 8.2 or 8.3. The cleanest way to handle this is to install multiple PHP versions side by side and use PHP-FPM pools to assign the correct version to each virtual host.

In this tutorial, you will learn how to run multiple PHP versions simultaneously on Ubuntu and how to configure both Apache and NGINX to use the right PHP-FPM socket per site.

Why use multiple PHP versions?

  • Host legacy and modern applications on the same VPS or dedicated server
  • Test upgrades safely before migrating production sites
  • Keep each vhost tied to the PHP version it supports
  • Use PHP-FPM for better process isolation and performance

Prerequisites

  • An Ubuntu server with sudo access
  • Apache or NGINX installed
  • Basic knowledge of virtual hosts or server blocks
  • DNS already pointing to your server

Step 1: Add the PHP repository

Ubuntu repositories may not include all PHP versions you need. The most common approach is to use the Ondřej Surý PHP PPA.

Update packages and install repository tools:

sudo apt update
sudo apt install -y software-properties-common ca-certificates lsb-release apt-transport-https

Add the PPA:

sudo add-apt-repository ppa:ondrej/php
sudo apt update

Step 2: Install multiple PHP versions with PHP-FPM

Install the versions and extensions you need. Example with PHP 7.4 and PHP 8.2:

sudo apt install -y php7.4 php7.4-fpm php7.4-cli php7.4-mysql php7.4-xml php7.4-mbstring php7.4-curl php7.4-zip
sudo apt install -y php8.2 php8.2-fpm php8.2-cli php8.2-mysql php8.2-xml php8.2-mbstring php8.2-curl php8.2-zip

Make sure both FPM services are enabled and running:

sudo systemctl enable php7.4-fpm php8.2-fpm
sudo systemctl start php7.4-fpm php8.2-fpm

You can verify active services with:

systemctl status php7.4-fpm
systemctl status php8.2-fpm

Step 3: Locate PHP-FPM sockets

Each PHP-FPM version usually exposes its own Unix socket. Typical paths are:

  • /run/php/php7.4-fpm.sock
  • /run/php/php8.2-fpm.sock

Check them with:

ls -lah /run/php/

These socket files are what Apache or NGINX will use to pass PHP requests to the correct PHP version.

How to configure Apache with multiple PHP versions

With Apache, the recommended setup is to use mod_proxy_fcgi together with PHP-FPM instead of mod_php. This allows each virtual host to target a different PHP-FPM socket.

Step 4A: Enable required Apache modules

sudo a2enmod proxy_fcgi setenvif rewrite headers
sudo systemctl restart apache2

If mod_php is enabled, disable it to avoid conflicts:

sudo a2dismod php7.4 php8.2 2>/dev/null || true
sudo systemctl restart apache2

Step 5A: Create Apache vhosts for different PHP versions

Example site using PHP 7.4:

/etc/apache2/sites-available/site1.conf

<VirtualHost *:80>
ServerName site1.example.com
DocumentRoot /var/www/site1/public_html

<Directory /var/www/site1/public_html>
AllowOverride All
Require all granted
</Directory>

<FilesMatch .php$>
SetHandler “proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost/”
</FilesMatch>

ErrorLog ${APACHE_LOG_DIR}/site1_error.log
CustomLog ${APACHE_LOG_DIR}/site1_access.log combined
</VirtualHost>

Example site using PHP 8.2:

/etc/apache2/sites-available/site2.conf

<VirtualHost *:80>
ServerName site2.example.com
DocumentRoot /var/www/site2/public_html

<Directory /var/www/site2/public_html>
AllowOverride All
Require all granted
</Directory>

<FilesMatch .php$>
SetHandler “proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost/”
</FilesMatch>

ErrorLog ${APACHE_LOG_DIR}/site2_error.log
CustomLog ${APACHE_LOG_DIR}/site2_access.log combined
</VirtualHost>

Enable the sites and reload Apache:

sudo a2ensite site1.conf site2.conf
sudo systemctl reload apache2

How to configure NGINX with multiple PHP versions

NGINX works especially well with PHP-FPM. Each server block can point to its own PHP socket using the fastcgi_pass directive.

Step 4B: Create NGINX server blocks for different PHP versions

Example site using PHP 7.4:

/etc/nginx/sites-available/site1

server {
listen 80;
server_name site1.example.com;
root /var/www/site1/public_html;
index index.php index.html;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ .php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}

location ~ /.ht {
deny all;
}
}

Example site using PHP 8.2:

/etc/nginx/sites-available/site2

server {
listen 80;
server_name site2.example.com;
root /var/www/site2/public_html;
index index.php index.html;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ .php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

location ~ /.ht {
deny all;
}
}

Enable the configs and reload NGINX:

sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/site2 /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Optional: Create separate PHP-FPM pools per site

Using the default pool per PHP version is enough for many servers, but for better isolation you can create a dedicated pool for each website. This is useful when you want different Unix users, resource limits, or logging per application.

Example pool for PHP 8.2:

/etc/php/8.2/fpm/pool.d/site2.conf

[site2]
user = www-data
group = www-data
listen = /run/php/site2-php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
pm.max_requests = 500
chdir = /

Then restart PHP-FPM:

sudo systemctl restart php8.2-fpm

After that, point the vhost to /run/php/site2-php8.2-fpm.sock instead of the default version socket.

Step 6: Test PHP version per vhost

Create a test file in each site root:

echo ‘<?php phpinfo(); ?>’ | sudo tee /var/www/site1/public_html/info.php
echo ‘<?php phpinfo(); ?>’ | sudo tee /var/www/site2/public_html/info.php

Visit each domain:

  • http://site1.example.com/info.php
  • http://site2.example.com/info.php

Confirm that each site loads the expected PHP version. Remove the file afterward for security reasons.

Common troubleshooting tips

  • 502 Bad Gateway in NGINX: the PHP-FPM service may be stopped or the socket path may be wrong
  • Apache downloads PHP files instead of executing them: PHP handler is not configured correctly
  • Permission denied on socket: verify socket owner, group, and web server user permissions
  • Wrong PHP version loaded: check that the vhost points to the intended FPM socket
  • Configuration errors: run apachectl configtest or nginx -t before reloading

Useful management commands

  • sudo update-alternatives –config php to change the default CLI PHP version
  • php -v to check the current CLI version
  • systemctl list-units | grep fpm to list installed PHP-FPM services
  • journalctl -u php8.2-fpm to inspect PHP-FPM logs

Note that changing the CLI version does not change the PHP version used by Apache or NGINX. Web requests are controlled by the configured PHP-FPM socket.

Best practices

  • Use supported PHP versions whenever possible
  • Isolate older applications and plan upgrades
  • Prefer dedicated pools for busy or sensitive sites
  • Monitor memory usage when running several PHP-FPM versions
  • Remove unused PHP modules to reduce attack surface
  • Secure all sites with HTTPS using Let’s Encrypt or another CA

Conclusion

Running multiple PHP versions on Ubuntu is straightforward when you use PHP-FPM. Install each required PHP version, confirm the FPM sockets, and then configure each Apache virtual host or NGINX server block to pass PHP requests to the correct socket. This gives you a flexible hosting setup for legacy and modern applications on the same VPS or dedicated server.

If you manage several client projects or maintain older software while deploying new apps, this approach is one of the most reliable ways to keep everything working side by side.

Be the first to comment

Leave a Reply

Your email address will not be published.


*