En resumen: para los administradores sin formación de desarrollo bastan cinco fundamentos para operar PHP con seguridad: PHP consta de varios programas (línea de comandos, PHP-FPM, módulo de Apache), cada uno con su propia versión; los ajustes actúan por niveles, desde el php.ini hasta la aplicación; PHP-FPM reparte las peticiones entre workers en pools; una actualización solo surte efecto tras reiniciar todos los procesos; y los logs son la pista más importante cuando algo no cuadra. Quien conoce estos puntos puede cerrar con rapidez y de forma demostrable vulnerabilidades como PHP2Shell.
De qué consta PHP en un servidor
PHP no es un programa único. En un servidor Linux típico hay varias variantes, cada una conectada mediante una interfaz de servidor (SAPI):
| Variante | Nombre típico | Para qué |
|---|---|---|
| Línea de comandos (CLI) | php, php8.3 |
tareas cron, Composer, scripts de mantenimiento |
| PHP-FPM | php-fpm, php-fpm8.3 |
peticiones web detrás de Nginx o Apache |
| Módulo de Apache | mod_php, libphp |
peticiones web directamente en el proceso de Apache |
| CGI | php-cgi |
configuraciones antiguas |
Cada variante puede tener una versión distinta y un php.ini distinto. En muchos servidores se ejecutan además varias versiones de PHP en paralelo, por ejemplo 8.2 y 8.4. En una actualización hay que considerar cada una por separado. Cómo trabajan las interfaces lo explica PHP-FPM explicado.
Qué variante atiende realmente sus sitios web se averigua mediante los procesos en ejecución y la configuración del servidor web:
ps -eo pid,user,lstart,cmd | grep -E "php|httpd|apache2" | grep -v grep
apachectl -M 2>/dev/null | grep -i php # ¿carga Apache un módulo de PHP?
ls /run/php/ 2>/dev/null # sockets de FPM, a menudo por versión y pool
La columna con la hora de inicio será importante más tarde, en el reinicio: todos los procesos de PHP deben haberse iniciado después del momento de la actualización. Si los procesos se ejecutan con distintos usuarios, indica pools separados, lo que es bueno. Si aparece un módulo de PHP en Apache aunque todos los sitios web deban funcionar con FPM, es señal de un lastre heredado que conviene eliminar. Para interfaces de hosting como Plesk o cPanel rige el mismo principio, solo que la interfaz muestra las versiones y los handlers de cada sitio web; lo determinante sigue siendo lo que se ejecuta realmente como proceso.
Los comandos más importantes para administradores
php -v # versión de la línea de comandos
php --ini # php.ini cargado y directorios leídos adicionalmente
php --ini=diff # desde PHP 8.5: desviaciones respecto al estándar
php -m # módulos compilados y cargados
php --ri session # ajustes de una extensión
php -l datei.php # comprobación de sintaxis sin ejecutar
php-fpm8.3 -v # versión del binario de FPM (nombre según la distribución)
php-fpm8.3 -t # probar la configuración de FPM sin reiniciar
systemctl status php8.3-fpm
Dos notas del manual: php -l encuentra errores de sintaxis, pero no los errores que solo aparecen al ejecutar. Y php -i llama a phpinfo(); su salida no debe estar en archivos públicos del directorio web.
Cómo actúan los ajustes de PHP
Un ajuste puede fijarse en varios lugares. Quién puede cambiar qué y dónde lo regula el modo de modificación de cada directiva:
- php.ini y conf.d: configuración básica por variante, leída al iniciar.
- Pool de FPM:
php_valueyphp_admin_valuepor pool. Según el manual, la aplicación no puede sobrescribir conini_set()los valores fijados conphp_admin_value. - Nivel de directorio:
.user.inien FPM o.htaccessen mod_php, solo para directivas en modoINI_PERDIRoINI_ALL. - Aplicación:
ini_set()en tiempo de ejecución, solo para directivas en modoINI_ALL.
Un ejemplo: memory_limit tiene el modo INI_ALL, de modo que la aplicación puede cambiarlo. post_max_size tiene INI_PERDIR y no se puede cambiar con ini_set(). Por eso, en las medidas provisionales de PHP2Shell, php.net exige fijar los valores de modo que las aplicaciones no puedan sobrescribirlos. Los detalles sobre los niveles los explica El php.ini explicado.
Los pools de PHP-FPM en breve
Un pool es un grupo de workers con usuario propio, socket propio y ajustes propios. Las directivas más importantes según el manual:
[shop]
user = shop
group = shop
listen = /run/php/shop.sock
pm = dynamic ; static, dynamic u ondemand
pm.max_children = 20 ; como máximo 20 peticiones simultáneas
pm.max_requests = 500 ; renovar el worker tras 500 peticiones
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/shop-slow.log
php_admin_value[error_log] = /var/log/php-fpm/shop-error.log
php_admin_flag[log_errors] = on
Un pool propio por cada sitio web, con usuario propio, separa los sitios entre sí. security.limit_extensions está por defecto en .php .phar e impide que FPM ejecute extensiones de archivo distintas de PHP. clear_env está activado por defecto y mantiene las variables de entorno fuera del worker.
Logs: dónde deben mirar los administradores
PHP escribe los errores en el destino fijado con error_log; PHP-FPM, además, en su propio log y, en las peticiones lentas, en el slowlog con backtrace. A ello se suman los logs de acceso y de errores del servidor web. Asegúrese de que display_errors esté desactivado en producción y log_errors activado: los errores deben ir al log, no a la página web. Los logs también deberían rotarse y conservarse durante un período definido, para que sigan ahí en caso de emergencia. Tras PHP2Shell, la prensa especializada aconseja conservar los logs del servidor desde el 20/10/2026. Una señal de alarma fuerte es un proceso de PHP-FPM o del servidor web que inicia una shell; cómo detectarlo figura en Señal de alarma: el servidor web inicia una shell.
Lista de control para administradores tras PHP2Shell
- Enumerar todas las variantes y versiones de PHP del servidor, también las que no se usan.
- Comprobar el estado de los paquetes; en backports de la distribución, buscar en el changelog CVE-2026-109618 y CVE-2026-109619.
- Actualizar a 8.5.12, 8.4.27, 8.3.36 o 8.2.35, o bien al backport confirmado.
- Reiniciar PHP-FPM, Apache y LiteSpeed y controlar las horas de inicio de los procesos.
- Contraprueba con
php -r 'var_dump(ini_get("memory_hard_limit_percent"));'; según el manual,bool(false)significa una versión afectada. - Asegurar los logs y revisarlos en busca de anomalías.
Cómo demostrar de forma fiable la versión y el estado del parche lo describe Comprobar correctamente la versión de PHP y el estado del parche.
¿Cómo ayuda PHP SOS en concreto?
En el contrato de mantenimiento de seguridad asumimos el mantenimiento básico de PHP junto con su equipo:
- Inventario: todas las variantes de PHP, versiones, pools y ubicaciones de configuración de cada servidor.
- Configuración: valores relevantes para la seguridad fijados con
php_admin_value, pools separados por sitio web. - Actualizaciones: aplicación, reinicio, control y documentación en cada versión de seguridad.
- Transmitir conocimiento: explicamos a sus administradores qué hemos cambiado y por qué.
Preguntas frecuentes
¿Por qué php -v muestra una versión distinta de la del sitio web?
La línea de comandos, PHP-FPM y el módulo de Apache son programas separados, con su propia versión y su propio php.ini. php -v solo muestra la línea de comandos. Para el sitio web cuenta la versión del binario que atiende realmente las peticiones.
¿Qué php.ini rige en mi servidor?
Lo muestra php --ini para la línea de comandos. Para PHP-FPM suele haber un php.ini propio y archivos de pool adicionales. Desde PHP 8.5, php --ini=diff muestra qué valores se desvían del estándar.
¿Qué diferencia hay entre php_value y php_admin_value?
Ambos fijan ajustes en un pool de FPM. Según el manual, la aplicación no puede sobrescribir con ini_set() los valores fijados con php_admin_value. Para los ajustes relevantes para la seguridad, php_admin_value es por tanto la opción correcta.
¿Basta una actualización sin reinicio?
No. Los procesos de PHP en ejecución conservan el código antiguo en memoria. Tras una actualización hay que reiniciar PHP-FPM, Apache con mod_php o LiteSpeed; de lo contrario, la versión vulnerable sigue ejecutándose.