Update PHP on an Ubuntu or Debian server (2026)
On an unmanaged VPS, patching PHP is your job. Find the PHP-FPM version actually serving WordPress, apt upgrade it, handle the backport version-number trap, and restart php-fpm.
By the Presscomet teamPublished 11 min read
On this page
On a VPS, patching PHP is your job
If your WordPress site runs on an unmanaged VPS — a plain Ubuntu or Debian box from a provider like a GoDaddy VPS, Linode, DigitalOcean, Hetzner or an EC2 instance — then there is no host quietly patching PHP for you behind the scenes. That is the deal you signed up for: full control, full responsibility. When a runtime bug like the PHP2Shell vulnerabilities (CVE-2026-109618 and CVE-2026-109619) lands, nobody updates the server unless you do.
The good news is that on Debian and Ubuntu the update itself is three commands and a restart. The parts that trip people up are knowing which PHP to update (the one serving the web, not the one on your command line), understanding why the version number barely moves afterwards, and remembering the restart. This guide covers all three. If you want the vulnerability background first, read PHP2Shell and WordPress; for the bigger security picture, see our WordPress security guide.
- Fixed upstream in
- 8.5.12 · 8.4.27 · 8.3.36 · 8.2.35
- Debian 13 package
- php8.4 8.4.27-1~deb13u1 (DSA-6574-1)
- Debian 12 package
- php8.2 8.2.35-1~deb12u1 (DLA-4848-1)
- Ubuntu 24.04 package
- php8.3 8.3.6-0ubuntu0.24.04.13 (USN-8948-1)
These are ordinary admin commands
Find the PHP that actually serves the site
A server can have several PHP versions installed at once, and the one on your command line is often not the one serving WordPress. php -v shows the CLI binary (what cron jobs and WP-CLI use). Your site is served by a PHP-FPM pool, or occasionally by Apache’s mod_php. Check that one.
# The CLI PHP — what WP-CLI and cron use (may differ from the web one)$ php -v# The FPM binary that serves the site — change the version to match yours$ php-fpm8.3 -v# Every installed PHP package and its exact build revision$ dpkg -l 'php*'# Which php-fpm services exist and which are running$ systemctl list-units 'php*-fpm*'The dpkg -l 'php*' list is the one that matters: it shows the full package revision, which is how you will confirm the fix later. Cross-check it against wp-admin under Tools › Site Health › Info › Server, which reports the PHP that answers real web requests and the PHP SAPI (fpm-fcgi for PHP-FPM, apache2handler for mod_php). If Site Health and your command line disagree, Site Health wins — it’s measuring the live request path.
The backport version-number trap
This is the single most confusing thing about patching PHP on a stable Linux distribution, so it’s worth stating plainly: Debian and Ubuntu do not bump the three-number PHP version when they fix a security bug. They take the fix, apply it to the version they already ship, and increase the package revision — the bit after the dash.
So on an Ubuntu 24.04 box, the PHP2Shell-patched build still reports PHP 8.3.6, even though upstream’s fixed release is 8.3.36. The fix is there; the headline number just doesn’t show it. What changed is the package revision:
| Distribution | Branch | Fixed package | Advisory |
|---|---|---|---|
| Debian 13 | php8.4 | 8.4.27-1~deb13u1 | DSA-6574-1 |
| Debian 12 | php8.2 | 8.2.35-1~deb12u1 | DLA-4848-1 |
| Ubuntu 24.04 | php8.3 | 8.3.6-0ubuntu0.24.04.13 | USN-8948-1 |
| Ubuntu 22.04 | php8.1 | 8.1.2-1ubuntu2.28 | USN-8948-1 |
| Ubuntu 26.04 | php8.5 | 8.5.4-0ubuntu1.5 | USN-8948-1 |
So how do you know you’re patched?
dpkg -l 'php*' against the advisory string — not the short 8.3.6 number. If your revision is equal to or newer than the one in the table (for example 8.3.6-0ubuntu0.24.04.13), the fix is installed. A number lower than the upstream fixed release does not mean unpatched on a distribution that backports.If you installed PHP from the popular third-party ondrej/php PPA (Ubuntu) or sury.org repository (Debian) instead of the distribution’s own packages, the same logic applies but the fix comes from that repository — so make sure its package is current when you upgrade.
Update the packages
Pick your platform. In every case it’s refresh the index, then upgrade. Take a snapshot or backup of the server first if your provider offers one — it makes a bad upgrade a two-minute rollback instead of a crisis.
Ubuntu’s security pocket carries the fix (USN-8948-1). Refresh and upgrade:
$ sudo apt update# Upgrade everything, or target PHP only:$ sudo apt upgrade$ sudo apt install --only-upgrade 'php*'# Confirm the installed revision matches the advisory, e.g. 8.3.6-0ubuntu0.24.04.13$ dpkg -l 'php*' | grep -E 'php[0-9.]+-fpm|libapache2-mod-php'On releases older than 22.04 the fix ships through Ubuntu Pro’s Expanded Security Maintenance (USN-8948-2), which is free for personal use — enable it with sudo pro attach if those packages don’t appear.
Debian 13 (trixie) fixes it in the main security archive (DSA-6574-1); Debian 12 (bookworm) ships the LTS/point-release fix (DLA-4848-1). Make sure the security line is in your sources, then upgrade:
$ sudo apt update$ sudo apt upgrade# Confirm, e.g. Debian 13: 8.4.27-1~deb13u1 · Debian 12: 8.2.35-1~deb12u1$ dpkg -l 'php*' | grep -E 'php[0-9.]+-fpm|libapache2-mod-php'If apt pulls no PHP update, check that your /etc/apt/sources.list still has the -security entry for your release — a surprising number of “it won’t update” tickets come down to a missing security line.
Containers don’t get apt upgrade; you change the image tag and recreate. The official php and wordpress images publish fixed tags (8.5.12, 8.4.27, 8.3.36, 8.2.35). There are no maintained tags for 8.1 or older.
# What is the running container actually on?$ docker exec <container> php -v# Pin a fixed tag in your Dockerfile or compose file, e.g. FROM php:8.4.27-fpm$ docker compose build --pull$ docker compose up -d --force-recreatePulling a new image changes nothing until the container is recreated — --force-recreate is the step that matters. FrankenPHP users should move to v1.13.2 or later, which bundles the fixed PHP.
The restart everyone forgets
This is the step that turns “I ran the update” into “I’m actually patched.” apt replaces the PHP files on disk, but PHP-FPM and Apache keep the old code running in their worker processes until they restart. A server that was upgraded but never restarted is still serving the vulnerable runtime.
# PHP-FPM (most WordPress VPS setups) — match your version number$ sudo systemctl restart php8.3-fpm# Apache with mod_php (instead of, or as well as, FPM)$ sudo systemctl restart apache2# If Nginx proxies to PHP-FPM, a reload is tidy but not strictly required$ sudo systemctl reload nginx# Confirm the service came back up$ systemctl status php8.3-fpm --no-pager“apt restarted it for me” — did it?
php-fpm automatically, but automatic restarts can be held back (for example by needrestart in a non-interactive upgrade, or a disabled restart hook). Don’t assume. Restart it yourself, check systemctl status, then reload Tools › Site Health › Info › Server in wp-admin to confirm the live version changed.Stuck on PHP 7.4, 8.0 or 8.1?
These branches are past upstream end of life, so the PHP project only published source-only backports for them — there’s no official binary release. What saves you is your distribution: Ubuntu 22.04 backported the fix to its PHP 8.1 (8.1.2-1ubuntu2.28), and distro-maintained 7.4/8.0 packages on supported releases got the same treatment. So if you’re on the distribution’s own packages and they’re current, you’re likely covered.
But treat that as breathing room, not a destination. An end-of-life branch gets security backports only while your distribution release is still supported, and only for the bugs they choose to backport. The durable fix is to move to PHP 8.3 or 8.4, which WordPress.org recommends and which get normal upstream updates. If you can’t patch or upgrade immediately and the box is internet-facing on an unsupported branch, follow the advice security agencies gave during PHP2Shell: take the site offline or behind network authentication until it’s on a fixed runtime.
Step 1: Install the new version alongside the old one
On Debian/Ubuntu with theondrej/phpPPA you can install, say,php8.4-fpmnext tophp8.1-fpmwithout removing anything.Step 2: Add the same extensions WordPress needs
Install matching extensions for the new version:php8.4-mysql,-curl,-gd(or-imagick),-mbstring,-xml,-zipand-intl.Step 3: Point the web server at the new socket
Update your Nginxfastcgi_passor Apache handler to the new FPM socket (e.g./run/php/php8.4-fpm.sock), then reload the web server.Step 4: Test, and keep the old version installed
Click through the site and watchwp-content/debug.logfor a day. The old FPM socket is one config line away if you need to switch back — but only onto a patched build.
The full compatibility-and-rollback walkthrough lives in how to check and update your PHP version in WordPress.
Verify you’re actually patched
Three checks close the loop: the running version in Site Health, the installed package revision against the advisory, and — if you want certainty — the changelog. Then answer the three questions in the checker below for a plain verdict.
# Live web version (compare with wp-admin › Site Health)$ php-fpm8.3 -v# Installed revision vs the advisory string$ dpkg -l 'php*' | grep -E 'php[0-9.]+-(fpm|common)'# Debian/Ubuntu changelog should mention both CVEs$ zcat /usr/share/doc/php8.3-common/changelog.Debian.gz | grep -iE 'CVE-2026-10961[89]|109618|109619' | headInteractive checker
Am I affected by PHP2Shell?
Runs in your browser · nothing is sent
- 1. PHP version
- 2. Server API
- 3. Hosting
- 4. Verdict
Automate it — or take PHP out of the path
PHP2Shell won’t be the last PHP runtime bug, and on a self-managed box the response time is entirely on you. Two things make the next one far less stressful:
- Turn on automatic security updates. Install
unattended-upgradesso security pocket updates land without you watching — and configure it (orneedrestart) to restart services, since an upgrade that doesn’t restart PHP-FPM leaves you exposed. - Put a CDN or WAF in front of the origin and make sure the box isn’t reachable by IP directly. It won’t fix a runtime bug, but it filters a lot of the early scanning while you patch.
There’s also a more structural answer: stop running PHP on every request. Presscomet reproduces the WordPress admin, block editor, URLs, feeds and REST API, but runs on Node.js with no PHP runtime — so PHP2Shell and the entire class of PHP-runtime vulnerabilities simply don’t apply, and there’s no php-fpm to update or restart at 2am. It is not “unhackable”: it has its own stack to keep patched (Node.js, its dependencies and the OS underneath), and it still needs the same server hygiene. Because it doesn’t execute PHP, your old PHP plugins don’t run — the common jobs are built in, and WooCommerce stores aren’t supported — so read can you run WordPress without PHP? before you decide.
If it fits your site, the migration only reads your existing server and reports what would move across — it never changes anything on your VPS — so it’s a safe thing to try.
Sources
Facts checked against these sources on October 24, 2026. Things change quickly; the vendor advisory always wins.
- [1]PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 security releases — PHP.net
- [2]USN-8948-1: PHP vulnerabilities — Ubuntu
- [3]Debian security tracker: CVE-2026-109618 — Debian
- [4]GHSA-w8hw-w9fx-j79w (CVE-2026-109618) — php-src on GitHub
- [5]GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) — php-src on GitHub
- [6]Supported versions — PHP.net
- [7]Two critical PHP flaws: find, mitigate and patch PHP2Shell — Qualys
Frequently asked questions
How do I update PHP on Ubuntu or Debian?
Run sudo apt update to refresh the package list, then sudo apt upgrade to install the patched PHP packages. Afterwards you must restart the service that serves your site — sudo systemctl restart php8.3-fpm for PHP-FPM, plus sudo systemctl restart apache2 if you use Apache mod_php. Until the service restarts, the old PHP stays loaded in memory.
Why does my PHP version still look old after apt upgrade?
Debian and Ubuntu backport security fixes without changing the upstream version number; they bump the package revision instead. Ubuntu 24.04’s PHP2Shell-patched package still reports 8.3.6 (build 8.3.6-0ubuntu0.24.04.13). Compare the full package revision from dpkg -l against the advisory rather than the three-number version.
Do I need to restart PHP-FPM after updating?
Yes, always. apt replaces the files on disk, but PHP-FPM, Apache and LiteSpeed keep the old code running in their worker processes until they restart. Run sudo systemctl restart php8.3-fpm (match your version), and restart apache2 if you use mod_php. On many systems apt restarts php-fpm for you, but confirm it rather than assume.
How do I know which PHP version is actually serving WordPress?
Don’t trust php -v alone — that’s the command-line PHP and can differ from the web one. Check the FPM binary directly with php-fpm8.3 -v, list installed packages with dpkg -l 'php*', and confirm against wp-admin › Tools › Site Health › Info › Server, which reports the PHP that answers web requests.
I'm on PHP 8.1 (or 7.4/8.0) on Ubuntu 22.04. Am I patched?
If you use the distribution packages, yes — Ubuntu backported the PHP2Shell fix to 22.04’s PHP 8.1 (8.1.2-1ubuntu2.28, USN-8948-1) even though 8.1 is past upstream end of life. If you installed PHP from a third-party PPA like ondrej/php, you depend on that repository shipping a fix. Either way, plan a move to 8.3 or 8.4.
How do I update PHP in a Docker WordPress container?
Pin a fixed tag (for example php:8.4.27-fpm or wordpress:php8.4), then rebuild and recreate: docker compose build --pull and docker compose up -d --force-recreate. Pulling a new image changes nothing until the container is recreated. There are no maintained official tags for PHP 8.1 or older.
Presscomet keeps your wp-admin, editor, URLs and content, and serves pages without PHP or MySQL. Check your site for free, then migrate in one click — your old site is only ever read.
Keep reading
- SecurityPHP2Shell and WordPress: are you affected, and how do you fix it?
Two critical bugs in PHP itself put almost every WordPress site on an affected runtime until the host patches it. Here’s what happened in plain English, a checker that tells you whether you’re affected, and step-by-step fixes for every kind of hosting.
- SecurityHow to check and update your PHP version in WordPress (2026)
Your PHP version decides whether your WordPress site still gets security fixes. Here’s how to find it in under a minute, what’s still supported, and a safe way to upgrade without breaking anything.
- HostingIs your WordPress host patched for PHP2Shell? What to ask (with an email template)
On most WordPress sites you can’t patch PHP yourself — your host has to. Here’s who is responsible on each kind of hosting, the four questions that get you a real answer, and a ready-to-send email.