Opción: Configurar PHP como CGI

El módulo de PHP de Apache funciona muy bien como configuración por defecto y es muy fácil de instalar. Pero tiene algunos inconvenientes:

  • El módulo de PHP de Apache tiene que cargarse en cada petición, por lo tanto el uso de memoria RAM es más alto
  • El módulo Prefork utiliza más CPU y RAM que Worker

Así que, seremos capaces de atender más peticiones con menos recursos. Aunque puede que tengamos problemas con algunos módulos o configuraciones como APC, o el número de conexiones mysql abiertas (se incrementará porque el número de peticiones concurrentes será por hilo), aunque notaremos la diferencia.

Lo primero, como digo en todas las páginas de esta serie de tutoriales, es que todo esto está probado con Ubuntu Server 12.04, así que puede que algunas cosas varíen en otros sabores de Linux, aunque lo importante es siempre igual. Puede que me veas utilizar apt-get para instalar paquetes y sudo para ejecutar cosas como root, eso deberás adaptarlo a tu distribución. También el nombre de los paquetes puede que cambie, aunque seguro que son parecidos

Instalación

Tenemos que instalar el MPM Worker, el módulo Fcgid y php-cgi, así que:

$ sudo apt-get install apache2-mpm-worker libapache2-mod-fcgis php5-cgi php-apc

Si tenemos la instalación de PHP hecha como módulo de Apache, nos dirá que debe eliminar libapache2-mod-php5 o apache-mpm-prefork.

Activar FCGId y configurar PHP

El siguiente paso es activar mod_fcgid:

$ sudo a2enmod fcgid

Tras ello, debemos crear un script de envolvente (wrapper script) donde colocaremos la configuración básica para lanzar los procesos CGI. El archivo lo podemos colocar en /usr/bin, /usr/local/bin o incluso dentro de nuestro document root (aunque no te lo recomiendo, pero lo podemos colocar en un nivel o directorio anterior). En el ejemplo, el archivo lo colocaré en /usr/local/bin/php-wrapper y tiene este contenido:

#!/bin/sh

PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS
PHP_FCGI_CHILDREN=5
export PHP_FCGI_CHILDREN

exec /usr/lib/cgi-bin/php5-cgi -d apc.shm_size=50M

La última parte: «-d apc.shm_size=50M» es para utilizar un caché de opcodes por usuario de 50Mb. Lo podemos cambiar para ajustar nuestra configuración dependiendo de la memoria de nuestro servidor o del uso que hagamos de APC.
También definimos PHP_FCGI_MAX_REQUESTS que es el número de peticiones antes de que se reinicien los procesos hijo (cada hijo podrá atender a varios clientes), pero es buena idea reiniciar de vez en cuando los procesos para limpiar fugas de memoria (memory leaks), que pueden ser causadas por fallos en PHP o por algunos scripts mal costruidos (eso nos pasa a todos).
PHP_FCGI_CHILDREN es el número de hijos que esta instancia va a lanzar. Depende de los recursos de nuestro sistema, podemos incrementar este número dependiendo de la CPU y RAM que tengamos disponible y a medida que aumentemos el número podremos atender a más clientes a la vez.
/usr/bin/php-fcgi es nuestro ejecutable de php actuando como cgi, puede que lo tengas en esa ruta o puede que no, si es así, búscalo con locate o find.

