Debian 13 (trixie) ships PHP 8.4, and on 11 November 2026 the exact version is 8.4.27-1~deb13u1, from the trixie-security archive (packages.debian.org). PHP 8.5 is not part of Debian 13: you get it from the packages.sury.org repository, which on the same day offered PHP 8.5.12 for trixie, next to every branch from 5.6 to 8.4 and a release candidate of 8.6.
This guide installs Debian's PHP with Nginx or Apache, shows where each php.ini lives, then adds PHP 8.5 side by side without letting the extra repository replace Debian's own 8.4 by accident, which is the step most guides skip. We ran every command below in a fresh Debian 13 container on 11 November 2026 and copied the outputs. RS Computers runs KVM servers in Amsterdam, Dublin and Prishtina, and a VPS in the Netherlands or any of our VPS and VDS plans comes with Debian 13 and full root access, so you can follow along on a clean server.
Key facts, checked on 11 November 2026:
- Debian 13's PHP branch is 8.4. The
phpmetapackage is version2:8.4+96and "depends on latest stable PHP version (currently 8.4)" (packages.debian.org/trixie/php). - The Debian security tracker lists php8.4
8.4.24-1~deb13u1in trixie and8.4.27-1~deb13u1in trixie (security). The second one is the fix for PHP2Shell. - Debian 13 gets full security support until 9 August 2028 and LTS until 30 June 2030 (Debian trixie release page). It stays on PHP 8.4 for that whole time.
- php.net supports 8.4 with security fixes until 31 December 2028 and 8.5 until 31 December 2029 (php.net supported versions).
- packages.sury.org is run by Ondřej Surý, a Debian Developer, who says he does it "mostly in my free time" (deb.sury.org).
Which PHP version does Debian 13 ship?
Ask apt on the server itself. These two commands only read package lists, so they are safe on a live machine. Run them as root, or put sudo in front:
# as root
apt update
apt-cache policy php
apt-cache policy php8.4-fpm | head -8
Our fresh Debian 13 container answered:
php:
Installed: (none)
Candidate: 2:8.4+96
Version table:
2:8.4+96 500
500 http://deb.debian.org/debian trixie/main amd64 Packages
php8.4-fpm:
Installed: (none)
Candidate: 8.4.27-1~deb13u1
Version table:
8.4.27-1~deb13u1 500
500 http://deb.debian.org/debian-security trixie-security/main amd64 Packages
8.4.24-1~deb13u1 500
500 http://deb.debian.org/debian trixie/main amd64 Packages
Read the version string from left to right. 8.4.27 is the PHP release from php.net, -1 is Debian's first packaging of it, and ~deb13u1 marks a build made as an update for Debian 13 stable. The main archive still has 8.4.24 from the last point release and the security archive has 8.4.27; apt installs the higher one. If your server only shows 8.4.24, the trixie-security line is missing from your apt sources. Fix that first.
| Package on Debian 13 | Version on 11 Nov 2026 | Archive |
|---|---|---|
php (metapackage) | 2:8.4+96 | trixie/main |
php8.4, php8.4-fpm, php8.4-cli | 8.4.27-1~deb13u1 | trixie-security |
| Same packages, release version | 8.4.24-1~deb13u1 | trixie/main (13.7) |
| PHP 8.3, 8.5 or older | not in Debian 13 | only from packages.sury.org |
Install PHP on Debian 13 with Nginx and PHP-FPM
Do not start with apt install php. That metapackage pulls in php8.4, and apt-cache depends php8.4 lists libapache2-mod-php8.4 as its first choice, ahead of php8.4-fpm. On an empty server that means Apache with mod_php, which you probably did not want with Nginx. Name the packages instead. As root:
# as root
apt install -y nginx php8.4-fpm php8.4-mysql php8.4-curl php8.4-mbstring php8.4-xml php8.4-zip php8.4-gd php8.4-intl
On our container this set up 61 packages in one go and ended with triggers for php8.4-cli and php8.4-fpm (8.4.27-1~deb13u1), no errors. The seven extensions are the ones WordPress, Laravel, Symfony and most shops ask for: php8.4-mysql gives mysqli and pdo_mysql, php8.4-xml covers dom, simplexml and xmlreader, and OPcache comes with the base packages already.
Check the version, the service and the socket
# as root
php -v
systemctl is-active php8.4-fpm nginx
ls -l /run/php/
php -m | grep -Ei "^(mysqli|pdo_mysql|curl|mbstring|xml|zip|gd|intl|Zend OPcache)$"
Expected output, trimmed:
PHP 8.4.27 (cli) (built: Oct 21 2026 07:53:46) (NTS)
Copyright (c) The PHP Group
Built by Debian
Zend Engine v4.4.27, Copyright (c) Zend Technologies
with Zend OPcache v8.4.27, Copyright (c), by Zend Technologies
active
active
lrwxrwxrwx 1 root root 30 Nov 11 12:25 php-fpm.sock -> /etc/alternatives/php-fpm.sock
srw-rw---- 1 www-data www-data 0 Nov 11 12:25 php8.4-fpm.sock
curl
gd
intl
mbstring
mysqli
pdo_mysql
xml
Zend OPcache
zip
The line that matters for the web server is /run/php/php8.4-fpm.sock, owned by www-data. That is the address Nginx talks to. It comes from listen = /run/php/php8.4-fpm.sock in /etc/php/8.4/fpm/pool.d/www.conf, the default pool.
Point an Nginx site at PHP-FPM
Replace example.com with your domain. As root:
# as root
mkdir -p /var/www/example.com
cat > /var/www/example.com/index.php <<'EOF'
<?php
echo 'PHP ', PHP_VERSION, ' via ', PHP_SAPI, "\n";
echo 'php.ini: ', php_ini_loaded_file(), "\n";
EOF
cat > /etc/nginx/sites-available/example.com <<'EOF'
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}
}
EOF
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
curl -s -H "Host: example.com" http://127.0.0.1/
nginx -t must end with test is successful, and curl should print:
PHP 8.4.27 via fpm-fcgi
php.ini: /etc/php/8.4/fpm/php.ini
In our first run curl printed the "Welcome to nginx!" page instead, because it fired before the reload had finished. A second curl a moment later gave the lines above. If you get a 502 instead, the socket path in fastcgi_pass does not match a running pool; our guide to fixing a 502 Bad Gateway walks through each cause. Delete the test file once the site works, so you do not publish your PHP version.
Install PHP on Debian 13 with Apache
With Apache, use the same php8.4-fpm service and hand PHP requests to it through proxy_fcgi. If you already did the Nginx part on the same server, stop Nginx first with systemctl disable --now nginx, because both want port 80. Then, as root:
# as root (php8.4-fpm and the extensions from above already installed)
apt install -y apache2
a2enmod proxy_fcgi setenvif
a2enconf php8.4-fpm
systemctl reload apache2
echo '<?php echo "PHP ", PHP_VERSION, " via ", PHP_SAPI, "\n";' > /var/www/html/info.php
curl -s http://127.0.0.1/info.php
Expected result: PHP 8.4.27 via fpm-fcgi. a2enmod suggests a restart, but in our test a reload was enough. The file a2enconf switches on is /etc/apache2/conf-available/php8.4-fpm.conf, shipped by the php8.4-fpm package. Its core is one handler line, which you will reuse per site later:
<FilesMatch ".+\.ph(?:ar|p|tml)$">
SetHandler "proxy:unix:/run/php/php8.4-fpm.sock|fcgi://localhost"
</FilesMatch>
Why not the older mod_php? It loads PHP into every Apache process, so the whole server runs one PHP version. The PHP2Shell advisory also says full remote code execution "was validated over HTTP against mod_php" with default limits (GHSA-w8hw-w9fx-j79w). PHP-FPM keeps PHP in its own processes, lets each site run as its own user, and lets two versions live side by side.
Where php.ini lives: CLI, FPM and Apache
Debian keeps a separate php.ini for every way PHP runs. Editing the wrong one is the classic reason a new upload limit "does not work".
| PHP runs as | php.ini | Extra .ini files | Apply changes with |
|---|---|---|---|
| Command line, cron, Composer | /etc/php/8.4/cli/php.ini | /etc/php/8.4/cli/conf.d/ | nothing, next run reads it |
| PHP-FPM (Nginx or Apache) | /etc/php/8.4/fpm/php.ini | /etc/php/8.4/fpm/conf.d/ | systemctl restart php8.4-fpm |
| PHP 8.5 from sury.org | /etc/php/8.5/fpm/php.ini and /etc/php/8.5/cli/php.ini | same pattern under 8.5 | systemctl restart php8.5-fpm |
php --ini shows the CLI files and php-fpm8.4 -i | grep "Loaded Configuration File" shows the FPM one. Instead of editing php.ini, put your own values in a small file that package updates never touch:
# as root
cat > /etc/php/8.4/fpm/conf.d/99-local.ini <<'EOF'
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
EOF
php-fpm8.4 -t
systemctl restart php8.4-fpm
echo '<?php echo ini_get("upload_max_filesize"), " ", ini_get("memory_limit"), "\n";' > /var/www/html/limits.php
curl -s http://127.0.0.1/limits.php
php8.4 -r 'echo ini_get("upload_max_filesize"), " ", ini_get("memory_limit"), "\n";'
Our output proves the point. The web answered 64M 256M, the command line still said 2M -1, because the CLI has its own php.ini, where Debian sets no memory limit. Debian's FPM defaults were upload_max_filesize = 2M, post_max_size = 8M and memory_limit = 128M. If uploads still fail after this, Nginx has its own limit; see our fix for 413 Request Entity Too Large.
Install PHP 8.5 on Debian 13 from packages.sury.org
These are the commands from the repository's own README.txt, which installs a signed keyring package instead of piping a key into apt-key. Run them as root. On a sudo account, put sudo in front of each line; the sh -c wrapper is there so the redirect also runs as root.
# as root
apt-get update
apt-get -y install lsb-release ca-certificates curl
curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
dpkg -i /tmp/debsuryorg-archive-keyring.deb
sh -c 'echo "deb [signed-by=/usr/share/keyrings/debsuryorg-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
apt-get update
You should see Setting up debsuryorg-archive-keyring (2025.11.18), and the last update fetches https://packages.sury.org/php trixie InRelease. The signed-by part means apt trusts this key for this one repository only, not for Debian's archives.
What the repository offers for trixie today
# as root
apt-cache search --names-only '^php[0-9.]+-fpm$' | sort -V
apt-cache policy php8.5-fpm | head -3
On 11 November 2026 the list ran from php5.6-fpm through 7.0 to 7.4, 8.0 to 8.5, and php8.6-fpm. PHP 8.5 was 8.5.12-3+0~deb.sury.org.1+debian13, PHP 8.3 was 8.3.36, and 8.6 was a release candidate, 8.6.0~rc5, which does not belong on a production site. php.net supports only 8.2 and newer, so treat 5.6 to 8.1 as a way to keep an old application alive while you move it, not as a target.
The step to do before installing anything
Right after adding the repository, run apt list --upgradable. We did, and apt wanted to replace 14 packages Debian had installed:
libgd3/trixie 2.3.3-16+0~deb.sury.org.1+debian13 amd64 [upgradable from: 2.3.3-14~deb13u1]
php-common/trixie 2:101+0~20261021.78+debian13~1.gbp53f25f all [upgradable from: 2:96]
php8.4-cli/trixie 8.4.27-1+0~20261021.57+debian13~1.gbp7636b9 amd64 [upgradable from: 8.4.27-1~deb13u1]
php8.4-fpm/trixie 8.4.27-1+0~20261021.57+debian13~1.gbp7636b9 amd64 [upgradable from: 8.4.27-1~deb13u1]
...
Same PHP release, different builder. sury's version strings sort higher, so the next apt upgrade silently moves your 8.4 sites from Debian's security team to the sury repository. If you want PHP 8.5 and nothing else from sury, tell apt with a pin file, as root:
# as root
cat > /etc/apt/preferences.d/sury-php <<'EOF'
# Keep Debian's own PHP 8.4 and libraries; take only PHP 8.5 from sury.org
Package: *
Pin: origin packages.sury.org
Pin-Priority: 100
Package: php8.5*
Pin: origin packages.sury.org
Pin-Priority: 500
EOF
apt-get update
apt list --upgradable
apt-cache policy php8.4-fpm | head -3
After the pin, apt list --upgradable printed only Listing..., and the php8.4-fpm candidate was back to 8.4.27-1~deb13u1. Priority 100 means "install from here only if nothing else has the package", and 500 lifts PHP 8.5 back to normal. If you would rather take all PHP packages from sury, skip the pin; just make that choice on purpose.
Install PHP 8.5 next to 8.4
# as root
apt-get install -y php8.5-fpm php8.5-mysql php8.5-curl php8.5-mbstring php8.5-xml php8.5-zip php8.5-gd php8.5-intl
php8.5 -v
systemctl is-active php8.4-fpm php8.5-fpm
ls -l /run/php/ | grep sock
PHP 8.5.12 (cli) (built: Nov 11 2026 06:28:37) (NTS)
Copyright (c) The PHP Group
Built by Debian
Zend Engine v4.5.12, Copyright (c) Zend Technologies
with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies
active
active
lrwxrwxrwx 1 root root 30 Nov 11 12:25 php-fpm.sock -> /etc/alternatives/php-fpm.sock
srw-rw---- 1 www-data www-data 0 Nov 11 12:25 php8.4-fpm.sock
srw-rw---- 1 www-data www-data 0 Nov 11 12:27 php8.5-fpm.sock
Every package in that command came from sury at version 8.5.12, while 8.4 stayed on Debian's build, and php8.5-gd worked with Debian's own libgd3. There is no php8.5-opcache package: OPcache is part of 8.5 itself and showed up in php8.5 -m without extra steps. Two FPM services now run, each with its own socket, its own pool folder and its own php.ini under /etc/php/8.5/.
One surprise: php -v on the command line now said 8.5.12 as well. Installing a higher version moves the php command to it, which matters for cron jobs and Composer. The next section puts it back.
Switch PHP versions per site and for the command line
Nothing changes for your sites until you point one at the new socket. On Nginx, change the fastcgi_pass line of that one site, as root:
# as root: move example.com to PHP 8.5
sed -i 's#php8.4-fpm.sock#php8.5-fpm.sock#' /etc/nginx/sites-available/example.com
nginx -t && systemctl reload nginx
curl -s -H "Host: example.com" http://127.0.0.1/
PHP 8.5.12 via fpm-fcgi
php.ini: /etc/php/8.5/fpm/php.ini
A second site, old.example.com, still pointed at php8.4-fpm.sock and answered PHP 8.4.27 via fpm-fcgi at the same time. Moving back is the same sed with the numbers swapped.
On Apache, put the handler inside the site's own VirtualHost. It wins over the server-wide php8.4-fpm conf:
# as root
mkdir -p /var/www/new.example.com
echo '<?php echo "PHP ", PHP_VERSION, " via ", PHP_SAPI, "\n";' > /var/www/new.example.com/index.php
cat > /etc/apache2/sites-available/new.example.com.conf <<'EOF'
<VirtualHost *:80>
ServerName new.example.com
DocumentRoot /var/www/new.example.com
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php/php8.5-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
EOF
a2ensite new.example.com
apache2ctl configtest
systemctl reload apache2
curl -s -H "Host: new.example.com" http://127.0.0.1/
curl -s http://127.0.0.1/info.php
configtest printed Syntax OK (plus a harmless warning about the global ServerName), the new site answered PHP 8.5.12 via fpm-fcgi and the default site still answered PHP 8.4.27 via fpm-fcgi.
For the command line, pick the version by hand with update-alternatives, as root:
# as root
update-alternatives --set php /usr/bin/php8.4
php -v | head -1
update-alternatives --query php | grep -E "^(Status|Value)"
update-alternatives: using /usr/bin/php8.4 to provide /usr/bin/php (php) in manual mode
PHP 8.4.27 (cli) (built: Oct 21 2026 07:53:46) (NTS)
Status: manual
Value: /usr/bin/php8.4
"Manual mode" means later installs no longer move it: when we installed php8.5-fpm again later, php stayed on 8.4. For a cron job or Composer run that belongs to an 8.5 site, call php8.5 by its full name rather than relying on the default.
Sites with their own users get their own pool file in /etc/php/8.4/fpm/pool.d/ or the 8.5 folder, each with its own socket; moving such a site means moving its pool file and changing its socket in Nginx.
Security updates for Debian PHP and sury PHP
Debian's PHP is patched through trixie-security, which unattended-upgrades allows by default. PHP from sury is a different origin, so the default settings skip it and your PHP 8.5 sites would stay on whatever you installed. Find the origin with apt-cache policy; ours showed release o=deb.sury.org,a=trixie,n=trixie,c=main. Then allow it, as root:
# as root
apt-get install -y unattended-upgrades
cat > /etc/apt/apt.conf.d/52unattended-upgrades-sury <<'EOF'
Unattended-Upgrade::Origins-Pattern {
"origin=deb.sury.org";
};
EOF
unattended-upgrade --dry-run -d 2>&1 | grep -E "Allowed origins|No packages found"
Allowed origins are: origin=Debian,codename=trixie,label=Debian, origin=Debian,codename=trixie,label=Debian-Security, origin=Debian,codename=trixie-security,label=Debian-Security, origin=deb.sury.org
No packages found that can be upgraded unattended and no pending auto-removals
With the pin from earlier, this updates only your PHP 8.5 packages from sury and leaves 8.4 to Debian. The daily timer, the automatic restarts and an hourly emergency mode are in our guide to automatic security updates on Debian 13, written after the PHP2Shell bugs. For SSH keys and the firewall on a fresh server, start with our Debian 13 hardening steps.
Debian's PHP or the sury repository: which to use
| Debian 13 PHP | packages.sury.org | |
|---|---|---|
| Versions on trixie (11 Nov 2026) | 8.4 only (8.4.27-1~deb13u1) | 5.6 to 8.5, plus 8.6.0~rc5 |
| Newest stable PHP | 8.4.27 | 8.5.12 |
| Update source | trixie-security, Debian security team | the sury repository, origin deb.sury.org |
| Automatic updates | on by default with unattended-upgrades | only after you add the origin |
| How long it is supported | 8.4 for the life of Debian 13: security until 9 Aug 2028, LTS until 30 Jun 2030 | follows php.net: 8.4 to 31 Dec 2028, 8.5 to 31 Dec 2029 |
| Who maintains it | Debian | Ondřej Surý, sponsors and donations; paid support via Freexian |
| Best for | most WordPress, Laravel and shop sites | apps that need 8.5, or an old app that needs 8.3 or lower |
Our advice: stay on Debian's 8.4 unless an application needs something else. When one does, add sury with the pin and run 8.5 only for the sites that need it.
Remove a PHP version cleanly
Move the sites first, then remove the packages. If you purge PHP 8.5 while a site still points at its socket, that site returns 502 at once. Find them, as root. Use a capital -R, because sites-enabled holds symlinks and a plain -r skips them; we learned that in the lab:
# as root
grep -Rl "php8.5-fpm.sock" /etc/nginx/sites-enabled/ /etc/apache2/sites-enabled/
It printed /etc/apache2/sites-enabled/new.example.com.conf. Change each file it lists back to the 8.4 socket and reload the web server. Then remove everything with 8.5 in its name, configuration included:
# as root
dpkg -l 'php8.5*' | grep ^ii | awk '{print $2}'
apt-get purge -y 'php8.5*'
apt-get autoremove --purge -y
ls /etc/php/
systemctl is-active php8.5-fpm
php -v | head -1
The purge removed 11 packages, from php8.5-fpm to php8.5-common, and deleted their configuration files. Afterwards /etc/php/ held only 8.4, php8.5-fpm was inactive, the 8.5 socket was gone and php -v said 8.4.27. Keep the quotes around 'php8.5*', and copy /etc/php/8.5/ away first if you edited it by hand: purge deletes it.
Frequently asked questions
What PHP version does Debian 13 use?
PHP 8.4. On 11 November 2026 the current package is php8.4 8.4.27-1~deb13u1 from trixie-security, and the php metapackage, 2:8.4+96, points to 8.4. Debian 13 keeps the 8.4 branch for its whole life and patches it with security updates.
Is PHP 8.5 available in Debian 13?
Not from Debian. PHP 8.5 comes from packages.sury.org, which on 11 November 2026 offered 8.5.12 for trixie. Add it with the signed keyring package, pin it so Debian's 8.4 stays in place, and install the php8.5-fpm packages next to 8.4.
What does 8.4.27-1~deb13u1 mean?
8.4.27 is the PHP release, -1 is Debian's first packaging of it, and ~deb13u1 marks an update built for Debian 13 stable. It is the version Debian published on 21 October 2026 in DSA-6574-1 to fix the PHP2Shell bugs, so any Debian 13 server showing it or something higher has that fix.
Can I install PHP 8.3 on Debian 13?
Yes, from the same sury repository, which had 8.3.36 for trixie on 11 November 2026. Install php8.3-fpm and the matching php8.3- extensions, and change the pin line from php8.5* to php8.3* or add a second block for it. php.net supports 8.3 with security fixes until 31 December 2027.
Can PHP 8.4 and PHP 8.5 run on the same server?
Yes. Each version has its own FPM service, its own socket in /run/php/ and its own folder in /etc/php/. In our test, one Nginx site answered from 8.5.12 and another from 8.4.27 at the same time. You choose per site with the socket path, and per server for the command line with update-alternatives.
Where is php.ini on Debian 13?
There is one per way of running PHP: /etc/php/8.4/cli/php.ini for the command line and /etc/php/8.4/fpm/php.ini for websites through PHP-FPM. Put your own changes in a file such as /etc/php/8.4/fpm/conf.d/99-local.ini and restart php8.4-fpm.
Which RS Computers plan fits a PHP server
For one small site or a test server, VPS Nano (1 vCPU, 1 GB RAM, 20 GB NVMe) is a fair place to start. For a handful of client sites with MariaDB, VPS Mini (4 vCPU, 4 GB, 80 GB) leaves more room for PHP workers and the database. For an agency server or a busy shop, VDS Small (4 dedicated vCPUs, 8 GB, 240 GB) is the size we used to test 200 PHP sites on separate FPM pools in our PHP2Shell post. The VPS plans use shared vCPUs and the VDS plans dedicated ones. Every server gets a dedicated IPv4 and IPv6 address, full root and free weekly backups, and is ready with Debian 13 in under 60 seconds after payment. You can pick a server in Amsterdam, a server in Dublin or a server in Prishtina, or compare all sizes on the VPS and VDS plans page. Not sure which size your PHP app needs? Ask us on Telegram.