Nginx y varias versiones de PHP en Debian y Ubuntu

Mascote do LinuxPro ligando o nginx a três PHP-FPM, placa 3D do hexágono verde na parede

Debian 12 trae PHP 8.2. Ubuntu 24.04, 8.3. Debian 13, 8.4. Ubuntu 26.04, 8.5. Un host de verdad necesita los tres a la vez: el WordPress antiguo, el Laravel nuevo, el CLI del cron. El repo de la distro no lo permite. El de Ondřej Surý lo permite. El nginx sale de nginx.org — estable, pineado, sin mezclar el módulo de la distro.

El mapa en septiembre de 2026

PHP en ciclo oficial:

  • 8.5 — activo hasta dic/2027, seguridad hasta dic/2029 (salió 20 nov 2025)
  • 8.4 — activo hasta dic/2026, seguridad hasta dic/2028
  • 8.3 — sólo seguridad, hasta dic/2027
  • 8.2 — seguridad hasta 31 dic 2026
  • 8.1 murió en 31 dic 2025 — no instale en caja nueva

Sury coinstala php8.3-fpm, php8.4-fpm e php8.5-fpm en la misma box. Cada uno tiene su propio socket en /run/php/. El nginx elige el socket en el vhost.

El repo de nginx del Sury cerró en abril de 2026. PHP continúa en packages.sury.org/php. Nginx: distro o nginx.org. No mezcles los dos binarios.

Nginx desde nginx.org

Debian 12 (bookworm), 13 (trixie); Ubuntu 24.04 (noble), 26.04 (resolute). amd64 y arm64. Huella de la clave: 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 (caduca 24 may 2027).

Debian:

sudo apt install -y curl gnupg2 ca-certificates lsb-release debian-archive-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor 
  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show 
  /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] 
https://nginx.org/packages/debian $(lsb_release -cs) nginx" 
  | sudo tee /etc/apt/sources.list.d/nginx.list

Ubuntu — solo cambia el keyring y la URL:

sudo apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor 
  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] 
https://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" 
  | sudo tee /etc/apt/sources.list.d/nginx.list

Pin para que apt no vuelva al nginx de la distro, e instala el estable (número par: 1.30.x en 2026). Mainline es .../mainline/debian o .../mainline/ubuntu.

printf '%sn' 'Package: *' 'Pin: origin nginx.org' 'Pin: release o=nginx' 'Pin-Priority: 900' 
  | sudo tee /etc/apt/preferences.d/99nginx
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
nginx -v

El paquete de nginx.org utiliza el usuario nginx e /etc/nginx/conf.d/ — no tiene sites-available. El de la distro usa www-data y el diseño Debian. Elige uno y quédate con él. El systemd se encarga del servicio en ambos.

¿Quieres el nginx de la distro, con sites-enabled e nginx-extras? Salta esta sección y haz sudo apt install nginx. El resto de PHP es igual; solo cambia el dueño del socket.

PHP: el DPA de Sury

Receta oficial de packages.sury.org/php/README.txt — vale para Debian 12/13 y Ubuntu 24.04/26.04:

sudo apt-get update
sudo apt-get -y install lsb-release ca-certificates curl
curl -sSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
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/php.list
sudo apt-get update

Atajo solo Ubuntu (PPA Launchpad del mismo Ondřej):

sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update

No actives los dos a la vez. Un source de PHP basta.

Tres FPM lado a lado + extensiones típicas de WordPress/Laravel:

sudo apt install -y 
  php8.3-fpm php8.3-cli php8.3-mysql php8.3-xml php8.3-curl php8.3-mbstring php8.3-zip php8.3-gd php8.3-intl php8.3-bcmath 
  php8.4-fpm php8.4-cli php8.4-mysql php8.4-xml php8.4-curl php8.4-mbstring php8.4-zip php8.4-gd php8.4-intl php8.4-bcmath 
  php8.5-fpm php8.5-cli php8.5-mysql php8.5-xml php8.5-curl php8.5-mbstring php8.5-zip php8.5-gd php8.5-intl php8.5-bcmath
sudo systemctl enable --now php8.3-fpm php8.4-fpm php8.5-fpm
ls /run/php/
# php8.3-fpm.sock  php8.4-fpm.sock  php8.5-fpm.sock

CLI por defecto (el que llama php sin número):

sudo update-alternatives --config php
php -v
php8.5 -v

Alinear el socket con nginx

Diagrama: navegadores chegam no nginx, que roteia para três pools de PHP-FPM no mesmo host

En nginx.org el worker es el usuario nginx. El pool por defecto de FPM es www-data. Sin alinear, se obtiene 502. En cada pool:

sudo sed -i 's/^listen.owner.*/listen.owner = nginx/' /etc/php/8.4/fpm/pool.d/www.conf
sudo sed -i 's/^listen.group.*/listen.group = nginx/' /etc/php/8.4/fpm/pool.d/www.conf
# repita 8.3 e 8.5
sudo systemctl restart php8.3-fpm php8.4-fpm php8.5-fpm

Si el nginx es el de la distribución, deje www-data y sáltese el sed.

Host virtual de ejemplo — tres sitios, tres PHPs. En nginx.org el archivo va en /etc/nginx/conf.d/:

server {
    listen 80;
    server_name wp.exemplo.com.br;
    root /var/www/wp.exemplo.com.br;
    index index.php index.html;
    location / { try_files $uri $uri/ /index.php?$args; }
    location ~ .php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}
server {
    listen 80;
    server_name app.exemplo.com.br;
    root /var/www/app.exemplo.com.br/public;
    index index.php;
    location / { try_files $uri $uri/ /index.php?$query_string; }
    location ~ .php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.5-fpm.sock;
    }
}
sudo mkdir -p /var/www/wp.exemplo.com.br /var/www/app.exemplo.com.br/public
echo '<?php phpinfo();' | sudo tee /var/www/wp.exemplo.com.br/index.php
sudo nginx -t && sudo systemctl reload nginx

Confirme en phpinfo() la PHP Version y la ruta del php.ini (/etc/php/8.3/fpm/php.ini, etc.). Cada versión mayor tiene su propio ini: cambiar 8.4 no toca el 8.5.

Cortafuegos y qué no hacer

sudo ufw allow 22,80,443/tcp
sudo ufw enable

No instale libapache2-mod-php* en este box. No apunte dos server_name iguales a sockets diferentes y espere un milagro. No suba PHP 8.1 “porque el plugin lo pide”: Sury todavía lo empaqueta, pero el upstream ha terminado. 8.2 solo hasta finales de 2026.

Panel con nginx+PHP ya masticado: ISPConfig. Este post es la caja pelada, sin panel.

Cierre

Un pin en nginx.org, un DPA en Sury, tres FPM, tres sockets, tres server. El apt actualiza el punto; el vhost elige el major. Cuando el 8.2 salga de soporte, borre el paquete — el 8.5 en el otro vhost ni se entera.

Nginx: nginx.org/en/linux_packages.html · PHP Sury: packages.sury.org/php · ciclo PHP: php.net/supported-versions.