Multiple PHP Versions Configuration: Complete Production Guide

Introduction

Running multiple PHP versions simultaneously on a single server is a common requirement in modern web hosting environments. Different applications often require different PHP versions - legacy applications may need PHP 7.4, while newer projects might require PHP 8.1 or 8.2. This guide provides comprehensive instructions for configuring multiple PHP versions side-by-side, allowing you to serve different applications with their optimal PHP version.

What You'll Learn

  • Installing multiple PHP versions on Ubuntu/Debian and CentOS/Rocky Linux
  • Configuring PHP-FPM pools for different PHP versions
  • Switching between PHP versions per virtual host in Nginx
  • Switching between PHP versions per virtual host in Apache
  • Managing PHP configurations across versions
  • Command-line PHP version switching
  • Performance optimization for multiple PHP versions
  • Troubleshooting common issues

Use Cases

  • Hosting multiple client websites with different PHP requirements
  • Migrating applications between PHP versions gradually
  • Testing applications against newer PHP versions before production upgrade
  • Supporting both legacy and modern applications on the same server
  • Development environments requiring multiple PHP versions

Prerequisites

  • Ubuntu 20.04/22.04, Debian 10/11, CentOS 8, or Rocky Linux 8/9
  • Root or sudo access
  • Web server installed (Nginx or Apache)
  • At least 2GB RAM (4GB+ recommended for production)
  • Basic understanding of PHP and web server configuration

Installation

Ubuntu/Debian: Installing Multiple PHP Versions

Step 1: Add Ondřej Surý's PHP Repository

# Install software-properties-common
sudo apt install -y software-properties-common

# Add Ondřej's PHP repository
sudo add-apt-repository ppa:ondrej/php -y

# Update package list
sudo apt update

Step 2: Install Multiple PHP Versions

# Install PHP 7.4 and PHP 8.1 and PHP 8.2 with common extensions
sudo apt install -y \
    php7.4 php7.4-fpm php7.4-cli php7.4-common php7.4-mysql php7.4-xml \
    php7.4-curl php7.4-gd php7.4-mbstring php7.4-zip php7.4-bcmath \
    php7.4-json php7.4-opcache php7.4-readline \
    php8.1 php8.1-fpm php8.1-cli php8.1-common php8.1-mysql php8.1-xml \
    php8.1-curl php8.1-gd php8.1-mbstring php8.1-zip php8.1-bcmath \
    php8.1-opcache php8.1-readline \
    php8.2 php8.2-fpm php8.2-cli php8.2-common php8.2-mysql php8.2-xml \
    php8.2-curl php8.2-gd php8.2-mbstring php8.2-zip php8.2-bcmath \
    php8.2-opcache php8.2-readline

# Enable all PHP-FPM services
sudo systemctl enable php7.4-fpm
sudo systemctl enable php8.1-fpm
sudo systemctl enable php8.2-fpm

# Start all PHP-FPM services
sudo systemctl start php7.4-fpm
sudo systemctl start php8.1-fpm
sudo systemctl start php8.2-fpm

# Verify all services are running
sudo systemctl status php7.4-fpm
sudo systemctl status php8.1-fpm
sudo systemctl status php8.2-fpm

Step 3: Verify Installations

# Check installed PHP versions
php7.4 -v
php8.1 -v
php8.2 -v

# Check socket locations
ls -la /var/run/php/
# You should see php7.4-fpm.sock, php8.1-fpm.sock, php8.2-fpm.sock

# Verify PHP-FPM is listening
sudo ss -pl | grep php

CentOS/Rocky Linux: Installing Multiple PHP Versions

Step 1: Install Remi Repository

# Install EPEL repository
sudo dnf install -y epel-release

# Install Remi repository
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm

# List available PHP versions
sudo dnf module list php

Step 2: Install Multiple PHP Versions

# Install PHP 7.4
sudo dnf module reset php -y
sudo dnf module enable php:remi-7.4 -y
sudo dnf install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-opcache php-cli php-zip php-curl

# Rename PHP 7.4 binaries
sudo cp /usr/bin/php /usr/bin/php7.4
sudo cp /usr/sbin/php-fpm /usr/sbin/php7.4-fpm

# Install PHP 8.1
sudo dnf module reset php -y
sudo dnf module enable php:remi-8.1 -y
sudo dnf install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring php-opcache php-cli php-zip php-curl

# Rename PHP 8.1 binaries
sudo cp /usr/bin/php /usr/bin/php8.1
sudo cp /usr/sbin/php-fpm /usr/sbin/php8.1-fpm

# Note: CentOS/Rocky typically uses alternatives system for PHP version management
sudo alternatives --config php

Note: Managing multiple PHP versions on CentOS/Rocky is more complex. Consider using containers or dedicated servers for simpler management. This guide focuses primarily on Ubuntu/Debian for multiple PHP versions.

Configuration

Configure PHP-FPM Pools for Each Version

Each PHP version needs its own socket or port configuration.

PHP 7.4 Pool Configuration

# Edit PHP 7.4 pool configuration
sudo vim /etc/php/7.4/fpm/pool.d/www.conf

# Key settings:
[www]
user = www-data
group = www-data
listen = /var/run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

# Process manager settings
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

PHP 8.1 Pool Configuration

# Edit PHP 8.1 pool configuration
sudo vim /etc/php/8.1/fpm/pool.d/www.conf

# Key settings:
[www]
user = www-data
group = www-data
listen = /var/run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

# Process manager settings
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

PHP 8.2 Pool Configuration

# Edit PHP 8.2 pool configuration
sudo vim /etc/php/8.2/fpm/pool.d/www.conf

# Same configuration as above
# Key settings:
[www]
user = www-data
group = www-data
listen = /var/run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

# Process manager settings
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

Restart All PHP-FPM Services

sudo systemctl restart php7.4-fpm
sudo systemctl restart php8.1-fpm
sudo systemctl restart php8.2-fpm

Nginx Configuration for Multiple PHP Versions

Configure different websites to use different PHP versions.

Site Using PHP 7.4

# Create configuration for legacy site
sudo bash -c 'cat > /etc/nginx/sites-available/legacy-site.com <<EOF
server {
    listen 80;
    server_name legacy-site.com www.legacy-site.com;
    root /var/www/legacy-site.com/html;
    index index.php index.html;

    access_log /var/log/nginx/legacy-site-access.log;
    error_log /var/log/nginx/legacy-site-error.log;

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

    # PHP 7.4 processing
    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Add header to show PHP version (optional, for testing)
    add_header X-PHP-Version "7.4" always;
}
EOF'

# Enable site
sudo ln -s /etc/nginx/sites-available/legacy-site.com /etc/nginx/sites-enabled/

Site Using PHP 8.1

# Create configuration for modern site
sudo bash -c 'cat > /etc/nginx/sites-available/modern-site.com <<EOF
server {
    listen 80;
    server_name modern-site.com www.modern-site.com;
    root /var/www/modern-site.com/html;
    index index.php index.html;

    access_log /var/log/nginx/modern-site-access.log;
    error_log /var/log/nginx/modern-site-error.log;

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

    # PHP 8.1 processing
    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Add header to show PHP version (optional, for testing)
    add_header X-PHP-Version "8.1" always;
}
EOF'

# Enable site
sudo ln -s /etc/nginx/sites-available/modern-site.com /etc/nginx/sites-enabled/

Site Using PHP 8.2

# Create configuration for newest site
sudo bash -c 'cat > /etc/nginx/sites-available/new-site.com <<EOF
server {
    listen 80;
    server_name new-site.com www.new-site.com;
    root /var/www/new-site.com/html;
    index index.php index.html;

    access_log /var/log/nginx/new-site-access.log;
    error_log /var/log/nginx/new-site-error.log;

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

    # PHP 8.2 processing
    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Add header to show PHP version (optional, for testing)
    add_header X-PHP-Version "8.2" always;
}
EOF'

# Enable site
sudo ln -s /etc/nginx/sites-available/new-site.com /etc/nginx/sites-enabled/

Test and Reload Nginx

# Test configuration
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

Apache Configuration for Multiple PHP Versions

If you're using Apache instead of Nginx:

Enable Required Apache Modules

# Enable proxy modules
sudo a2enmod proxy_fcgi setenvif rewrite

# Disable mod_php (if installed)
sudo a2dismod php7.4 php8.1 php8.2

# Restart Apache
sudo systemctl restart apache2

Site Using PHP 7.4 (Apache)

# Create virtual host
sudo bash -c 'cat > /etc/apache2/sites-available/legacy-site.com.conf <<EOF
<VirtualHost *:80>
    ServerName legacy-site.com
    ServerAlias www.legacy-site.com
    DocumentRoot /var/www/legacy-site.com/html

    <Directory /var/www/legacy-site.com/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # PHP 7.4 via PHP-FPM
    <FilesMatch \.php\$>
        SetHandler "proxy:unix:/var/run/php/php7.4-fpm.sock|fcgi://localhost"
    </FilesMatch>

    ErrorLog \${APACHE_LOG_DIR}/legacy-site-error.log
    CustomLog \${APACHE_LOG_DIR}/legacy-site-access.log combined
</VirtualHost>
EOF'

# Enable site
sudo a2ensite legacy-site.com.conf

Site Using PHP 8.1 (Apache)

# Create virtual host
sudo bash -c 'cat > /etc/apache2/sites-available/modern-site.com.conf <<EOF
<VirtualHost *:80>
    ServerName modern-site.com
    ServerAlias www.modern-site.com
    DocumentRoot /var/www/modern-site.com/html

    <Directory /var/www/modern-site.com/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # PHP 8.1 via PHP-FPM
    <FilesMatch \.php\$>
        SetHandler "proxy:unix:/var/run/php/php8.1-fpm.sock|fcgi://localhost"
    </FilesMatch>

    ErrorLog \${APACHE_LOG_DIR}/modern-site-error.log
    CustomLog \${APACHE_LOG_DIR}/modern-site-access.log combined
</VirtualHost>
EOF'

# Enable site
sudo a2ensite modern-site.com.conf

Reload Apache

# Test configuration
sudo apache2ctl configtest

# Reload Apache
sudo systemctl reload apache2

Command Line PHP Version Switching

Switch the default PHP CLI version using update-alternatives:

# View available PHP versions
sudo update-alternatives --display php

# Set PHP 7.4 as default
sudo update-alternatives --set php /usr/bin/php7.4

# Set PHP 8.1 as default
sudo update-alternatives --set php /usr/bin/php8.1

# Set PHP 8.2 as default
sudo update-alternatives --set php /usr/bin/php8.2

# Interactive selection
sudo update-alternatives --config php

# Verify current version
php -v

Deployment

Test PHP Versions

Create test files for each site to verify PHP versions:

# Create test file for PHP 7.4 site
sudo bash -c 'cat > /var/www/legacy-site.com/html/phpinfo.php <<EOF
<?php
echo "<h1>PHP Version Info</h1>";
echo "PHP Version: " . phpversion() . "<br>";
echo "Server API: " . php_sapi_name() . "<br>";
phpinfo();
?>
EOF'

# Create test file for PHP 8.1 site
sudo bash -c 'cat > /var/www/modern-site.com/html/phpinfo.php <<EOF
<?php
echo "<h1>PHP Version Info</h1>";
echo "PHP Version: " . phpversion() . "<br>";
echo "Server API: " . php_sapi_name() . "<br>";
phpinfo();
?>
EOF'

# Create test file for PHP 8.2 site
sudo bash -c 'cat > /var/www/new-site.com/html/phpinfo.php <<EOF
<?php
echo "<h1>PHP Version Info</h1>";
echo "PHP Version: " . phpversion() . "<br>";
echo "Server API: " . php_sapi_name() . "<br>";
phpinfo();
?>
EOF'

Access these files in your browser:

  • http://legacy-site.com/phpinfo.php (should show PHP 7.4)
  • http://modern-site.com/phpinfo.php (should show PHP 8.1)
  • http://new-site.com/phpinfo.php (should show PHP 8.2)

Important: Delete these test files after verification for security:

