Apache es uno de los servidores web mas conocidos del mundo, destaca principalmente por su estabilidad, rendiemiento y un gran abanico de módulos disponibles. En este artÃculo explicaré los diferentes gestores de hilos y los diferentes modos de ejecución de código en php y las implicaciones que conlleva hacerlo de una forma u otra.
Es posible habilitar el soporte de PHP en Apache de varias maneras:
- mod_php(mejor opción para entornos mono-usuario): El modo mas rápido siempre que NO se atiendan peticiones de forma concurrente, si se comparte hosting y alguien consigue esplotar alguna vulnerabilidad todos los ficheros de todos los clientes serán vulnerables ya que los ficheros generados por Apache pertenecen al mismo usuario del sistema, si ejecuta código se ejecutará con los permisos del usuario de Apache, el interprete de php está embebido dentro de Apache por lo tanto ese binario se cargará tanto para servir contenido estático como dinámico, por lo tanto consumirá mas recursos.
- CGI: Se ejecuta el php como un software externo, cada ejecución del cgi abre y cierra el entorno de ejecución entero. Mediante este tipo de ejecución tenemos el problema de mod_php de un solo usuario para todo pero podemos utilizar el módulo suexec de Apache para que se ejecute con los permisos del propietario del cgi.
- FastCGI(mejor opción para entornos multi-usuario): El nivel de rendimiento es muy similar al de mod_php, pero consume bastante RAM.
- php-fpm(FastCGI Process Manager): Versión mejorada de fastcgi, permite recargar la config de php en caliente, reinicio de los procesos sin destruir la caché del opcode entre otras funcionalidades, no soporta suexec pero mediante varias instancias de fpm podremos ejecutar cada vhost con un usuario diferente.
NOTA: CGI vs FastCGI –> En vez de crear procesos nuevos por cada petición, FastCGI puede usar un solo proceso persistente el cual maneja cualquier petición durante su periodo de vida.
Modificaciones en la ejecución:
- SuPHP: Igual que CGI pero permite ejecutar el cgi con los permisos del propietario del cgi sin utilizar ningún módulo de Apache como suexec. Por contra consume una cantidad considerable de CPU y no se pueden utilizar sistemas de opcode caching(en cada petición se recompila el código en PHP, no cachea), debido a esta limitación se ha convertido en una opción descartable en la mayorÃa de escenarios.
- SuExec: Módulo de Apache que nos permite ejecutar php con el usuario indicado, sà que permite opcode caching, solo es compatible con la ejecución de phps mediante cgi. Suexec isn’t really required to run cgi-scripts, but it’s a really good idea if you have multiple users serving websites…
SuExec posee varios parámetros que nos permiten afinar el comportamiento de los phps:
- SUEXEC_SAFEPATH: Default PATH for suexec (default: /usr/local/bin:/usr/bin:/bin)
- SUEXEC_LOGFILE: Path to the suexec logfile (default: /var/log/Apache2/suexec_log)
- SUEXEC_CALLER: Name of the user Apache is running as (default: Apache)
- SUEXEC_DOCROOT: Directory in which suexec will run scripts (default: /var/www)
- SUEXEC_MINUID: Minimum UID, which is allowed to run scripts via suexec (default: 1000)
- SUEXEC_MINGID: Minimum GID, which is allowed to run scripts via suexec (default: 100)
- SUEXEC_USERDIR: User subdirectories (like /home/user/html) (default: public_html)
- SUEXEC_UMASK: Umask for the suexec process (default: 077)
Por ejemplo si necesitamos un determinado umask serÃa tan sencillo como definirlo en la compialción de Apache:
SUEXEC_UMASK="022"
NOTA: Mediante cgi/fastcgi se puede indicar un manejador de php-cgi diferente para cada vhost permitiendonos asà tener una versión especÃfica de php o php.ini en cada vhost.
Recursos | mod_php | CGI | FastCGI | suPHP |
---|---|---|---|---|
Memory usage | Low | Low | High | Low |
CPU Usage | Low | High | Low | High |
Security | Low | Low | High | High |
Run as file owner | Mo | No | Yes | Yes |
Overall Performance | Fast | Slow | Fast | Slow |
Además del método de ejecución de php debemos tener en cuenta el gestor de hilos de Apache( mpms ):
- worker –> Escalabilidad y concurrencia, además recomendado si se utiliza SSL. La única pega es que necesita mantener un thread por cada conexión establecida hasta que se cumpla el timeout, aunque no se genere tráfico. Arranca varios procesos y cada uno de ellos varios threads.
- prefork(default Unix) –> Estabilidad y retrocompatibilidad, adecuado cuando se utilizan librerÃas que no soportan threading(como mod_php). Arranca un nuevo proceso por petición.
- itk –> Es experimental y muy parecido a prefork, hace un chroot en cada fork, mas seguro pero mas pesado, cada vhost se ejecuta con un uid y gid determinado.
- peruser(abandonado desde el 2004) –> Cada hijo de Apache corre con su UID y GID, chrootea procesos de Apache, por contra no se recomienda utilizarlo en producción, rompe SSL y no es muy escalable.
- event –> Como worker pero un solo thread se encarga de todas las conexiones que no generan tráfico, recomendado cuando el tráfico de los clientes es puntual, es considerado inestable.
NOTA: Los únicos mpms con soporte para threads es worker/event por lo tanto si queremos ejecutar php como cgi/fastcgi no dispondremos de otra opción mas que compilar Apache con mpm –> worker ya que event es muy inestable.
Por lo tanto las opciones disponibles quedan asÃ:
MPM | Modo ejecución |
---|---|
worker | CGI/FastCGI con o sin suexec |
prefork | mod_php |
itk | mod_php |
peruser | mod_php |
event | CGI/FastCGI con o sin suexec |
Podemos ver los diferentes mpms a la hora de compilar Apache:
Apache2_MPMS="-event -itk -peruser -prefork worker"
La diferencia entre un proceso hijo (fork) y un hilo de ejecución (thread) es que los procesos no comparten ciertos recursos entre sÃ, son independientes entre sà y se comunican mediante IPC , normalmente pasando por el núcleo, mientras que los threads si comparten recursos como la memoria del proceso que los genera, un proceso multihilo genera threads y hace que compartan estos recursos y se comuniquen entre sÃ, normalmente sin pasar por el núcleo. Los threads o hilos de ejecución son más rápidos que los procesos independientes pero, la ventaja de los procesos hijo es esa, que son independientes y están aislados los unos de los otros.
NOTA: Para poder ejecutar cgi, Apache debe ser compilado con soporte para threading, el único mpm estable que lo soporta es worker, asà que:
Apache2_MPMS="worker"
Un aspecto importante a la hora de compilar Apache es decidir que funcionalidades debe soportar, de este modo además de obtener un binario mas liviando y rápido tendremos un Apache mas seguro ya que si existe alguna vulnerabilidad de un módulo que no hemos incluido no nos afectará.
Podemos ver la lista completa de módulos a la hora de compilar:
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgi cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias -asis -auth_digest -authn_dbd -cern_meta -charset_lite -dbd -dumpio -ident -imagemap -log_forensic -proxy -proxy_ajp -proxy_balancer -proxy_connect -proxy_ftp -proxy_http -proxy_scgi -reqtimeout -substitute -version"
NOTA: Según el tipo de mpm que vayamos a utilizar deberemos compilar Apache con diferentes opciones.
En la propia compilación de Apache emerge ya nos advierte:
Attention: cgi and cgid modules are now handled via Apache2_MODULES flags in make.conf. Make sure to enable those in order to compile them.
In general, you should use 'cgid' with threaded MPMs and 'cgi' otherwise.
Si el mpm soporta threading:
www-servers/Apache threads
Apache2_MODULES="... cgid ..."
dev-lang/php cgi gd sockets mysql mysqli threads
Si no lo soporta:
www-servers/Apache -threads
Apache2_MODULES="... cgi ..."
dev-lang/php Apache2 gd sockets mysql mysqli -threads
En mis pruebas he optado por abandonar métodos obsoletos o inestables, por lo tanto se van a chequear:
- Apache prefork - mod_php:
- Apache ITK - mod_php:
- Apache worker-cgi:
- Apache worker-cgi y suexec:
- Apache worker-fastcgi:
- Apache worker-fastcgi-multiinstancia:
Apache prefork - mod_php:
Apache2_MPMS="prefork"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
www-servers/Apache -threads
Si indicamos un mpm que no soporta threads como es el caso de prefork, pero intentamos compilar Apache con la use flag de threads nos aparecerá el siguiente error:
You have selected a non-threaded MPM but USE=threads is enabled
dev-lang/php Apache2 gd sockets mysql mysqli -threads
NOTA: El parámetro que indica que los phps se ejecutarán con mod_php es la use Apache2
Compilamos Apache:
Compilamos php:
Indicamos a Apache que debe utilizar el módulo interno:
Apache2_OPTS="............ -D PHP5"
Configuramos el vhost:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/WEB
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
<Directory "/var/www/WEB">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
Reiniciamos el servicio:
Podemos comprobar como Apache está siendo ejecutado por el usuario Apache:
<?php system('whoami'); ?>
NOTA: Todos los vhosts configurados correrrán con este mismo user, asà que una vulnerabilidad en una de las aplicaciones web puede afectar a los demás vhosts!!
Un usuario malicioso podrÃa hacer algo de este estilo:
<?php
system("cp /var/www/users/victim/public_html/blog/wp-config.php /var/www/users/pwnerer/hohoho.txt");
?>
Eliminamos el fichero:
Apache ITK - mod_php:
Apache2_MPMS="itk"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
Compilamos Apache:
Configuramos el vhost:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/WEB
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
AssignUserId USER USER
<Directory "/var/www/WEB">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
Indicamos a Apache que debe utilizar el módulo interno:
Apache2_OPTS="............ -D PHP5"
chown -R USER:USER /var/www/WEB
Reiniciamos el servicio:
Una forma de comprobar que el php se está ejecutando con el usuario correcto es mediante este sencillo php:
<?php system('whoami'); ?>
DeberÃa de responder con el nombre del usuario con el que configurásteis el vhost.
Eliminamos el fichero:
Apache worker-cgi:
Para poder ejecutar php con un cgi externo necesitamos un mpm con soporte para threads(worker).
Apache2_MPMS="worker"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
Compilamos Apache con soporte para threads:
www-servers/Apache threads
Compilamos php con soporte para la ejecución a través de cgi:
dev-lang/php berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite3 ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads cgi
Compilamos Apache y php:
Configuramos Apache para que utilice cgi y suexec:
Apache2_OPTS=".... -D CGI"
Creamos el directorio donde estará el interprete de php y en caso de ser necesario el php.ini:
find / -iname php-cgi
cp /usr/bin/php-cgi /var/www/html/cgi-bin/WEB/
chown -R Apache:Apache /var/www/html/cgi-bin/WEB
Configuramos el vhost indicando que debe hacer cuando se le solicite un fichero php:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/WEB
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
ScriptAlias /local-bin /var/www/html/cgi-bin/WEB
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-cgi
<Directory "/var/www/html/cgi-bin/WEB">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/WEB">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
Configuramos Apache para que cargue el módulo cgi:
#LoadModule cgi_module modules/mod_cgi.so
<IfDefine CGI>
LoadModule cgid_module modules/mod_cgid.so
</IfDefine
Reiniciamos el servicio:
Una forma de comprobar que el php se está ejecutando con el usuario correcto es mediante este sencillo php:
<?php system('whoami'); ?>
Esto deberÃa de responder:
Apache
Apache worker-cgi y suexec:
Para poder ejecutar php con un cgi externo necesitamos un mpm con soporte para threads(worker).
Apache2_MPMS="worker"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
Compilamos Apache con soporte para threads:
www-servers/Apache threads suexec
Compilamos php con soporte para la ejecución a través de cgi:
dev-lang/php berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite3 ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads cgi
Compilamos Apache y php:
Configuramos Apache para que utilice cgi y suexec:
Apache2_OPTS=".... -D SUEXEC -D CGI"
Creamos el directorio donde estará el interprete de php y en caso de ser necesario el php.ini:
cp /usr/bin/php-cgi /var/www/html/cgi-bin/WEB/
useradd USER
chown -R USER:USER /var/www/html/cgi-bin/WEB
Configuramos el vhost indicando que debe hacer cuando se le solicite un fichero php:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/WEB
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
SuexecUserGroup USER USER
ScriptAlias /local-bin /var/www/html/cgi-bin/WEB
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-cgi
<Directory "/var/www/html/cgi-bin/WEB">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/WEB">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
Configuramos Apache para que cargue el módulo cgi:
#LoadModule cgi_module modules/mod_cgi.so
<IfDefine CGI>
LoadModule cgid_module modules/mod_cgid.so
</IfDefine
Reiniciamos el servicio:
Una forma de comprobar que el php se está ejecutando con el usuario correcto es mediante este sencillo php:
<?php system('whoami'); ?>
Esto deberÃa de responder con el nombre del usuario configurado en el vhost.
Apache worker-fastcgi:
Para poder ejecutar php con un cgi externo necesitamos un mpm con soporte para threads(worker).
Apache2_MPMS="worker"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
Compilamos Apache con soporte para threads:
www-servers/Apache threads
Compilamos php con soporte para la ejecución a través de fastcgi:
dev-lang/php berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite3 ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads fpm cgi
Compilamos Apache, php y el módulo de fastcgi para Apache:
Configuramos Apache para que utilice fastcgi:
Apache2_OPTS=".... -D FASTCGI"
LoadModule fastcgi_module modules/mod_fastcgi.so
<IfDefine FASTCGI>
AddHandler fastcgi-script fcg fcgi fpl
</IfDefine>
Creamos el directorio donde estará el interprete de php con soporte para fastcgi y en caso de ser necesario el php.ini:
find / -iname php-fpm
cp /usr/bin/php-fpm /var/www/html/cgi-bin/WEB/
chown -R Apache:Apache /var/www/html/cgi-bin/WEB
Configuramos el vhost indicando que debe hacer cuando se le solicite un fichero php:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/WEB
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
ScriptAlias /local-bin /var/www/html/cgi-bin/WEB
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-fpm
FastCgiExternalServer /var/www/html/cgi-bin/WEB/php-fpm -socket /var/run/php-fpm.sock
<Directory "/var/www/html/cgi-bin/WEB">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/WEB">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
</VirtualHost>
listen = /var/run/php-fpm.sock
listen.owner = Apache
listen.group = Apache
user = Apache
group = Apache
En caso de ser necesario modificamos el umask:
start-stop-daemon --umask 0002 --start --pidfile ${PHP_FPM_PID} --exec /usr/lib/${PHPSLOT}/bin/php-fpm -- -y "${PHP_FPM_CONF}" -g "${PHP_FPM_PID}"
NOTA: Mediante socket Unix además de ganar en redimiento también lo haremos en seguridad ya que solo se permitirá conexiones desde la máquina local.
Reiniciamos el servicio:
/etc/init.d/php-fpm restart
Una forma de comprobar que el php se está ejecutando con el usuario correcto es mediante este sencillo php:
<?php system('whoami'); ?>
Esto deberÃa de responder el usuario con el que hemos configurado php-fpm, en mi caso nobody.
Apache worker-fastcgi-multiinstancia:
La configuración es muy similar a la anterior pero en este caso lanzaremos varias instancias de php-fpm de este modo cada una de ellas correrá con un usuario distinto.
Apache2_MPMS="worker"
Apache2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias"
Compilamos Apache con soporte para threads:
www-servers/Apache threads
Compilamos php con soporte para la ejecución a través de fastcgi:
dev-lang/php berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite3 ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads fpm cgi
Compilamos Apache, php y el módulo de fastcgi para Apache:
Configuramos Apache para que utilice fastcgi:
Apache2_OPTS=".... -D FASTCGI"
LoadModule fastcgi_module modules/mod_fastcgi.so
<IfDefine FASTCGI>
AddHandler fastcgi-script fcg fcgi fpl
</IfDefine>
Creamos el directorio donde estará el interprete de php con soporte para fastcgi y en caso de ser necesario el php.ini:
useradd user00
mkdir -p /var/www/html/cgi-bin/user00
find / -iname php-fpm
cp /usr/bin/php-fpm /var/www/html/cgi-bin/user00/
chown -R user00:user00 /var/www/html/cgi-bin/user00
mkdir -p /var/www/user00
chown -R user00:user00 /var/www/user00
useradd user01
mkdir -p /var/www/html/cgi-bin/user01
find / -iname php-fpm
cp /usr/bin/php-fpm /var/www/html/cgi-bin/user01/
chown -R user01:user01 /var/www/html/cgi-bin/user01
mkdir -p /var/www/user01
chown -R user01:user01 /var/www/user01
Configuramos el vhost indicando que debe hacer cuando se le solicite un fichero php:
Listen 80
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/user00
ServerName alfaexploit.com
ServerAlias www.alfaexploit.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
ScriptAlias /local-bin /var/www/html/cgi-bin/user00
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-fpm
FastCgiExternalServer /var/www/html/cgi-bin/user00/php-fpm -socket /var/run/php-fpm_user00.sock
<Directory "/var/www/html/cgi-bin/user00">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/user00">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
# Monitoring status:
<LocationMatch "/(ping|status)">
SetHandler php-fastcgi-virt
Action php-fastcgi-virt /local-bin/php-fpm virtual
</LocationMatch>
</VirtualHost>
<VirtualHost *:80>
ServerAdmin kr0m@alfaexploit.com
DocumentRoot /var/www/user01
ServerName alfaexploit2.com
ServerAlias www.alfaexploit2.com
ErrorLog /var/log/apache2/alfaexploit.error_log
CustomLog /var/log/apache2/alfaexploit.access_log combined
DirectoryIndex index.php index.htm index.html
ScriptAlias /local-bin /var/www/html/cgi-bin/user01
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-fpm
FastCgiExternalServer /var/www/html/cgi-bin/user01/php-fpm -socket /var/run/php-fpm_user01.sock
<Directory "/var/www/html/cgi-bin/user01">
Options -Indexes ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/user01">
options -Indexes FollowSymLinks
AllowOverride All
order allow,deny
Allow from all
</Directory>
# Monitoring status:
<LocationMatch "/(ping|status)">
SetHandler php-fastcgi-virt
Action php-fastcgi-virt /local-bin/php-fpm virtual
</LocationMatch>
</VirtualHost>
[global]
error_log = /var/log/php-fpm.log
include=/etc/php/fpm-php5.5/pool.d/*.conf
Configuramos los pools FPM:
[user00]
user = user00
group = user00
listen = /var/run/php5-fpm_user00.sock
listen.owner = Apache
listen.group = Apache
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /status
ping.path = /ping
ping.response = pong
[user01]
user = user01
group = user01
listen = /var/run/php5-fpm_user01.sock
listen.owner = Apache
listen.group = Apache
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /status
ping.path = /ping
ping.response = pong
En caso de ser necesario modificamos el umask:
start-stop-daemon --umask 0002 --start --pidfile ${PHP_FPM_PID} --exec /usr/lib/${PHPSLOT}/bin/php-fpm -- -y "${PHP_FPM_CONF}" -g "${PHP_FPM_PID}"
Reiniciamos el servicio:
/etc/init.d/php-fpm restart
Una forma de comprobar que el php se está ejecutando con el usuario correcto es mediante este sencillo php:
<?php system('whoami'); ?>
<?php system('whoami'); ?>
Esto deberÃa de responder el usuario con el que hemos configurado en cada instancia php-fpm.
FPM nos proporciona cierta información de cada uno de los pools:
URL/ping
Con esto ya tendrÃamos los diferentes modos de configuración de Apache, sus MPMs y sus formas de ejecución de PHP, en cada escenario se han realizado unas pruebas orientativas sobre rendimiento en cada escenario, se debe tener en cuenta que el servidor Apache ha sido instalado y testado en un portátil con las X arrancadas, firefox con diversas pestañas y varias aplicaciones de escritorio.
Los benchmarks se han realizado sobre un core 2 duo a 2.26GHz con 4Gb de RAM y el software empleado para las pruebas ha sido Apache benchmark:
Para plotear se ha optado por gnuplot:
sci-visualization/gnuplot X cairo gd qt4 readline wxwidgets -aqua bitmap -doc -examples -ggi -latex -lua plotutils svga -thin-splines
Generamos los ficheros de gráficas:
gnuplot> set output “NAME.png”
gnuplot> plot “NAME.csv” using 7 w lines title ‘CTime’, “NAME.csv” using 8 w lines title ‘DTime’, “NAME.csv” using 9 w lines title ‘TTime’, “NAME.csv” using 10 w lines title ‘Wait’
Estos son los resultados:
itk_modphp | prefork_modphp | worker_cgi |
---|---|---|
worker_cgi_suexec | worker_fastcgi | comparativa |
---|---|---|
Como podemos observar la combinación que mas estable permanece cuando hay varias peticiones simultáneas es la que utiliza fast-cgi.