Running multiple PHP versions on the same server or development machine is never straightforward. One distro upgrade can break packages and turn your environment into a mess. For example, Ubuntu 20.04 ships with PHP 7.4, 22.04 comes with PHP 8.1, and 24.04 will use PHP 8.3. But what if you have projects that require both old and new PHP versions at the same time? That’s where PHPenv comes in. It’s an excellent tool for local development—and even for UAT servers.
To demonstrate how to use different PHP versions side by side, I’ll first install WordPress on Ubuntu 20.04 using Ansible. After that, I’ll set up PHPenv and switch to PHP 8.2.5 using pfm. The first part focuses on WordPress with Ansible, but if you want to skip straight to the PHPenv setup, feel free to jump ahead.
Install WordPress with Ansible
As a “lazy” sysadmin, I’m not a fan of repetitive manual work—so I’ll use Ansible to handle the installation. With just a few simple configurations, I’ll have WordPress up and running with FPM, Apache, and MySQL—all set automatically.
Install Ansible on Ubuntu 20.04
sudo apt update
sudo apt install software-properties-common -y
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible -yAnsible needs to know which servers to manage. Create an inventory file
mkdir ~/ansible
cd ~/ansible
vim inventory.iniEverything happens on the same host. Adding only localhost to inventory.ini
[wordpress]
127.0.0.1 ansible_connection=localTest Ansible
ansible -i inventory.ini wordpress -m pingYou should get
127.0.0.1 | SUCCESS => {
"changed": false,
"ping": "pong"
}Clone the DigitalOcean Playbooks Repo
cd ~
git clone https://github.com/do-community/ansible-playbooks.git
cd ansible-playbookscd wordpress-lamp_ubuntu1804, you should see:
inventory
playbook.yml
vars/default.yml
templates/
Configure Inventory. Paste this
[wordpress]
127.0.0.1 ansible_connection=localEdit the variables file vars/default.yml
---
#System Settings
php_modules: [ 'php-curl', 'php-gd', 'php-mbstring', 'php-xml', 'php-xmlrpc', 'php-soap', 'php-intl', 'php-zip' ]
#MySQL Settings
mysql_root_password: StrongRootPass123
mysql_db: wordpress
mysql_user: wpuser
mysql_password: StrongWpPass123
http_host: localhost
http_conf: wordpress.conf
http_port: "80"
Run the Playbook
ansible-playbook -i inventory playbook.ymlAfter ansible finish it work, follow wordpress installation from the browser. Next we will setup fpm
sudo apt install php7.4-fpm -y
sudo systemctl enable php7.4-fpm
sudo systemctl start php7.4-fpmEnable Required Apache Modules
sudo a2enmod proxy_fcgi setenvif
sudo a2enmod rewriteInside /etc/apache2/sites-available/wordpress.conf at the end of VirtualHost block add
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost/"
</FilesMatch>Disable mod_php
sudo a2dismod php7.4
sudo systemctl restart apache2Verify It’s Using FPM. Create a test file: /var/www/wordpress/info.php and add, without forget to delete it later
<?php phpinfo(); ?>Visit http://YOUR_PUBLIC_IP/info.php. We are expecting FPM/FastCGI in ServerApi.
Till now We have wordpress with old php version and FPM. Let’s install phpenv. With it we will upgrade to php 8.2.5 again using FPM.
Install phpenv on Ubuntu
clone the repo
git clone https://github.com/phpenv/phpenv.git ~/.phpenvadd phpenv to PATH
echo 'export PATH="$HOME/.phpenv/bin:$PATH"' >> ~/.bashrcinitialize phpenv in your shell every time Bash starts
echo 'eval "$(phpenv init -)"' >> ~/.bashrcexit server and enter again. We need utility for building versions of PHP to use them side by side with each other. BTW if you need to install additional plugins like composer, check this: https://github.com/ngyuki/phpenv-composer
git clone https://github.com/php-build/php-build $(phpenv root)/plugins/php-buildwe will need some additional packages
sudo apt install pkg-config libxml2-dev libsqlite3-dev zlib1g-dev libbz2-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libonig-dev libreadline-dev libtidy-dev libxslt1-dev libzip-dev librabbitmq-dev libsodium-dev libpq-dev libxml2-dev libxslt1-dev default-mysql-client default-libmysqlclient-dev build-essential autoconf bison m4 re2cbuild php 8.2.5. Expecting “[Success]: Built 8.2.5 successfully.”
PHP_BUILD_CONFIGURE_OPTS="--with-sodium --with-mysqli --with-pdo-mysql" \
phpenv install 8.2.5Reload configs
phpenv rehashFPM proccess will run as www-data. (set user = www-data group = www-data) in file below
vim ~/.phpenv/versions/8.2.5/etc/php-fpm.d/www.confPHP-FPM will run as systemd proccess. Add this config in /etc/systemd/system/php-fpm-8.2.5.service
# It's not recommended to modify this file in-place, because it
# will be overwritten during upgrades. If you want to customize,
# the best way is to use the "systemctl edit" command.
[Unit]
Description=The PHP FastCGI Process Manager
After=network.target
[Service]
Type=simple
PIDFile=/home/ubuntu/.phpenv/versions/8.2.5/var/run/php-fpm.pid
ExecStart=/home/ubuntu/.phpenv/versions/8.2.5/sbin/php-fpm --nodaemonize --fpm-config /home/ubuntu/.phpenv/versions/8.2.5/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
# Set up a new file system namespace and mounts private /tmp and /var/tmp directories
# so this service cannot access the global directories and other processes cannot
# access this service's directories.
PrivateTmp=true
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by this unit.
ProtectSystem=full
# Sets up a new /dev namespace for the executed processes and only adds API pseudo devices
# such as /dev/null, /dev/zero or /dev/random (as well as the pseudo TTY subsystem) to it,
# but no physical devices such as /dev/sda.
PrivateDevices=true
# Explicit module loading will be denied. This allows to turn off module load and unload
# operations on modular kernels. It is recommended to turn this on for most services that
# do not need special file systems or extra kernel modules to work.
ProtectKernelModules=true
# Kernel variables accessible through /proc/sys, /sys, /proc/sysrq-trigger, /proc/latency_stats,
# /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq will be made read-only to all processes
# of the unit. Usually, tunable kernel variables should only be written at boot-time, with the
# sysctl.d(5) mechanism. Almost no services need to write to these at runtime; it is hence
# recommended to turn this on for most services.
ProtectKernelTunables=true
# The Linux Control Groups (cgroups(7)) hierarchies accessible through /sys/fs/cgroup will be
# made read-only to all processes of the unit. Except for container managers no services should
# require write access to the control groups hierarchies; it is hence recommended to turn this on
# for most services
ProtectControlGroups=true
# Any attempts to enable realtime scheduling in a process of the unit are refused.
RestrictRealtime=true
# Restricts the set of socket address families accessible to the processes of this unit.
# Protects against vulnerabilities such as CVE-2016-8655
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
# Takes away the ability to create or manage any kind of namespace
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
Start the process
sudo systemctl start php-fpm-8.2.5.serviceenable at startup
systemctl enable php-fpm-8.2.5.serviceIn project’s apache config, add this inside the . The default port is 9000. If you want to change it, it’s done in ~/.phpenv/versions/8.2.5/etc/php-fpm.d/www.conf:
<FilesMatch \.php$>
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>inside project folder add file called .php-version with
8.2.5In wp-config.php change localhost to 127.0.0.1. new PHP 8.2.5 FPM is using TCP instead of the Unix socket.
/** MySQL hostname */
define( 'DB_HOST', '127.0.0.1' );WordPress should work with new php version now:)
Add even more php versions.
cd ~/.phpenv/plugins/php-build/
phpenv rehash
PHP_BUILD_CONFIGURE_OPTS="--with-sodium --with-mysqli --with-pdo-mysql" \
phpenv install 8.4.8If you want to build new php version but you get error like this: [Error] Definition 8.4.8 not found -> download the last definitions with pulling last changes. Remote repo is : https://github.com/php-build/php-build.git
cd ~./phpenv/plugins/php-builds
git pull