En este artículo voy a explicar detalladamente cómo compilar, instalar y configurar un servidor PHP FastCGI Process Manager (FPM) versión 7, desde sus fuentes. Incluyendo los cambios necesarios en la configuración de un sitio Joomla! para que funcione correctamente con PHP 7.

Tal como algun@s tal vez sepan, este blog está basado en una instalación de Joomla! (mi CMS favorito por diversas razones que no vienen al caso). La cuestión es que, luego de la última actualización de Joomla!, me encontré con este mensaje de error:

Más que un error se trata de una advertencia que indica que la versión de PHP instalada en el servidor es obsoleta, y se recomienda actualizar como mínimo a PHP 5.6. Por supuesto este "error" no afecta en lo más mínimo al funcionamiento del sitio, sino que es una advertencia de seguridad. Pero como tal, no merece ser ignorada.

Las alternativas para actualizar la versión de PHP en el servidor eran pocas: actualizar el sistema operativo (Debian), tratar de obtener una versión superior desde los backports, o compilar la última versión estable de PHP (7). Como el servidor corre sobre sobre un contenedor OpenVZ, no es posible encarar una migración de SO (más bien se debe comenzar con una instancia nueva). Por otro lado, en los backports de Wheezy no existe una versión superior de PHP. Entonces la alternativa más simple fue compilar PHP desde los fuentes. Y por qué no actualizar a PHP 7, la última y más importante versión de PHP desde PHP 5.6, la cual promete mejoras notables de rendimiento y consumo de memoria, gracias al nuevo Zend Engine 3.0.

Manos a la obra pues.

Compilar PHP 7 desde los fuentes

Para comenzar, descargar los fuentes de la última versión estable de PHP disponible en el sitio Web oficial:

root@linuxito:~# wget http://php.net/get/php-7.1.7.tar.gz/from/this/mirror -O php-7.1.7.tar.gz

Descomprimir el contenido del paquete y cambiar al directorio extraído:

root@linuxito:~# tar -xzf php-7.1.7.tar.gz
root@linuxito:~# cd php-7.1.7

El primer paso en toda compilación es configurar el paquete. PHP tiene cientos de opciones de configuración, por lo que es necesario revisar detenida y cuidadosamente cada una de ellas (con alguna ayuda de Google quizás, para entender bien de qué se trata cada una). Para listar todas las opciones disponibles ejecutar:

./configure --help

Las opciones de configuración dependen de cada instalación, sistema operativo, servicios disponibles y software al que dará soporte PHP. En mi caso decidí instalar PHP 7 en el directorio /usr/local/php7 (para que toda la instalación quede contenida en un único directorio) y necesito soporte para bases de datos MySQL y por supuesto el servidor FastCGI. El resto de las opciones son más o menos genéricas de toda instalación de FPM.

Respecto al directorio de instalación es mejor (más recomendable para simplificar los updates) utilizar un directorio cuyo nombre contenga la versión completa, por ejemplo /usr/local/php-7.1.7 y luego utilizar un enlace simbólico llamado /usr/local/php. De esta forma diferentes versiones de PHP pueden convivir en el mismo servidor, y al momento de actualizar la versión sólo basta con cambiar el target del enlace simbólico. En este esquema, el script de inicio de servicio System V para FPM debe ser un enlace simbólico al script dentro de /usr/local/php/.

Para no perder todas las opciones decidí guardarlas en un pequeño script Bash:

root@linuxito:~/php-7.1.7# nano configure.sh
#!/bin/bash

./configure --prefix=/usr/local/php7/ \
--disable-cli \
--enable-fpm \
--with-fpm-user=www-data \
--with-fpm-group=www-data \
--disable-ipv6 \
--with-openssl \
--with-pcre-regex \
--with-pcre-jit \
--with-zlib \
--enable-bcmath \
--with-bz2 \
--with-curl \
--enable-calendar \
--enable-exif \
--enable-ftp \
--with-gd \
--enable-gd-native-ttf \
--with-gettext \
--with-mhash \
--enable-intl \
--enable-mbstring \
--with-mcrypt \
--with-mysqli \
--enable-pcntl \
--with-pdo-mysql \
--with-readline \
--enable-sockets \
--enable-zip

