PHP 8.1 is not shipped in the default Debian 13 or Debian 12 repositories. Debian 13 defaults to PHP 8.4, and Debian 12 defaults to PHP 8.2. If your application specifically requires PHP 8.1 (WordPress plugins, Laravel 9.x, legacy codebases that haven’t been tested on newer versions), you need the Sury third-party repository to install it.
The steps below cover the Sury repository, common extensions, PHP-FPM and production tuning. PHP 8.1 reached end of life upstream at the end of 2025, so php.net ships no new 8.1 releases, but Sury keeps backporting security fixes into its 8.1.34 packages. If your application supports it, PHP 8.4 is the recommended version for new deployments. The install, extension and PHP-FPM steps below were run again on fresh Debian 13 and Debian 12 systems in October 2026 against the Sury PHP 8.1 build that carries the PHP2Shell fixes.
Prerequisites
- Debian 13 (Trixie) or Debian 12 (Bookworm) with sudo access
- An active internet connection for package downloads
Update Your System
Start with a fully updated system:
sudo apt update && sudo apt -y upgrade
Reboot if the kernel was updated:
[ -e /var/run/reboot-required ] && sudo reboot
If the file isn’t there, nothing happens and you can carry on with the repository setup.
Add the Sury PHP Repository
The Sury PHP repository is maintained by OndΕej SurΓ½, who is also the official Debian PHP package maintainer. It publishes every PHP branch from 5.6 up to 8.5 side by side, for Debian releases that don’t ship them natively.
Install the prerequisite packages:
sudo apt install -y lsb-release ca-certificates curl
Download and install the Sury archive keyring, which sets up both the GPG signing key and the repository source:
curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
Add the PHP repository to your sources list:
echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list
Update the package index to pull in the new repository metadata:
sudo apt update
You should see the Sury repository listed in the update output, confirming it was added correctly.
Install PHP 8.1
With the Sury repository in place, install PHP 8.1:
sudo apt install -y php8.1
This installs the core PHP 8.1 packages including php8.1-cli, php8.1-common, php8.1-opcache, and libapache2-mod-php8.1 (Apache integration module).
Confirm the installed version:
php8.1 -v
The output confirms PHP 8.1.34 with OPcache enabled:
PHP 8.1.34 (cli) (built: Oct 21 2026 08:18:19) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.34, Copyright (c) Zend Technologies
with Zend OPcache v8.1.34, Copyright (c), by Zend Technologies
Don’t read too much into that version string. It says 8.1.34 on the vulnerable build and on the patched one alike, which matters for the check below.
Check PHP 8.1 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, both rated CVSS 9.2 and fixed upstream on 21 October 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 got no upstream release because the branch is end of life, but Sury backported both fixes into its php8.1 8.1.34-9 packages for trixie and bookworm, so a server installed from this repository on or after 21 October is already covered.
Because the backport keeps the 8.1.34 number, php8.1 -v can’t tell you whether you’re patched. The package changelog can, since Sury names both CVEs in the entry that fixes them:
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.1-common/changelog.Debian.gz
A patched server prints the backport line. Empty output means the installed build predates the fix:
+ [CVE-2026-109618, CVE-2026-109619]: Avoid state corruption via
For a second check, read the package version, because patched Sury builds carry the 21 October snapshot date in the version string:
dpkg-query -W -f='${Package} ${Version}\n' php8.1-common php8.1-fpm
We got this on Debian 13, and on Debian 12 the suffix reads debian12 instead, with the same 8.1.34-9 release:
php8.1-common 8.1.34-9+0~20261021.82+debian13~1.gbp4e430a
php8.1-fpm 8.1.34-9+0~20261021.82+debian13~1.gbp4e430a
If you installed PHP 8.1 before 21 October and the changelog check comes back empty, pull the update. On Debian and Ubuntu the PHP packages restart PHP-FPM and Apache during the upgrade, which we watched happen on Debian 13 and Ubuntu 26.04. A running worker keeps the old code until it restarts, so restart php8.1-fpm yourself afterwards (and apache2 if you use libapache2-mod-php8.1) and the question is settled.
sudo apt update && sudo apt -y upgrade
Then restart the PHP processes so no worker is left running the old library:
sudo systemctl restart php8.1-fpm
Run the zgrep again afterwards and confirm the line shows up. The full write-up of both bugs is in the PHP security advisory. If you’re still on Debian 11, Sury publishes the same patched 8.1.34-9 build for bullseye, but Debian’s own PHP 7.4 there gets no free fix and the release itself is out of support, so plan the move to Debian 13 and the current PHP guide for Debian.
Install PHP 8.1 Extensions
Most web applications need extensions beyond the base install. Install the commonly required ones for frameworks like WordPress, Laravel, and Drupal:
sudo apt install -y php8.1-{fpm,xml,mysql,zip,intl,ldap,gd,cli,bz2,curl,mbstring,pgsql,opcache,soap,cgi}
The syntax php8.1-{fpm,xml,mysql,...} is a bash brace expansion that installs multiple packages in one command. Each extension maps to a separate Debian package.
Here is what each extension provides:
| Extension | Purpose |
|---|---|
fpm | FastCGI Process Manager for Nginx or Apache proxy_fcgi |
mysql | MySQL/MariaDB driver (mysqli + PDO) |
pgsql | PostgreSQL driver |
gd | Image processing (JPEG, PNG, WebP, AVIF) |
mbstring | Multi-byte string handling for UTF-8 |
xml | XML parsing (DOM, SimpleXML, XMLReader) |
curl | HTTP client for API calls |
zip | ZIP archive handling |
intl | Internationalization (ICU library) |
opcache | Bytecode caching for performance |
ldap | LDAP/Active Directory authentication |
soap | SOAP web services |
Verify all extensions loaded correctly:
php8.1 --modules
The output lists every loaded module:
[PHP Modules]
bz2
calendar
Core
ctype
curl
date
dom
exif
FFI
fileinfo
filter
ftp
gd
gettext
hash
iconv
intl
json
ldap
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_pgsql
pgsql
Phar
posix
readline
Reflection
session
shmop
SimpleXML
soap
sockets
sodium
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
Every extension from the install line shows up, along with the modules that ship inside php8.1-common such as sodium and FFI, so nothing is missing before you wire PHP into a web server.
Configure PHP-FPM
PHP-FPM runs PHP as a separate service rather than embedding it inside Apache. This is the standard approach when using Nginx, and also works with Apache via proxy_fcgi.
Enable and start the PHP 8.1 FPM service:
sudo systemctl enable --now php8.1-fpm
Verify it is running:
sudo systemctl status php8.1-fpm
The output shows the FPM master process with idle worker pools:
β php8.1-fpm.service - The PHP 8.1 FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php8.1-fpm.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-03-26 09:22:26 UTC; 898ms ago
Docs: man:php-fpm8.1(8)
Main PID: 17500 (php-fpm8.1)
Status: "Ready to handle connections"
Tasks: 3 (limit: 4655)
Memory: 13.5M (peak: 15.3M)
CGroup: /system.slice/php8.1-fpm.service
ββ17500 "php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)"
PHP-FPM listens on a Unix socket at /run/php/php8.1-fpm.sock by default. Point your Nginx fastcgi_pass directive or Apache proxy_fcgi configuration to this socket. The pool configuration is at /etc/php/8.1/fpm/pool.d/www.conf.
Tune php.ini for Production
PHP ships with conservative defaults. For web applications, you will typically need to adjust memory limits and upload sizes. Edit the FPM php.ini:
sudo vi /etc/php/8.1/fpm/php.ini
Common settings to adjust:
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_vars = 3000
date.timezone = UTC
Restart PHP-FPM to apply changes:
sudo systemctl restart php8.1-fpm
The CLI and FPM use separate php.ini files. Changes to /etc/php/8.1/fpm/php.ini only affect web requests. CLI scripts read from /etc/php/8.1/cli/php.ini.
PHP 8.1 Key Features
PHP 8.1, released November 2021, introduced several major language features:
- Enums – First-class enumerated types, replacing the constant-based workarounds
- Fibers – Lightweight concurrency primitives for async programming
- Readonly properties – Class properties that can only be written once (in the constructor)
- Intersection types – Combine multiple type constraints with
& - Never return type – Declare that a function never returns (throws exception or calls
exit()) - array_is_list() – Built-in function to check if an array is a list (sequential integer keys starting from 0)
Going Further
- Set up a complete LAMP stack on Debian with Apache, MariaDB, and PHP
- Deploy WordPress with Nginx and PHP-FPM for better performance than mod_php
- Install MariaDB on Debian for the database backend
- Plan your migration to PHP 8.4 on Debian now that upstream 8.1 support has ended
- For Ubuntu servers, see Install PHP 8.4 on Ubuntu 24.04
Thank you so much! I followed the steps and upgraded to PHP-8.1.17
Welcome.
Thanks you, works perfect!
Thank you, It worked .