sudo rm /var/www/*/html/phpinfo.php

Migrating Applications Between PHP Versions

When migrating an application to a newer PHP version:

Step 1: Create Test Environment

# Copy application to test directory
sudo cp -r /var/www/production-site.com /var/www/test-site.com

# Create test virtual host with new PHP version
# Point to new PHP-FPM socket

Step 2: Check Compatibility

# Run PHP compatibility checker
cd /var/www/test-site.com
composer require --dev phpcompatibility/php-compatibility

# Check for PHP 8.1 compatibility
vendor/bin/phpcs --standard=PHPCompatibility --runtime-set testVersion 8.1 /path/to/code

Step 3: Fix Deprecated Code

Common issues when upgrading:

  • PHP 8.0+: Named arguments, match expressions
  • PHP 8.1: Enums, readonly properties, fibers
  • Deprecated functions and features

Step 4: Test Thoroughly

# Run application test suite
vendor/bin/phpunit

# Manual testing
# Browse site thoroughly

Step 5: Switch Production

# Update production virtual host to use new PHP version
sudo vim /etc/nginx/sites-available/production-site.com

# Change from:
# fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
# To:
# fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

# Reload web server
sudo systemctl reload nginx

Monitoring

Monitor All PHP-FPM Versions

# Check status of all PHP-FPM services
sudo systemctl status php7.4-fpm php8.1-fpm php8.2-fpm

# Monitor active processes
ps aux | grep php-fpm

# Check memory usage per version
ps aux | grep php7.4-fpm | awk '{sum+=$6} END {print "PHP 7.4 Memory: " sum/1024 " MB"}'
ps aux | grep php8.1-fpm | awk '{sum+=$6} END {print "PHP 8.1 Memory: " sum/1024 " MB"}'
ps aux | grep php8.2-fpm | awk '{sum+=$6} END {print "PHP 8.2 Memory: " sum/1024 " MB"}'

# Monitor logs
sudo tail -f /var/log/php7.4-fpm.log
sudo tail -f /var/log/php8.1-fpm.log
sudo tail -f /var/log/php8.2-fpm.log

Monitoring Script

sudo bash -c 'cat > /usr/local/bin/php-versions-monitor.sh <<'EOF'
#!/bin/bash

echo "======================================"
echo "  PHP Versions Monitoring Report"
echo "  $(date)"
echo "======================================"
echo ""

echo "=== PHP-FPM Services Status ==="
for version in 7.4 8.1 8.2; do
    if systemctl is-active --quiet php${version}-fpm; then
        echo "PHP ${version}-FPM: RUNNING"
        processes=$(ps aux | grep php${version}-fpm | grep -v grep | wc -l)
        echo "  Active processes: $processes"
    else
        echo "PHP ${version}-FPM: STOPPED"
    fi
done
echo ""

echo "=== Memory Usage ==="
for version in 7.4 8.1 8.2; do
    mem=$(ps aux | grep php${version}-fpm | grep -v grep | awk '{sum+=$6} END {print sum/1024}')
    if [ ! -z "$mem" ]; then
        printf "PHP %s Memory: %.2f MB\n" "$version" "$mem"
    fi
done
echo ""

echo "=== Socket Status ==="
ls -lah /var/run/php/ | grep sock
echo ""

echo "======================================"
EOF'

sudo chmod +x /usr/local/bin/php-versions-monitor.sh

# Run monitoring script
sudo /usr/local/bin/php-versions-monitor.sh

Troubleshooting

PHP Version Not Working

Issue: Website showing wrong PHP version or not processing PHP

Solutions:

  1. Check PHP-FPM service is running:
sudo systemctl status php7.4-fpm
sudo systemctl start php7.4-fpm
  1. Verify socket exists:
ls -la /var/run/php/php7.4-fpm.sock
  1. Check Nginx/Apache configuration:
# Nginx
sudo nginx -t
grep -r "php7.4-fpm.sock" /etc/nginx/sites-enabled/

# Apache
sudo apache2ctl configtest
grep -r "php7.4-fpm.sock" /etc/apache2/sites-enabled/
  1. Check socket permissions:
sudo chmod 666 /var/run/php/php7.4-fpm.sock

502 Bad Gateway Error

Issue: Nginx returns 502 error when accessing PHP pages

Solutions:

  1. Check PHP-FPM is running:
sudo systemctl restart php8.1-fpm
sudo systemctl status php8.1-fpm
  1. Check PHP-FPM error log:
sudo tail -50 /var/log/php8.1-fpm.log
  1. Verify socket path matches in both configs:
# Check PHP-FPM pool config
grep "listen = " /etc/php/8.1/fpm/pool.d/www.conf

# Check Nginx config
grep "fastcgi_pass" /etc/nginx/sites-enabled/your-site.com
  1. Increase PHP-FPM processes:
# Edit pool configuration
sudo vim /etc/php/8.1/fpm/pool.d/www.conf

# Increase max_children
pm.max_children = 50

sudo systemctl restart php8.1-fpm

Memory Issues with Multiple PHP Versions

Issue: Server running out of memory with multiple PHP-FPM versions

Solutions:

  1. Reduce processes per pool:
# Edit each pool configuration
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
  1. Use ondemand process manager:
pm = ondemand
pm.max_children = 15
pm.process_idle_timeout = 10s
  1. Disable unused PHP versions:
# Stop and disable PHP version not in use
sudo systemctl stop php7.4-fpm
sudo systemctl disable php7.4-fpm

Composer Using Wrong PHP Version

Issue: Composer uses wrong PHP version

Solutions:

  1. Specify PHP binary explicitly:
php8.1 /usr/local/bin/composer install
  1. Use update-alternatives:
sudo update-alternatives --set php /usr/bin/php8.1
composer install
  1. Set PHP version in composer.json:
{
    "config": {
        "platform": {
            "php": "8.1.0"
        }
    }
}

Extension Not Available in Specific PHP Version

Issue: Extension works in one PHP version but not another

Solution:

# Check available extensions for each version
php7.4 -m
php8.1 -m
php8.2 -m

# Install missing extension
sudo apt install php8.1-extension-name

# Restart PHP-FPM
sudo systemctl restart php8.1-fpm

Security Best Practices

Per-Site User Isolation

Configure different pools with different users:

# Create dedicated user for site
sudo useradd -r -s /bin/false site1user

# Create dedicated pool
sudo bash -c 'cat > /etc/php/8.1/fpm/pool.d/site1.conf <<EOF
[site1]
user = site1user
group = site1user
listen = /var/run/php/php8.1-site1-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5

php_admin_value[open_basedir] = /var/www/site1:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
EOF'

# Set ownership
sudo chown -R site1user:site1user /var/www/site1

# Restart PHP-FPM
sudo systemctl restart php8.1-fpm

Disable Dangerous Functions

# Edit php.ini for each version
sudo vim /etc/php/8.1/fpm/php.ini

# Add:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

Update Regularly

# Update all PHP versions
sudo apt update
sudo apt upgrade php* -y

# Restart all PHP-FPM services
sudo systemctl restart php7.4-fpm php8.1-fpm php8.2-fpm

Performance Optimization

OPcache Configuration

Configure OPcache for each PHP version:

# Edit OPcache settings
sudo vim /etc/php/8.1/mods-available/opcache.ini

# Recommended settings:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=0

Resource Allocation Strategy

Allocate resources based on usage:

# High-traffic site (PHP 8.1)
pm.max_children = 50
pm.start_servers = 10

# Low-traffic legacy site (PHP 7.4)
pm.max_children = 10
pm.start_servers = 3

# Staging site (PHP 8.2)
pm = ondemand
pm.max_children = 5

Conclusion

You've successfully configured multiple PHP versions on your server, enabling you to run legacy and modern applications side-by-side. This setup provides flexibility, easier migrations, and better resource management.

Key Takeaways

  • Multiple PHP versions can coexist using separate PHP-FPM pools
  • Each site can use its own PHP version via different sockets
  • Command-line PHP version can be switched using update-alternatives
  • Proper resource allocation prevents memory issues
  • Per-site user isolation improves security

Best Practices

  1. Monitor Resource Usage: Keep track of memory and CPU for each PHP version
  2. Plan Migration Path: Gradually migrate applications to newer PHP versions
  3. Test Thoroughly: Always test in staging before production changes
  4. Keep Updated: Regularly update all PHP versions for security
  5. Document Configuration: Maintain documentation of which sites use which PHP version

Next Steps

  1. Set up automated monitoring for all PHP-FPM instances
  2. Create migration checklist for PHP version upgrades
  3. Implement automated testing for PHP compatibility
  4. Configure centralized logging
  5. Plan end-of-life strategy for older PHP versions

Running multiple PHP versions provides the flexibility needed in modern hosting environments while maintaining compatibility with legacy applications.

Happy deploying!