De esta forma, al momento de actualizar sólo se debe correr el script dentro del nuevo paquete.

Otorgar permisos de ejecución al script:

root@linuxito:~/php-7.1.7# chmod +x configure.sh

Correr el script de configuración hasta satisfacer todos los requerimientos:

root@linuxito:~/php-7.1.7# ./configure.sh

En el caso de Debian 7 tuve que instalar algunas librerías necesarias para compilar y realizar algunas modificaciones adicionales.

root@linuxito:~/php-7.1.7# apt-get install libxml2-dev libbz2-dev libcurl4-gnutls-dev libpng-dev libicu-dev libmcrypt-dev libreadline-dev
root@linuxito:~/php-7.1.7# ln -s /usr/lib/x86_64-linux-gnu/libssl.a /usr/lib

Una vez configurado con éxito, compilar:

root@linuxito:~/php-7.1.7# make

Luego de un tiempo finaliza la compilación de PHP y es posible instalarlo en su ubicación definitiva:

root@linuxito:~/php-7.1.7# make install
Installing shared extensions:     /usr/local/php7/lib/php/extensions/no-debug-non-zts-20160303/
Installing PHP FPM binary:        /usr/local/php7/sbin/
Installing PHP FPM defconfig:     /usr/local/php7/etc/
Installing PHP FPM man page:      /usr/local/php7/php/man/man8/
Installing PHP FPM status page:   /usr/local/php7/php/php/fpm/
Installing phpdbg binary:         /usr/local/php7/bin/
Installing phpdbg man page:       /usr/local/php7/php/man/man1/
Installing PHP CGI binary:        /usr/local/php7/bin/
Installing PHP CGI man page:      /usr/local/php7/php/man/man1/
Installing build environment:     /usr/local/php7/lib/php/build/
Installing header files:          /usr/local/php7/include/php/
Installing helper programs:       /usr/local/php7/bin/
  program: phpize
  program: php-config
Installing man pages:             /usr/local/php7/php/man/man1/
  page: phpize.1
  page: php-config.1
Installing PDO headers:           /usr/local/php7/include/php/ext/pdo/

Dentro del subdirectorio bin/ se encuentra el binario php-cgi, a través del cual es posible verificar la versión instalada:

root@linuxito:~# /usr/local/php7/bin/php-cgi -v
PHP 7.1.7 (cgi-fcgi) (built: Jul  7 2017 11:52:16)
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

A continuación, copiar el script de inicio del servicio PHP-FPM, el cual se encuentra dentro del paquete con los fuentes (bajo la ruta sapi/fpm/):

root@linuxito:~/php-7.1.7# cp sapi/fpm/init.d.php-fpm /etc/init.d/php7-fpm

Instalar el script de inicio y luego editarlo:

root@linuxito:~/php-7.1.7# update-rc.d php7-fpm defaults
 Adding system startup for /etc/init.d/php7-fpm ...
   /etc/rc0.d/K20php7-fpm -> ../init.d/php7-fpm
   /etc/rc1.d/K20php7-fpm -> ../init.d/php7-fpm
   /etc/rc6.d/K20php7-fpm -> ../init.d/php7-fpm
   /etc/rc2.d/S20php7-fpm -> ../init.d/php7-fpm
   /etc/rc3.d/S20php7-fpm -> ../init.d/php7-fpm
   /etc/rc4.d/S20php7-fpm -> ../init.d/php7-fpm
   /etc/rc5.d/S20php7-fpm -> ../init.d/php7-fpm
root@linuxito:~/php-7.1.7# chmod +x /etc/init.d/php7-fpm
root@linuxito:~/php-7.1.7# nano /etc/init.d/php7-fpm

Cambiar la variable php_fpm_PID para que guarde el PID de FPM dentro de /var/run (en lugar de /usr/local/php7/var/run/):

php_fpm_PID=/var/run/php7-fpm.pid

Guardar los cambios y cerrar.

