Debian

Install PHP 8.1 on Debian 13 / Debian 12

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.

Original content from computingforgeeks.com - post 100

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:

ExtensionPurpose
fpmFastCGI Process Manager for Nginx or Apache proxy_fcgi
mysqlMySQL/MariaDB driver (mysqli + PDO)
pgsqlPostgreSQL driver
gdImage processing (JPEG, PNG, WebP, AVIF)
mbstringMulti-byte string handling for UTF-8
xmlXML parsing (DOM, SimpleXML, XMLReader)
curlHTTP client for API calls
zipZIP archive handling
intlInternationalization (ICU library)
opcacheBytecode caching for performance
ldapLDAP/Active Directory authentication
soapSOAP 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

Keep reading

PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Php PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Configure Samba File Share on Debian 13 / 12 Debian Configure Samba File Share on Debian 13 / 12 Backup and Restore Linux Systems with Timeshift Debian Backup and Restore Linux Systems with Timeshift Install HestiaCP on Ubuntu 26.04/24.04 and Debian 13/12 Web Hosting Install HestiaCP on Ubuntu 26.04/24.04 and Debian 13/12 Patch WordPress Against CVE-2026-87902 File Inclusion Security Patch WordPress Against CVE-2026-87902 File Inclusion Monitor Apache with Prometheus and Grafana Prometheus Monitor Apache with Prometheus and Grafana

4 thoughts on “Install PHP 8.1 on Debian 13 / Debian 12”

Leave a Comment

Press ESC to close