Ahora, debemos decirle a Apache que use esta configuración. Para ello, en los archivos de configuración de nuestro VirtualHost (en el ejemplo era /etc/apache2/sites-available/totaki.com, debemos insertar los siguientes cambios (en negrita):

<VirtualHost *:80>
        ServerAdmin info@totaki.com
        ServerName totaki.com
        ServerAlias www.totaki.com
        DocumentRoot /home/cloud/www/totaki.com/www
        <Ifmodule mod_fcgid.c>
                # See /etc/apache2/mods-available/fcgid.conf for (fcgid-script)
                AddHandler fcgid-script .php .php5 .phtml
                FcgidWrapper /usr/local/bin/php-wrapper .php
                FcgidWrapper /usr/local/bin/php-wrapper .php5
                FcgidWrapper /usr/local/bin/php-wrapper .phtml
        </IfModule>
<Directory />
                Options FollowSymLinks
                AllowOverride All</Directory>
<Directory /home/cloud/www/totaki.com/www/>
                Options FollowSymLinks MultiViews +ExecCGI
                AllowOverride All
                Order allow,deny
                allow from all</Directory>
        ErrorLog    "/home/cloud/www/totaki.com/logs/error.log"
        LogLevel warn
        CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined</VirtualHost>

Ahora, sólo nos queda reiniciar el servidor. Crearemos un script sencillo para verificar que estamos funcionando com PHP-CGI, y accederemos a la dirección donde colocamos el script:

<?php phpinfo(); ?>

Screenshot 21-03-2014-070318

Un php.ini personalizado para cada Virtualhost

Con esta configuración no podemos utilizar php_value en .htaccess para modificar la configuración de php para un directorio en especial. Pero podemos configurar un archivo php.ini diferente para cada virtualhost defniendo la directiva PHPRC en la configuración de nuestro VirtualHost dentro de nuestro script envolvente de PHP. En este ejemplo, ésta es la configuración que he utilizado para el VirtualHost:

<VirtualHost *:80>
        ServerAdmin info@totaki.com
        ServerName totaki.com
        ServerAlias www.totaki.com
        DocumentRoot /home/cloud/www/totaki.com/www
        <Ifmodule mod_fcgid.c>
                # See /etc/apache2/mods-available/fcgid.conf for (fcgid-script)
                AddHandler fcgid-script .php .php5 .phtml
                FcgidInitialEnv PHPRC "/home/cloud/www/totaki.com/php/"
                FcgidWrapper /usr/local/bin/php-wrapper .php
                FcgidWrapper /usr/local/bin/php-wrapper .php5
                FcgidWrapper /usr/local/bin/php-wrapper .phtml
        </IfModule>
        <Directory />
                Options FollowSymLinks
                AllowOverride All
         </Directory>
    <Directory /home/cloud/www/totaki.com/www/>
                Options FollowSymLinks MultiViews +ExecCGI
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>
        ErrorLog    "/home/cloud/www/totaki.com/logs/error.log"
        LogLevel warn
        CustomLog "/home/cloud/www/totaki.com/logs/access.log" combined
</VirtualHost>

Ahora, colocamos un fichero php.ini en /home/cloud/www/totaki.com/www. Recuerda que cada VirtualHost puede tener una configuración PHPRC diferente, siempre que tengan un ServerName diferente.

Configuración CGI a nivel de sistema

Se recomienda tener parte de la configuración fuera de la configuración del VirtualHost. Podemos ver todos los parámetros que podemos tocar de Fcgid aquí, pero pondré algo más abajo los que uso más frecuentemente. Algunos de estos parámetros pueden ser también definidos dentro del VirtualHost. De todas formas, voy a crear /etc/apache2/conf.d/cgisettings.conf:

<IfModule mod_fcgid.c>
        FcgidBusyScanInterval 10
        FcgidMaxProcesses 20
        FcgidMaxRequestLen 1073741824
</IfModule>

Aquí vemos:

  • FcgidBusyScanInterval: es el intervalo en el que el proceso buscará hijos ocupados.
  • FcgidMaxProccesses: es el número total de procesos CGI a lanzar
  • FcgidMaxRequestLen: es el tamaño total de la petición. Es útil si en tu aplicación soportas subida de ficheros. Antiguamente, por defecto, aquí había un valor alto, pero ahora no, por lo que tendremos que aumentarlo a meno.

Podemos además definir la directiva FcgidMaxProcessesPerClass que define el número máximo de procesos que puede lanzar cada VirtualHost.

Advertencia con Shellshock bug

Hace un tiempo saltó la alerta del bug ShellShock, puede ser letal para nosotros y es muy fácilmente explotable si utilizamos esta configuración en nuestro servidor. Por tanto, asegúrate de terner instalada la última versión de bash.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *