PHP is one of the most adopted open source programming languages, commonly used to build interactive and dynamic web pages. A local PHP environment lets you test applications before you deploy them. This guide covers Ubuntu 24.04 and 22.04, and Debian users have a separate PHP on Debian guide.
We install PHP 8.3 from Ondřej Surý’s PPA, check it for the PHP2Shell fix and set up Composer. Rocky Linux and AlmaLinux have their own PHP 8.3 guide. The install was run in October 2026 on fresh Ubuntu 24.04 and 22.04 servers against PHP 8.3.36 from the PPA, and the Composer steps, patch checks and the upgrade from an older 8.3 build were run on 24.04 as a regular sudo user.
Prerequisites
You need a local or virtual machine running Ubuntu 24.04 or 22.04, with sudo access and a working internet connection.
Step 1 – Add APT PPA repository
All the installation steps used in this article are performed on the command line. This can be done from a root user account or another standard user account with permissions to use sudo.
Launch terminal on your Ubuntu system. For Desktop you can use Desktop Environment search function to locate the “Terminal” application. For remote applications an SSH session will drop you right at the terminal (using your client).
Ensure you have the latest versions of deb applications and utilities installed on the system. The second line reboots only when the upgrade left Ubuntu’s reboot flag behind, such as after a new kernel.
sudo apt update && sudo apt upgrade -y
[ -f /var/run/reboot-required ] && sudo reboot
Install tools required to configure APT repositories on the system.
sudo apt install curl gpg gnupg2 software-properties-common ca-certificates apt-transport-https lsb-release
Next, add the PPA that carries the PHP 8.3 packages, ppa:ondrej/php. The -y flag skips the “Press ENTER” prompt, and the command refreshes the package index on its own.
sudo add-apt-repository -y ppa:ondrej/php
Confirm APT now picks PHP 8.3 from the PPA rather than from Ubuntu’s own archive:
apt-cache policy php8.3
On 24.04 the candidate is the deb.sury.org build, with Ubuntu’s own 8.3.6 packages listed below it. A 22.04 server shows only the PPA line, with ubuntu22.04.1 in the version string.
php8.3:
Installed: (none)
Candidate: 8.3.36-1+ubuntu24.04.1+deb.sury.org+1
Version table:
8.3.36-1+ubuntu24.04.1+deb.sury.org+1 500
500 https://ppa.launchpadcontent.net/ondrej/php/ubuntu noble/main amd64 Packages
8.3.6-0ubuntu0.24.04.13 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages
8.3.6-0ubuntu0.24.04.12 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages
8.3.6-0maysync1 500
500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
The PPA only builds for 24.04 (noble) and 22.04 (jammy) now, and its own description says it is being merged into packages.sury.org, so expect the repository URL for these two releases to change in the coming weeks. It has no Ubuntu 26.04 build at all. packages.sury.org serves 26.04, and 26.04 ships PHP 8.5 in its own archive, which the PHP 8.5 guide for Ubuntu 26.04 covers. The PPA’s 20.04 (focal) index is empty, and the PHP2Shell fix for Ubuntu’s own PHP 7.4 on 20.04 requires Ubuntu Pro (free for personal use), so a 20.04 server without Pro has no patched PHP. Move it to 24.04 instead of hunting for packages.
Step 2 – Install PHP 8.3 and extensions
Once the repository is configured, proceed to install PHP 8.3 on Ubuntu system. On a fresh server the php8.3 package also pulls in Apache and libapache2-mod-php8.3 and starts Apache on port 80 (27 new packages on 24.04, 36 on 22.04), which is what you want for an Apache site.
sudo apt -y install php8.3
If the box will run Nginx, or only needs PHP on the command line, skip that line and install php8.3-fpm (or just php8.3-cli) instead. On our 24.04 test server php8.3-fpm came in with 10 packages and no Apache, and installing the php8.3 metapackage after it still added no Apache, because FPM already satisfies its dependency:
sudo apt -y install php8.3-fpm
If you already installed the metapackage and want Nginx, stop and disable Apache first, because Nginx can’t start while Apache holds port 80:
sudo systemctl disable --now apache2
Confirm the installation by checking PHP version.
php8.3 -v
The first line names the release the CLI runs. It does not tell you whether that build carries the latest security fixes, which is what the next section checks.
PHP 8.3.36 (cli) (built: Oct 21 2026 14:32:55) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.36, Copyright (c) Zend Technologies
with Zend OPcache v8.3.36, Copyright (c), by Zend Technologies
Other additional PHP extensions can be installed as required. The command syntax is php8.3-<extension_name>
sudo apt install php8.3-{cli,pdo,mysql,zip,gd,mbstring,curl,xml,bcmath,common}
APT skips the packages the first command already installed and adds the rest with their libraries. This is the 24.04 run; 22.04 installs 40 packages for the same line.
php8.3-cli is already the newest version (8.3.36-1+ubuntu24.04.1+deb.sury.org+1).
php8.3-cli set to manually installed.
php8.3-common is already the newest version (8.3.36-1+ubuntu24.04.1+deb.sury.org+1).
php8.3-common set to manually installed.
The following additional packages will be installed:
fontconfig-config fonts-dejavu-core fonts-dejavu-mono libabsl20220623t64
libaom3 libavif16 libdav1d7 libdeflate0 libfontconfig1 libfreetype6
libgav1-1 libgd3 libgomp1 libheif-plugin-aomdec libheif-plugin-aomenc
libheif1 libimagequant0 libjbig0 libjpeg-turbo8 libjpeg8 liblerc4 libonig5
libpng16-16t64 librav1e0 libsharpyuv0 libsvtav1enc1d1 libtiff6 libwebp7
libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 libxslt1.1 libyuv0
libzip4t64
Suggested packages:
libgd-tools libheif-plugin-libde265 libheif-plugin-x265
libheif-plugin-ffmpegdec libheif-plugin-jpegdec libheif-plugin-jpegenc
libheif-plugin-j2kdec libheif-plugin-j2kenc libheif-plugin-rav1e
libheif-plugin-svtenc
The following NEW packages will be installed:
fontconfig-config fonts-dejavu-core fonts-dejavu-mono libabsl20220623t64
libaom3 libavif16 libdav1d7 libdeflate0 libfontconfig1 libfreetype6
libgav1-1 libgd3 libgomp1 libheif-plugin-aomdec libheif-plugin-aomenc
libheif1 libimagequant0 libjbig0 libjpeg-turbo8 libjpeg8 liblerc4 libonig5
libpng16-16t64 librav1e0 libsharpyuv0 libsvtav1enc1d1 libtiff6 libwebp7
libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxpm4 libxslt1.1 libyuv0
libzip4t64 php8.3-bcmath php8.3-curl php8.3-gd php8.3-mbstring php8.3-mysql
php8.3-xml php8.3-zip
0 upgraded, 44 newly installed, 0 to remove and 0 not upgraded.
Need to get 12.8 MB of archives.
After this operation, 38.5 MB of additional disk space will be used.
Some of the extensions that we installed are:
cli: command line interpreter. It is used for testing PHP scripts from shell or interactive PHP scripting.mysql: for interacting with MySQL databaseszip: useful when working with compressed filesgd: you need it to work with imagesmbstring: management of non-ASCII stringscurl: for making HTTP requests in PHPxml: working with XML databcmath: arbitrary-precision decimal mathcommon: common modules and their ini files, shared by every PHP 8.3 SAPI
In this section we’ve been able to install PHP and commonly required PHP extensions. Before moving on to Composer, check that the build you got is patched.
Check PHP 8.3 for PHP2Shell (CVE-2026-109618, CVE-2026-109619)
PHP2Shell is a pair of critical remote code execution bugs in PHP itself, CVE-2026-109618 and CVE-2026-109619, rated CVSS v4.0 9.2 in PHP’s 20 October pre-announcement and fixed upstream on 21 October 2026 in PHP 8.3.36 (and 8.5.12, 8.4.27, 8.2.35). The Ondřej Surý PPA already ships the fixed 8.3 build for Ubuntu 24.04 and 22.04, so a fresh install from this guide is patched. The PHP security advisory has the details.
Read the package changelog rather than the version line, because the changelog names the CVEs a build fixes:
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-common/changelog.Debian.gz
A patched PPA build prints this line on 24.04 and 22.04 alike. No output means the installed package is older than the fixed build. On a fresh install that is the whole check, so you can go straight to Composer.
+ (CVE-2026-109618, CVE-2026-109619): Avoid state corruption via
The same zgrep works if the server runs Ubuntu 24.04’s own php8.3 instead of the PPA, but the fixed archive build 8.3.6-0ubuntu0.24.04.13 words it differently, so expect these lines instead:
- debian/patches/CVE-2026-109618_109619.patch: Avoid state corruption via
- CVE-2026-109618
- CVE-2026-109619
On that build it’s the only check that means anything, because Ubuntu backports the fix without changing the upstream version and php -v prints 8.3.6 before and after it. Minimized images and containers often strip /usr/share/doc, so the changelog isn’t there at all. Compare the installed package version with the fixed one instead:
dpkg --compare-versions "$(dpkg-query -W -f='${Version}' php8.3-common)" ge 8.3.36 && echo patched || echo VULNERABLE
That threshold fits the PPA build. Our test server printed VULNERABLE while rolled back to an older 8.3 build and this after the upgrade below. For Ubuntu’s own package, compare against 8.3.6-0ubuntu0.24.04.13 instead, since 8.3.36 is newer than any 8.3.6 archive build.
patched
A server that passes either check needs nothing more here.
Upgrade an existing server
If either check fails, upgrade every installed PHP 8.3 package. The quoted glob covers the CLI, FPM, common and extension packages. libapache2-mod-php8.3 and libphp8.3-embed don’t match it, so they are named on their own, and APT skips whichever isn’t installed:
sudo apt update
sudo apt install --only-upgrade 'php8.3*' libapache2-mod-php8.3 libphp8.3-embed
Other branches you installed from the same PPA, such as php8.4 or php8.2 alongside 8.3, need the same command with their own prefix, because each branch has its own packages and its own fixed release.
Then restart every service that runs PHP, because a process that started before the upgrade keeps the old code in memory until it’s replaced. That means Apache for mod_php and php8.3-fpm if you installed it, so drop whichever unit your server doesn’t have:
sudo systemctl restart apache2 php8.3-fpm
Long-running PHP CLI workers, such as queue workers under supervisor or a systemd unit, hold the old build too, so restart them the same way. To prove the running services are the new ones, compare their start time with the upgrade time. Find the upgrade in the dpkg logs first. zgrep also reads the rotated, compressed ones:
zgrep -h ' upgrade php8.3-common' /var/log/dpkg.log* | sort | tail -1
Our 24.04 test server was rolled back to the original 8.3.6 build before the upgrade, so the line shows the jump to the PPA’s fixed release. A fresh install prints nothing here, since nothing was upgraded.
2026-10-22 16:02:52 upgrade php8.3-common:amd64 8.3.6-0maysync1 8.3.36-1+ubuntu24.04.1+deb.sury.org+1
Then read when Apache last started, and FPM if you run it:
systemctl show -p ActiveEnterTimestamp apache2
systemctl show -p ActiveEnterTimestamp php8.3-fpm
Both timestamps must be later than the upgrade time. An earlier one means that service still runs the old build, so restart it again, then rerun the zgrep or the version comparison.
ActiveEnterTimestamp=Thu 2026-10-22 16:03:32 UTC
ActiveEnterTimestamp=Thu 2026-10-22 16:03:32 UTC
With a patched build confirmed, move on to dependency management with Composer.
Step 3 – Set up PHP Composer
Composer is a PHP utility for handling dependency management when building applications using PHP and many third party modules. With Composer you declare libraries that the project has dependency on and it will manage its installation and updating.
Run these steps as your regular user, not root, and download the Composer setup script:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
Before running it, check the installer against the SHA-384 checksum Composer publishes, as the Composer download page recommends. The checksum changes with every installer release, so this reads the current one instead of hardcoding it, and deletes the file if it doesn’t match:
EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
[ "$EXPECTED_CHECKSUM" = "$ACTUAL_CHECKSUM" ] && echo "Installer verified" || { echo "Installer corrupt"; rm composer-setup.php; }
Anything other than this line means the download was altered or truncated, so fetch it again:
Installer verified
Next run the script to set up composer.phar, then remove the installer:
php composer-setup.php
php -r "unlink('composer-setup.php');"
The installer checks the PHP settings it needs, then writes composer.phar to your home directory:
All settings correct for using Composer
Downloading...
Composer (version 2.10.3) successfully installed to: /home/josphat/composer.phar
Use it: php composer.phar
Make the script available to all users in the system.
sudo mv composer.phar /usr/local/bin/composer
For use by a single logged in user, move the script to ~/.local/bin instead. That directory does not exist on a new account, and Ubuntu’s ~/.profile only adds it to PATH when it exists, so create it, then reload the profile (or log in again):
mkdir -p ~/.local/bin && mv composer.phar ~/.local/bin/composer
source ~/.profile
Check your Composer version by running:
composer --version
Composer reports its own version and the PHP binary it runs on, which should be the 8.3 build:
Composer version 2.10.3 2026-08-27 13:34:23
PHP version 8.3.36 (/usr/bin/php8.3)
Run the "diagnose" command to get more detailed diagnostics output.
When using Composer in your project, you have to initialize for composer.json file creation. This file is used to manage app dependencies and defining project details such as Author and License. See the basic Composer’s autoload functionality.
The command to initialize a project is.
composer init
Generated data will be saved inside the composer.json file.
Step 4 – Test PHP 8.3 installation
We can now create a test PHP script.
vim hello.php
Add these lines and save the file:
<?php
echo 'Hello World from my PHP code';
?>
Test the script to confirm PHP is able to process it correctly.
php hello.php;echo
If successful you will see the characters within the quotes in your code printed out.
Hello World from my PHP code
That output means the CLI interpreter, the extensions and Composer are all in place.
Conclusion
At this point, you should have PHP 8.3 programming environment configured in your local or remote Ubuntu Linux machine and ready to get started. We hope you benefited from our article. Until next time, cheers!
Why are you reposting out of date articles?
ppa:ondrej/php has not supported php 8.3 on 20.04 for a while now…