Otro enfoque para la configuración de Apache + PHP es usar el nuevo PHP-FPM (FPM siglas para FastCGI Process Manager), gestiona los procesos de PHP lanzados en su propio servidor (fuera de Apache) lo que te permite hacer algunas cosas interesantes:
- Mejor control de procesos (mínimo y máximo número de procesos y procesos de control disponibles)
- Mejor gestión de plugins PHP como APC frente a mod_php
- chrooting (enjaulado), por lo que podemos aislar aplicaciones o hosts virtuales.
- Ejecutar procesos con un uid/gid específico (esto se podría hacer con el módulo de apache suExec)
- Mejor rendimiento, en mis pruebas, se ejecuta un 10% más rápido que CGI.
- Etc.
No podemos usar mod_fcgid (como lo hicimos desde el enfoque CGI), porque no podemos conectarnos a cualquier servidor externo FastCGI, por ello, utilizaremos mod_fastcgi (un poco más antiguo pero útil). En Apache 2.4 podríamos utilizar el nuevo mod_proxy_fcgi.
Contents
Instalación de mod_fastcgi (Apache 2.2) y php-fpm
Si usamos una distribución Debian/Ubuntu:
$ sudo apt-get install php5-fpm libapache2-mod-fastcgi
Configuración de Apache 2.2
Lo primero que debemos hacer es habilitar el módulo:
$ sudo a2enmod fastcgi
También tendremos que habilitar el módulo de acciones (si no está ya habilitado):
$ sudo a2enmod actions
Tendremos que crear un archivo de configuración de php-FPM para Apache, como el siguiente (/etc/apache2/conf.d/php-fpm.conf):
<IfModule mod_fastcgi.c> Alias /php5-fpm-cgi /usr/lib/cgi-bin/php5-fcgi FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php-fpm.sock -pass-header Authorization </IfModule>
Ahora, vamos a editar nuestra configuración del VirtualHost (he tomado el ejemplo que se encuentra en el documento de Instalación y configuración de un servidor web, y he resaltado los cambios en negrita):
<VirtualHost *:80> ServerAdmin info@totaki.com ServerName totaki.com ServerAlias www.totaki.com DocumentRoot /home/cloud/www/totaki.com/www <Directory /> Options FollowSymLinks AllowOverride All </Directory> <Directory /home/cloud/www/totaki.com/www/> Options FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Directory> <IfModule mod_fastcgi.c> <FilesMatch ".+\.ph(p[345]?|t|tml)$"> SetHandler application/x-httpd-php </FilesMatch> Action application/x-httpd-php /php5-fpm-cgi </IfModule> ErrorLog "/home/cloud/www/totaki.com/logs/error.log" LogLevel warn CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined </VirtualHost>
Esto también se puede hacer de modo que afecte a todo el servidor con tan solo poner un nuevo archivo /etc/apache2/conf.d/, pero he preferido hacerlo a través de un VirtualHost para lograr un mayor control.
Utilizaremos el servidor cgi en el socket /var/run/php-ftm.sock (podemos configurar un servidor remoto, para distribuir la carga, preferiblemente en el mismo datacenter, podríamos acceder a través de LAN, por lo que será más rápido), pero cuando se configura en la misma máquina se ejecutará sin problemas como un socket UNIX.
Configuración en Apache 2.4
En esta nueva versión de Apache, hay ocasiones en las que mod_fcgi no se puede instalar en nuestros servidores, por lo que debemos usar otro módulo como mod_proxy_fcgi. Esto nos ofrece una gran cantidad de novedades interesantes que podemos utilizar.
En versiones anteriores a Apache 2.4.4 sólo podemos usarlo con PHP-FPM escuchando en un puerto (no en un socket de UNIX). Podemos editar nuestro VirtualHost de la siguiente manera:
<VirtualHost *:80> ServerAdmin info@totaki.com ServerName totaki.com ServerAlias www.totaki.com DocumentRoot /home/cloud/www/totaki.com/www ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/home/cloud/www/totaki.com/www/$1 <Directory /> Options FollowSymLinks AllowOverride All </Directory> <Directory /home/cloud/www/totaki.com/www/> Options FollowSymLinks MultiViews AllowOverride All Require all grantes </Directory> ErrorLog "/home/cloud/www/totaki.com/logs/error.log" LogLevel warn CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined </VirtualHost>
Y eso es todo. Lo peor es que hay que especificar la ruta complete en cada VirtualHost. Pero hay ciertas cosas importantes que podemos hacer como usar un equilibrador de carga para ese proxy, o hacer una configuración global en las últimas versiones. Más información aquí.
Configurando PHP-FPM
Tenemos que editar /etc/php5/fpm/pool.d/www.conf para cambiar algunos ajustes. Las opciones del servidor para el número de procesos pueden depender del conjunto CPU+RAM de tu servidor, por lo que puedes ajustarlo más tarde.
El archivo más o menos sería como el siguiente (he marcado los cambios en negrita):
; Start a new pool named 'www'. ; the variable $pool can we used in any directive and will be replaced by the ; pool name ('www' here) [www] ; Per pool prefix ; It only applies on the following directives: ; - 'slowlog' ; - 'listen' (unixsocket) ; - 'chroot' ; - 'chdir' ; - 'php_values' ; - 'php_admin_values' ; When not set, the global prefix (or /usr) applies instead. ; Note: This directive can also be relative to the global prefix. ; Default Value: none ;prefix = /path/to/pools/$pool ; Unix user/group of processes ; Note: The user is mandatory. If the group is not set, the default user's group ; will be used. user = www-data group = www-data ; The address on which to accept FastCGI requests. ; Valid syntaxes are: ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on ; a specific port; ; 'port' - to listen on a TCP socket to all addresses on a ; specific port; ; '/path/to/unix/socket' - to listen on a unix socket. ; Note: This value is mandatory. ;listen = 127.0.0.1:9000 listen = /var/run/php-fpm.sock ; Set listen(2) backlog. A value of '-1' means unlimited. ; Default Value: 128 (-1 on FreeBSD and OpenBSD) ;listen.backlog = -1 ; Set permissions for unix socket, if one is used. In Linux, read/write ; permissions must be set in order to allow connections from a web server. Many ; BSD-derived systems allow connections regardless of permissions. ; Default Values: user and group are set as the running user ; mode is set to 0666 listen.owner = www-data listen.group = www-data ;listen.mode = 0666 ; List of ipv4 addresses of FastCGI clients which are allowed to connect. ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address ; must be separated by a comma. If this value is left blank, connections will be ; accepted from any ip address. ; Default Value: any ;listen.allowed_clients = 127.0.0.1 ; Choose how the process manager will control the number of child processes. ; Possible Values: ; static - a fixed number (pm.max_children) of child processes; ; dynamic - the number of child processes are set dynamically based on the ; following directives. With this process management, there will be ; always at least 1 children. ; pm.max_children - the maximum number of children that can ; be alive at the same time. ; pm.start_servers - the number of children created on startup. ; pm.min_spare_servers - the minimum number of children in 'idle' ; state (waiting to process). If the number ; of 'idle' processes is less than this ; number then some children will be created. ; pm.max_spare_servers - the maximum number of children in 'idle' ; state (waiting to process). If the number ; of 'idle' processes is greater than this ; number then some children will be killed. ; ondemand - no children are created at startup. Children will be forked when ; new requests will connect. The following parameter are used: ; pm.max_children - the maximum number of children that ; can be alive at the same time. ; pm.process_idle_timeout - The number of seconds after which ; an idle process will be killed. ; Note: This value is mandatory. pm = dynamic ; The number of child processes to be created when pm is set to 'static' and the ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. ; This value sets the limit on the number of simultaneous requests that will be ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP ; CGI. The below defaults are based on a server without much resources. Don't ; forget to tweak pm.* to fit your needs. ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' ; Note: This value is mandatory. pm.max_children = 50 ; The number of child processes created on startup. ; Note: Used only when pm is set to 'dynamic' ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 pm.start_servers = 30 ; The desired minimum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' pm.min_spare_servers = 20 ; The desired maximum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' pm.max_spare_servers = 40 ; The number of seconds after which an idle process will be killed. ; Note: Used only when pm is set to 'ondemand' ; Default Value: 10s ;pm.process_idle_timeout = 10s; ; The number of requests each child process should execute before respawning. ; This can be useful to work around memory leaks in 3rd party libraries. For ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. ; Default Value: 0 pm.max_requests = 10000
… El resto del archivo se mantiene sin cambios (el mío estaba todo comentado), pero vale la pena decir que puedes tener un log de scripts lentos mostrando la traza inversa de los mismos y podemos cambiar las opciones php.ini desde este archivo. Ahora, todo lo que tienes que hacer es reiniciar el demonio php5-fpm:
$ sudo service php5-fpm restart
y Apache:
$ sudo service php5-fpm restart
Habilitar ping y status de FPM
Podemos solicitar el ping y el status del demonio FPM añadiendo unas pocas líneas de código. Primero, en /etc/php5/fpm/pool.d/www.conf, añadimos o quitamos el comentario de las siguientes líneas:
pm.status_path = /status ping.path = /ping ;ping.response = pong
La última línea, puede ser una palabra como respuesta a una señal de ping.
Por lo tanto, en nuestro archivo VirtualHost, añadimos lo siguiente:
<FilesMatch "^(ping|status)$"> SetHandler application/x-httpd-php Action application/x-httpd-php /php5-fpm-cgi virtual </FilesMatch>
En este caso, FilesMatch solamente trabajará cuando la URL termine con la palabra ping o status (se puede usar también LocationMatch “/status” y LocationMatch “/ping” en su lugar. La línea de acción permitirá pasar al demonio CGI un archivo no existente (dado que tenemos que definir una palabra clave virtual).
Recuerda asegurarlo, o la gente tendrá acceso a estas dos URLs, podemos utilizar lo siguiente:
<FilesMatch "^(ping|status)$"> SetHandler application/x-httpd-php Action application/x-httpd-php /php5-fpm-cgi virtual Order deny,allow Deny from all Allow from [my-ip] </FilesMatch>
Donde [my-ip] es tu dirección IP pública (o quizás 127.0.0.1 para un ping local).
Crear pools para diferentes configuraciones php-fpm
Si quieres crear una nueva configuración FPM para unVirtualHost diferente para restringir parámetros, cambia el usuario o aíslalo, simplemente editando la configuración de apache php-fpm (/etc/apache2/conf.d/php-fpm.conf) (usando negrita para nuevos ajustes):
<IfModule mod_fastcgi.c> Alias /php5-fpm-cgi /usr/lib/cgi-bin/php5-fcgi FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php-fpm.sock -pass-header Authorization Alias /php5-fpm-heavy-cgi /usr/lib/cgi-bin/php5-hfcgi FastCgiExternalServer /usr/lib/cgi-bin/php5-hfcgi -socket /var/run/php-fpm2.sock -pass-header Authorization </IfModule>
En este caso, estamos creando otro Alias llamado /php5-fpm-heavy-cgi donde pondremos la configuración para sitios de carga pesada (lanzar menos procesos hijos, por ejemplo), nótese que estoy usando /var/run/php-fpm2.sock, por lo que voy a crear una nueva configuración de pool, copiando primeramente la ya existente:
$ sudo cp /etc/php/fpm/pool.d/www.conf /etc/php/fpm/pool.d/heavy_www.conf
y entonces, editamos el archivo. Lo más importante es cambiar la línea con [www] a otra cosa, como una forma de nombrar nuestro nuevo pool, entonces cambia el valor bajo listen a /var/run/php-fpm2.sock, luego puedes cambiar lo que desees.
El último aspecto es usar la nueva configuración en un VirtualHost, simplemente cambiando
Action application/x-httpd-php /php5-fpm-cgi
por
Action application/x-httpd-php /php5-fpm-heavy-cgi
Deja un comentario