Introducción
Si alguna vez tuviste que correr dos apps en el mismo servidor —una legacy en PHP 8.1 y otra reciente en 8.3—, ya sabes el dolor de cabeza que significa no romper una mientras arreglas la otra. La tentación de parchear /usr/bin/php para que apunte a una versión distinta termina mal: tickets rotos, deploys que duelen y una resolución de alternativas que nadie recuerda cómo se configuró.
En Ubuntu/Debian, el camino más estable no es parchear binarios. Es usar los paquetes paralelos de ppa:ondrej/php y dejar que cada proceso hable con el socket de su propia versión.
El Contexto
Ubuntu empaqueta una sola versión de PHP por release. Si necesitás 8.1 y 8.3 al mismo tiempo, lo natural es instalar ambas variantes de FPM y CLI en paralelo:
add-apt-repository ppa:ondrej/php
apt update
apt install php8.1-fpm php8.1-cli php8.1-mbstring php8.1-xml
apt install php8.3-fpm php8.3-cli php8.3-mbstring php8.3-xml
Cada paquete trae su propio socket en /run/php/. La clave es que Nginx o Apache no eligen por versión; eligen por socket. Cada pool FPM escucha en el suyo:
a2enconf php8.1-fpm
systemctl restart php8.1-fpm
El flujo queda así:
graph TD
A[Sitio Web] --> B[Nginx / Apache]
B -->|legacy| C[php8.1-fpm pool]
B -->|app nueva| D[php8.3-fpm pool]
C --> E["/run/php/php8.1-fpm.sock"]
D --> F["/run/php/php8.3-fpm.sock"]
G[CLI] -->|php8.1| H[php8.1]
G -->|php8.3| I[php8.3]Advertencia: Nunca parchees /usr/bin/php con symlinks manuales en producción. Un deploy posterior de paquetes puede romper todo sin dejar rastro en /var/log.
La Solución
Para cambiar la versión CLI según el proyecto sin tocar binarios globales:
update-alternatives --config php
Dentro de cada proyecto podés usar .phpbrewrc o phpenv, pero si el servidor solo necesita servir peticiones web, alcanza con tener ambos FPM corriendo y apuntar cada virtual host a su socket. Esa separación es suficiente: el dispatcher es el socket, no un binario compartido.
Consejo: Documentá en el README del servidor qué versión corre cada pool y en qué socket está escuchando. Cuando algo falle a las 3 AM, la memoria de trabajo no alcanza.
Lecciones Aprendidas
- Parchear
/usr/bin/phptrae riesgos de regresión en cualquier deploy posterior. - Los sockets son la abstracción correcta para separar versiones en el mismo servidor: aíslan el ciclo de vida de cada pool.
ppa:ondrej/phpes el estándar no-oficial pero ampliamente adoptado en Ubuntu para mantener versiones que ya salieron de soporte en los repositorios oficiales.
Conclusión
Convivir con varias versiones de PHP es una necesidad común, no un caso borde. Los paquetes paralelos de FPM + sockets por pool son la solución más mantenible dentro de un servidor Ubuntu.