Además del script de inicio System V, el paquete incluye archivos de configuración de PHP (php.ini) de ejemplo. Copiar el modelo de "producción" al subdirectorio lib/:

root@linuxito:~/php-7.1.7# cp php.ini-production /usr/local/php7/lib/php.ini
root@linuxito:~/php-7.1.7# nano /usr/local/php7/lib/php.ini

Realizar las modificaciones deseadas:

post_max_size = 20M
upload_max_filesize = 20M
short_open_tag = On
session.use_strict_mode = 1

Para mi sitio Web, la configuración por defecto de "producción" se ajusta a mis necesidades. Sólo ajusté los tamaños de subida de archivos, habilite los short tags (<?) y habilité el modo estricto para las sesiones de PHP, con el objetivo de mejorar la seguridad.

Finalizada la instalación y configuración de PHP 7, ahora se debe configurar el servidor FastCGI.

Configuración de FPM

Cambiar al directorio de instalación de PHP 7:

root@linuxito:~/php-7.1.7# cd /usr/local/php7/etc/
root@linuxito:/usr/local/php7/etc# ll
total 12
-rw-r--r-- 1 root staff 4468 Jul  7 11:52 php-fpm.conf.default
drwxr-sr-x 2 root staff 4096 Jul  7 11:52 php-fpm.d

Dentro del subdirectorio etc/ se incluye un archivo de configuración de ejemplo de FPM. Copiarlo o renombrarlo:

root@linuxito:/usr/local/php7/etc# cp php-fpm.conf.default php-fpm.conf
root@linuxito:/usr/local/php7/etc# nano php-fpm.conf

Cambiar la configuración para que guarde el PID de FPM en /var/run/ y el log de errores en /var/log/:

pid = /var/run/php7-fpm.pid
error_log = /var/log/php7-fpm.log

El siguiente paso consiste en configurar todos los pooles de FPM necesarios (o copiarlos desde la instalación de PHP anterior):

root@linuxito:/usr/local/php7/etc# cd php-fpm.d/
root@linuxito:/usr/local/php7/etc/php-fpm.d# cp www.conf.default www.conf
root@linuxito:/usr/local/php7/etc/php-fpm.d# nano www.conf

Toda instalación básica cuenta con al menos un pool de conexiones, típicamente llamado "www":

[www]
user = www-data
group = www-data
listen = /var/run/php7-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 15
pm.min_spare_servers = 10
pm.max_spare_servers = 20

Ajustar correctamente el usuario y grupo (www-data en Debian y derivados), ubicación y permisos del socket Unix, y configuración del gestor de procesos (en este caso en modo "dynamic").

En este punto se ha finalizado la configuración y es posible iniciar el servidor PHP-FPM:

root@linuxito:/usr/local/php7/var/run# service php7-fpm start
Starting php-fpm  done
root@linuxito:/usr/local/php7/var/run# service php7-fpm status
php-fpm (pid 31486) is running...

Utilizando el comando ps es posible verificar que el proceso esté levantado:

root@linuxito:/usr/local/php7/var/run# ps aux | grep "[p]hp7"
root     31486  0.0  0.4 144192  4928 ?        Ss   08:15   0:00 php-fpm: master process (/usr/local/php7/etc/php-fpm.conf)

Sino utilizando pstree es posible visualizar el pool completo incluyendo el demonio y sus hijos:

root@linuxito:/usr/local/php7/var/run# pstree -cup 31486
php-fpm(31486)-+-php-fpm(31487,www-data)
               |-php-fpm(31488,www-data)
               |-php-fpm(31489,www-data)
               |-php-fpm(31490,www-data)
               |-php-fpm(31491,www-data)
               |-php-fpm(31492,www-data)
               |-php-fpm(31493,www-data)
               |-php-fpm(31494,www-data)
               |-php-fpm(31495,www-data)
               |-php-fpm(31496,www-data)
               |-php-fpm(31497,www-data)
               |-php-fpm(31498,www-data)
               |-php-fpm(31499,www-data)
               |-php-fpm(31500,www-data)
               `-php-fpm(31501,www-data)

Configuración de Nginx

En este punto tenemos dos servidores PHP FastCGI en funcionamiento:

root@linuxito:/usr/local/php7/var/run# netstat -xl | grep php
unix  2      [ ACC ]     STREAM     LISTENING     2063883  /var/run/php5-fpm.sock
unix  2      [ ACC ]     STREAM     LISTENING     1683596028 /var/run/php7-fpm.sock

El último paso consiste entonces en actualizar la configuración de Nginx para que haga uso del nuevo servidor PHP. Dependiendo de cada instalación, la configuración de Nginx puede localizarse en diferentes ubicaciones. En este caso se trata de una instalación de Nginx desde su código fuente:

root@linuxito:/usr/local/php7/var/run# nano /usr/local/nginx/conf/nginx.conf

Dentro del protocolo HTTP (http {) agregar el acceso al nuevo servidor PHP:


    upstream php7-fpm-sock {
        server unix:/var/run/php7-fpm.sock;
    }

Luego, en la ubicación correspondiente, cambiar la configuración FastCGI para que envíe la ejecución la nuevo servidor FPM:

                location ~ \.php {

                #fastcgi_pass php5-fpm-sock;
                fastcgi_pass php7-fpm-sock;

Luego reiniciar el servidor Nginx:

root@linuxito:/usr/local/php7/var/run# service nginx restart

A modo de verificación del servidor PHP, agregar un script PHP en la raíz del sitio Web que invoque a la función phpinfo():

<?php
phpinfo();

Luego verificar el acceso:

Se observa que PHP levanta el script de inicialización php.ini correcto.

Consideraciones para sitios Joomla! con PHP 7

PHP 7 ha abandonado el soporte para el driver de bases de datos mysql, por lo que es necesario utilizar MySQLi o PDO.

Abrir el archivo de configuración de Joomla!:

# nano configuration.php

Revisar la configuración de la variable $dbtype. Si tiene el valor "mysql", cambiarlo por "mysqli" o "pdomysl":

    public $dbtype = 'mysqli';

Por otro lado, es probable que falle la conexión con el servidor MySQL cuando se utiliza "localhost" como nombre de host. Cambiar por "127.0.0.1":

    public $host = '127.0.0.1';

Cleanup

El sitio funciona correctamente :)

La versión de PHP queda "escrachada" públicamente en los headers de la respuesta HTTP:

Habiendo comprobado que todos los sitios Web funcionan correctamente, deshabilitar el servidor php5-fpm:

root@linuxito:/etc/init.d# service php5-fpm stop
root@linuxito:/etc/init.d# update-rc.d php5-fpm disable
update-rc.d: warning:  start runlevel arguments (none) do not match php5-fpm Default-Start values (2 3 4 5)
update-rc.d: warning:  stop runlevel arguments (none) do not match php5-fpm Default-Stop values (0 1 6)
 Disabling system startup links for /etc/init.d/php5-fpm ...
 Removing any system startup links for /etc/init.d/php5-fpm ...
   /etc/rc0.d/K20php5-fpm
   /etc/rc1.d/K20php5-fpm
   /etc/rc2.d/S20php5-fpm
   /etc/rc3.d/S20php5-fpm
   /etc/rc4.d/S20php5-fpm
   /etc/rc5.d/S20php5-fpm
   /etc/rc6.d/K20php5-fpm
 Adding system startup for /etc/init.d/php5-fpm ...
   /etc/rc0.d/K20php5-fpm -> ../init.d/php5-fpm
   /etc/rc1.d/K20php5-fpm -> ../init.d/php5-fpm
   /etc/rc6.d/K20php5-fpm -> ../init.d/php5-fpm
   /etc/rc2.d/K80php5-fpm -> ../init.d/php5-fpm
   /etc/rc3.d/K80php5-fpm -> ../init.d/php5-fpm
   /etc/rc4.d/K80php5-fpm -> ../init.d/php5-fpm
   /etc/rc5.d/K80php5-fpm -> ../init.d/php5-fpm

Opcionalmente, desinstalar el paquete php5-fpm:

# apt-get purge php5-fpm php5-mysql


Tal vez pueda interesarte


Compartí este artículo