Skip to content

PHP

How to Install PHP 8.5 on Ubuntu 24.04 — and Run Several PHP Versions Side by Side

Install PHP 8.5 and PHP-FPM on Ubuntu 24.04, keep PHP 8.3 and 8.4 alongside it, give each site its own FPM pool, and switch the CLI version safely.

6 min read By the Hanoo team

PHP 8.5 was released in November 2025 and is now the newest supported PHP. Ubuntu 24.04 LTS, though, ships PHP 8.3 in its own archive — so getting PHP 8.5 means adding a package source, and running real applications usually means keeping several PHP versions installed side by side: Magento on 8.5, a Laravel app on 8.4, a legacy site on 8.3.

This guide installs PHP 8.5 and PHP-FPM on Ubuntu 24.04, runs it next to other versions without conflicts, gives each site its own PHP-FPM pool, and keeps everything patched.

Which PHP versions are supported in 2026?

Each PHP release gets two years of active support followed by two years of security fixes, ending on 31 December:

VersionReleasedActive support untilSecurity fixes until
PHP 8.5November 202531 Dec 202731 Dec 2029
PHP 8.4November 202431 Dec 202631 Dec 2028
PHP 8.3November 2023Ended31 Dec 2027
PHP 8.2December 2022Ended31 Dec 2026
PHP 8.1 and older—EndedEnded — upgrade

For new projects, choose PHP 8.4 or 8.5. Check your framework first: Magento 2.4.9 wants 8.4 or 8.5, Laravel 13 needs 8.3 or newer, WordPress recommends 8.4 or 8.5, and Moodle 5.1 stops at 8.4.

What's new in PHP 8.5

  • The pipe operator |> passes a value through a chain of callables left to right, replacing deeply nested calls.
  • A built-in URI extension parses and normalises URLs according to RFC 3986 and the WHATWG URL standard, instead of the loose parse_url().
  • array_first() and array_last() finally return the first and last values of an array without moving its internal pointer.
  • clone with property overrides, which makes "with-er" methods on readonly classes much simpler.
  • #[\NoDiscard] warns when the return value of a function that must be checked is ignored.
PHP
$slug = '  Hello World  '
    |> trim(...)
    |> strtolower(...)
    |> (fn (string $value): string => str_replace(' ', '-', $value));
// "hello-world"

Step 1: add the PHP repository

The Ondřej Surý PPA is the de-facto source of current PHP builds for Ubuntu and Debian; it is maintained by a long-standing Debian PHP packager and carries every supported version for each Ubuntu LTS.

Terminal
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update

Step 2: install PHP 8.5 and PHP-FPM

Install the FPM service, the command-line binary and the extensions your application needs. A broad set that covers most frameworks and CMSs:

Terminal
sudo apt install php8.5-fpm php8.5-cli php8.5-common php8.5-mysql php8.5-pgsql \
  php8.5-curl php8.5-gd php8.5-intl php8.5-mbstring php8.5-xml php8.5-zip \
  php8.5-bcmath php8.5-soap php8.5-opcache php8.5-redis

Check the result:

Terminal
php8.5 -v
systemctl status php8.5-fpm

Step 3: install other versions side by side

Every version lives in its own directories and runs its own service, so installing another one never replaces the first:

Terminal
sudo apt install php8.4-fpm php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl

You now have:

Output
/etc/php/8.4/fpm/   → php8.4-fpm.service → /run/php/php8.4-fpm.sock
/etc/php/8.5/fpm/   → php8.5-fpm.service → /run/php/php8.5-fpm.sock

Each version has its own php.ini for FPM and CLI, and its own extensions. Installing php8.5-redis does nothing for PHP 8.4.

Step 4: give each site its own PHP-FPM pool

The default www pool runs every site as www-data. That means one compromised site can read every other site's files and secrets. Give each site a pool of its own, running as its own user, on the PHP version it needs. For a shop running on PHP 8.5, create /etc/php/8.5/fpm/pool.d/shop.conf:

INI
[shop]
user = shop
group = shop
listen = /run/php/php8.5-fpm-shop.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500

