En resumen: para operar PHP en contenedores, elija la variante adecuada de la imagen oficial (fpm, apache o cli), active el php.ini de producción, instale solo las extensiones necesarias y fije límites de memoria y de procesos que encajen entre sí. Los contenedores son inmutables: una actualización de seguridad de PHP como la de PHP2Shell solo surte efecto cuando la imagen se ha reconstruido y se ha reiniciado cada contenedor. Esta reconstrucción debe formar parte, por tanto, como proceso fijo, de toda operación con contenedores.
¿Por qué PHP en contenedores?
Los contenedores empaquetan PHP, las extensiones y la configuración en una imagen que se ejecuta igual en cualquier servidor. Para las empresas significa menos sorpresas entre prueba y producción, una recuperación más rápida y versiones claras. Para la seguridad significa también una nueva obligación: en un contenedor nadie aplica actualizaciones de forma automática.
Esta página trata la operación diaria. Cómo parchear de forma concreta contenedores existentes frente a PHP2Shell figura en Parchear PHP en contenedores Docker.
Elegir la variante de imagen adecuada
| Variante | Contenido | Uso típico |
|---|---|---|
php:<version>-fpm |
PHP-FPM, necesita un servidor web delante | producción con Nginx, Caddy o un ingress |
php:<version>-apache |
Apache con mod_php, por defecto mpm_prefork | configuraciones sencillas, aplicaciones antiguas |
php:<version>-cli |
línea de comandos; es la única variante que incluye también php-cgi | tareas cron, workers de colas, pasos de build |
…-alpine |
sobre Alpine Linux con musl | imágenes pequeñas, en algunas extensiones hacen falta adaptaciones |
…-bookworm, …-trixie |
sobre la versión de Debian indicada | base fija para builds reproducibles |
Para proyectos nuevos suele recomendarse la variante fpm con un contenedor de servidor web independiente. Con mod_php, el equipo de PHP ve en relación con PHP2Shell el mayor riesgo; quien usa la imagen apache opera justo ese modo de ejecución.
Construir una imagen de producción
Un ejemplo ligero para una aplicación con acceso a MySQL:
FROM php:8.4-fpm-alpine
# Activar la configuración de producción (muy recomendado según la documentación de la imagen)
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Solo las extensiones necesarias
RUN docker-php-ext-install -j"$(nproc)" pdo_mysql
# Ajustes propios
COPY zz-sicherheit.ini "$PHP_INI_DIR/conf.d/"
# El código pertenece a root; los workers de FPM se ejecutan como www-data y solo pueden leerlo
COPY . /var/www/html
Los scripts auxiliares de la imagen se encargan de construir extensiones: docker-php-ext-configure para las opciones, docker-php-ext-install para construir, docker-php-ext-enable para activar, por ejemplo tras pecl install. Si se descomprime el código fuente con docker-php-source, según la documentación debería borrarse de nuevo en la misma capa. El archivo zz-sicherheit.ini podría ser así:
expose_php = Off
display_errors = Off
log_errors = On
session.use_strict_mode = 1
session.cookie_httponly = 1
Otros dos principios hacen las imágenes más robustas. Primero, la imagen entregada contiene solo lo que se necesita en tiempo de ejecución; el compilador, las cachés de paquetes y los archivos de prueba van a una fase de build propia. Segundo, el usuario con el que se ejecuta PHP solo debe poder escribir donde es necesario, por ejemplo en directorios de subidas o de caché en volúmenes montados. Muchos equipos operan además el contenedor con el sistema de archivos protegido contra escritura. Un archivo PHP introducido lo tiene entonces mucho más difícil para permanecer, y cada reinicio restablece el estado limpio de la imagen. Esto no sustituye una investigación tras un incidente, pero reduce de forma notable la superficie de ataque.
Procesos, memoria y logs en el contenedor
Tres factores determinan si un contenedor de PHP funciona de forma estable.
- Número de workers:
pm.max_childrenen el pool de FPM establece cuántas peticiones se atienden a la vez. Cada worker puede ocupar hastamemory_limit. - Límite de memoria del contenedor: limita todos los procesos en conjunto. Como regla aproximada, el número de workers por la memoria de cada worker más una reserva debe caber por debajo del límite; de lo contrario, el sistema termina procesos.
- Logs: los contenedores escriben los logs en la salida estándar. En PHP-FPM,
catch_workers_output = yesredirige las salidas de los workers al log principal; sin este ajuste, según el manual, se pierden.
Resulta útil además request_terminate_timeout, que termina las peticiones individuales tras un intervalo cuando max_execution_time no actúa. Cómo operar contenedores en un clúster lo describe Parchear PHP en Kubernetes.
Contenedores y seguridad: lo que ha mostrado PHP2Shell
En PHP2Shell, los contenedores desempeñan un papel doble. Por un lado, son una ayuda: como medida provisional frente a CVE-2026-109618, php.net recomienda combinar memory_limit=-1 con un límite de memoria mediante contenedor o cgroup, idealmente de modo que solo se termine el worker afectado. RLIMIT_AS y RLIMIT_DATA no son adecuados para ello según php.net. Esta medida no es una protección completa y no sustituye a la actualización.
Por otro lado, los contenedores son una trampa si las imágenes no se reconstruyen. Una imagen con PHP 8.4.26 sigue siendo vulnerable, por muchas veces que se reinicie el contenedor. Solo una reconstrucción a 8.4.27 o posterior y la sustitución de todos los contenedores en ejecución cierran la vulnerabilidad. El estado se puede comprobar directamente en el contenedor en ejecución:
docker exec <container> php -v
docker exec <container> php-fpm -v
docker exec <container> php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
Si el último comando devuelve bool(false), PHP no conoce la directiva introducida con las versiones corregidas; según el manual, la versión está entonces afectada. A largo plazo solo ayuda una reconstrucción automática, como se describe en CI/CD: reconstruir automáticamente las imágenes de PHP.
Fije en el Dockerfile la versión exacta de PHP en la etiqueta y súbala de forma consciente. Así queda constancia en el código de cuándo se desplegó cada versión.
¿Cómo ayuda PHP SOS en concreto?
En el refuerzo del servidor para servidores web PHP nos ocupamos también de los contenedores:
- Revisar las imágenes: imagen base, versión de PHP, extensiones y configuración de cada imagen.
- Reforzar la configuración: ini de producción, lista de extensiones reducida, límites de workers y de memoria adecuados.
- Configurar la reconstrucción: un proceso que reconstruye y despliega las imágenes con cada nueva versión de PHP.
- Controlar el tiempo de ejecución: demostramos que en cada contenedor en ejecución corre la versión corregida.
Preguntas frecuentes
¿Qué variante de la imagen de PHP es la correcta?
Para Nginx u otro proxy, la variante fpm; para una configuración sencilla con Apache, la variante apache; para scripts y tareas cron, la variante cli. Las variantes Alpine son más pequeñas, pero se basan en musl en lugar de glibc, lo que se nota en algunas extensiones.
¿Se actualiza PHP automáticamente en el contenedor?
No. Un contenedor en ejecución no cambia. Debe reconstruir la imagen con la nueva versión de PHP y reiniciar los contenedores. Solo entonces se ejecuta la versión corregida.
¿Cómo se relacionan memory_limit y el límite del contenedor?
memory_limit limita cada petición de PHP; el límite del contenedor, todo el contenedor. Ambos deben encajar: el número de workers por la memoria de cada worker debería quedar por debajo del límite del contenedor.
¿Necesito un php.ini en los contenedores?
Sí. Las imágenes oficiales incluyen php.ini-development y php.ini-production como plantillas. Para producción, la documentación de la imagen recomienda expresamente la plantilla de producción; los ajustes propios van a conf.d.