Chapter 1 of 5

Install PHP and its extensions for Laravel on Debian 13

verified on 2 September 2026 · 4 min

Quick answer

Debian 13 provides PHP 8.4 in its official repositories: sudo apt install php-cli php-fpm php-mbstring php-xml php-curl php-zip php-bcmath php-intl php-mysql is enough for Laravel 13, with no third-party repository. Watch out for two packages that are often recommended by mistake: php-json has served no purpose since PHP 8.0, and php-mysql is the one you need, not php-mysqli, because Laravel goes through PDO.

Laravel 13 asks for PHP 8.2 at the very least, plus a handful of extensions. Good news: Debian 13 “trixie” ships PHP 8.4 in its official repositories, which makes the third-party Sury repository pointless in the ordinary case.

Steps run on a clean Debian 13 container, on 2 September 2026. This chapter is part of installing Laravel on a Debian server, in the Web development path.

Check what your Debian already offers

Before adding a single repository, look at what the distribution provides:

bash
sudo apt update
apt-cache policy php-cli
code
php-cli:
  Installed: (none)
  Candidate: 2:8.4+96
  Version table:
     2:8.4+96 500
        500 http://deb.debian.org/debian trixie/main arm64 Packages

PHP 8.4 is available. That is well beyond what Laravel 13 needs, and it spares you an external repository to maintain. Which PHP version each Debian release ships:

Debian PHP in the official repositories Enough for Laravel 13?
13 “trixie” 8.4 Yes
12 “bookworm” 8.2 Yes, at the required minimum
11 “bullseye” 7.4 No, a third-party repository is needed

Install PHP and the extensions

A single command covers the base Laravel requires, plus the database drivers:

bash
sudo apt install -y php-cli php-fpm \
  php-mbstring php-xml php-curl php-zip \
  php-bcmath php-intl \
  php-mysql php-sqlite3 \
  unzip curl ca-certificates

Two common extensions are missing from that list, because they depend on your architecture choices: php-redis, covered in the chapter on Redis, and php-gd or php-imagick for image processing.

Check the version you ended up with:

bash
php -v
code
PHP 8.4.24 (cli) (built: Jul 31 2026 05:11:11) (NTS)

Then make sure every extension Laravel expects answers for itself:

bash
for e in ctype curl dom fileinfo filter hash mbstring openssl \
         pcre pdo session tokenizer xml bcmath intl zip; do
  printf "%-10s %s\n" "$e" "$(php -m | grep -qix "$e" && echo OK || echo MANQUANT)"
done

On the test install, all sixteen lines return OK. Several of those extensions are compiled into Debian’s PHP binary and have no package of their own: they show up in php -m all the same.

Two packages that keep being recommended by mistake

php-json no longer has any reason to exist

Since PHP 8.0, the JSON extension is compiled into the binary and can no longer be disabled. The php-json package survives in Debian as a plain transitional package. Installing it breaks nothing, but it brings nothing either.

php-mysqli is not the right package

Laravel goes through PDO, not mysqli. php-mysql is the one you want, and it provides both. Check what PHP actually sees:

bash
php -r 'echo implode(", ", PDO::getAvailableDrivers()), PHP_EOL;'
code
mysql, sqlite

If mysql is not in that list, Laravel will not be able to connect to MySQL or MariaDB, whatever you put in the .env file.

Tune PHP for a web application

Two files sit side by side, with different values: the command-line one and the web server one. Editing the wrong one is a classic source of confusion.

bash
/etc/php/8.4/cli/php.ini    # artisan, composer, scheduled tasks
/etc/php/8.4/fpm/php.ini    # requests served by nginx or Apache

The settings that matter for a Laravel application live in the FPM file:

/etc/php/8.4/fpm/php.ini
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 21M
max_execution_time = 60

post_max_size has to stay above upload_max_filesize, otherwise an upload at the maximum size is rejected before it ever reaches the application. Then reload the service, without which the values stay exactly as they were:

bash
sudo systemctl reload php8.4-fpm
php -i | grep memory_limit          # CLI value
sudo -u www-data php-fpm8.4 -i | grep memory_limit

With PHP in place, the next step is installing Composer.

Install another PHP version with the Sury repository

This detour is only worth taking if you are after a version Debian does not provide: PHP 8.5 on Debian 13, or PHP 8.2 on a Debian 11. The method has changed: apt-key is gone as of Debian 12, so a dedicated keyring is required.

bash
sudo apt install -y curl ca-certificates
sudo curl -fsSLo /etc/apt/keyrings/php.gpg https://packages.sury.org/php/apt.gpg

echo "deb [signed-by=/etc/apt/keyrings/php.gpg] https://packages.sury.org/php/ $(. /etc/os-release && echo $VERSION_CODENAME) main" \
  | sudo tee /etc/apt/sources.list.d/php.list

sudo apt update
sudo apt install -y php8.5-cli php8.5-fpm php8.5-mbstring php8.5-xml php8.5-curl php8.5-zip php8.5-bcmath php8.5-intl php8.5-mysql

With several versions installed, pick the one that answers to the php command:

bash
sudo update-alternatives --config php
What a third-party repository costs you

You will have to maintain it: at every Debian upgrade, check that the repository has kept up, and follow its security updates separately. If the official repositories are enough, stay on them.

Common errors

Installing php-mysqli instead of php-mysql Laravel uses PDO. Without pdo_mysql no MySQL connection works, whatever the .env settings say.
Adding the Sury repository with no need for it Debian 13 already provides PHP 8.4. A third-party repository adds its own maintenance and a separate security watch.
apt-key has been removed since Debian 12 Tutorials that use it fail. You need a keyring in /etc/apt/keyrings and the signed-by option.
Editing the wrong php.ini The cli/ file and the fpm/ file are separate. The settings that matter for a web application are in fpm/.
Forgetting to reload PHP-FPM Values changed in php.ini only take effect after systemctl reload php8.4-fpm.
post_max_size lower than upload_max_filesize An upload at the maximum size is rejected before it reaches the application.
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.