php_admin_value[memory_limit] = 512M
php_admin_value[open_basedir] = /srv/shop:/tmp
php_admin_flag[expose_php] = off
Terminal
sudo adduser --system --group --home /srv/shop shop
sudo systemctl reload php8.5-fpm

Then point the site's web server at that socket — fastcgi_pass unix:/run/php/php8.5-fpm-shop.sock; in Nginx, or php_fastcgi unix//run/php/php8.5-fpm-shop.sock in Caddy. Moving the site to another PHP version later means creating the same pool under the other version and switching the socket path.

Sizing pm.max_children

Each FPM worker holds a full PHP process in memory. A practical starting point is:

Output
pm.max_children ≈ (RAM you can give this site) ÷ (average worker memory)

Measure the average with ps -o rss= -u shop | awk '{ s += $1 } END { print s / NR / 1024 " MB" }' under normal traffic. 60–120 MB per worker is typical for WordPress and Laravel; Magento workers are larger.

Step 5: choose the default php command

The plain php command points to one version through Debian's alternatives system:

Terminal
sudo update-alternatives --config php

This affects only the CLI. FPM pools, cron jobs and deploy scripts should name the version explicitly (php8.5 artisan …, php8.4 wp-cli.phar …) so a change to the default never silently moves an application to another PHP.

Step 6: keep PHP patched

Ubuntu's unattended-upgrades installs security updates from Ubuntu's own archive, but not from PPAs unless you allow them. Add the PPA's origin in a file such as /etc/apt/apt.conf.d/52unattended-upgrades-php:

Output
Unattended-Upgrade::Allowed-Origins:: "LP-PPA-ondrej-php:${distro_codename}";

PHP patch releases come out roughly monthly and regularly include security fixes; leaving PHP on a PPA without automatic updates is one of the most common ways self-managed servers fall behind.

Multiple PHP versions with Hanoo

Hanoo manages exactly this setup on Ubuntu servers you own. It installs PHP 8.0 through 8.5 side by side on Ubuntu 22.04, 24.04 and 26.04 LTS — from the same PPA on 22.04 and 24.04, and from Ondřej Surý's packages.sury.org repository on 26.04, where the PPA publishes no builds — and adds that source to unattended upgrades, so PHP security releases arrive automatically. Every application gets its own Linux user and its own PHP-FPM pool on the version you pick when you create it, and pool settings — process manager, max_children, memory limit, upload size — are editable as structured fields in the dashboard rather than raw config files. Cron jobs and workers run as the application's user, so a Magento store on PHP 8.5 and a legacy app on PHP 8.1 share a server without sharing a single file permission.

Frequently asked questions

Does Ubuntu 24.04 include PHP 8.5?

No. Ubuntu 24.04's own archive provides PHP 8.3. PHP 8.4 and 8.5 for Ubuntu 24.04 are installed from the ppa:ondrej/php repository.

Can I run PHP 8.3, 8.4 and 8.5 on the same server?

Yes. Each version installs into its own directories with its own FPM service and socket, so they coexist. Point each site's web server configuration at the FPM socket of the version it needs.

How do I change the default PHP version on Ubuntu?

Run sudo update-alternatives --config php and choose the version. This changes the php command only; web requests use whichever PHP-FPM socket the web server is configured with.

Is PHP 8.5 stable enough for production?

Yes. PHP 8.5 is a general-availability release with active support until the end of 2027. The real question is whether your application and its dependencies support it — Magento 2.4.9 does, for example, while Moodle 5.1 stops at PHP 8.4.

Should every site have its own PHP-FPM pool?

Yes. A separate pool per site, running as a separate user, isolates sites from each other, lets you size and tune each one independently, and makes it possible to run different PHP versions per site.

How do I enable OPcache in PHP 8.5?

OPcache is built into PHP 8.5. Make sure opcache.enable=1 in the FPM php.ini and give it enough memory with opcache.memory_consumption; on a production server, also consider opcache.validate_timestamps=0 with an FPM reload after every deploy.