Instalar php7 en debian y hacerlo convivir con php5 simultáneamente con php-fpm

Necesitaba instalar el nuevo PHP7 en un servidor donde recientemente tenía instalado un servidor en producción en Debian 8. Este servidor cumple con los servicios web y para eso tiene el conjunto de programas de servidor Apache, MySQL y PHP. Como la instalación se ha hecho mediante el repositorio estable de debian la versión que trae de php es la 5.6.

Sin embargo la idea es añadirle también la versión de PHP 7 que ha salido hace poco a disposición general. A continuación muestro como lo he hecho para que puedan funcionar las dos versiones distintamente.

El servicio PHP 5 está configurado como un sistema standalone, es decir no funciona como un módulo de apache, eso me permite tener mayor control, puesto que hago que cada virtualhost de Apache tenga su propia instancia de PHP y controlar así qué virtualhosts requiere más recursos. También me permite tener más pistas a la hora de ver qué ha podido suceder cuando ha habido algún problema sin afectar a los demás.

Así pues, asumo en esta muestra que ya tienes instalado y configurado en tu servidor PHP 5 en modo FPM y todo ello conectado con apache mediante socket o puerto local.

Preparación

Nos situamos en el directorio de fuentes:

cd /usr/src

Instalamos los paquetes necesarios:

apt-get -y install build-essential autoconf insserv bison git

Instalamos las librerías:

apt-get -y install libgmp-dev libmysqlclient-dev libfcgi-dev libfcgi0ldbl libmcrypt-dev libreadline-dev

Ajustamos el fallo de la localización del fichero gmp.h para compilar.

ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h

Compilación

Clonamos el repositorio

git clone https://git.php.net/repository/php-src.git
cd php-src

Compilamos

./buildconf
./configure --prefix=/usr/local/php7 --localstatedir=/usr/local/var --sysconfdir=/usr/local/etc/php7 --with-config-file-path=/usr/local/etc/php7 --with-config-file-scan-dir=/usr/local/etc/php7/conf.d --mandir=/usr/local/php7/share/man --enable-mbstring --enable-zip --enable-bcmath --enable-pcntl --enable-ftp --enable-exif --enable-calendar --enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-wddx --with-curl --with-mcrypt --with-iconv --with-gmp --with-pspell --with-gd --with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib-dir=/usr --with-xpm-dir=/usr --with-freetype-dir=/usr --enable-gd-native-ttf --enable-gd-jis-conv --with-openssl --with-pdo-mysql=/usr --with-gettext=/usr --with-zlib=/usr --with-bz2=/usr --with-mysqli=/usr/bin/mysql_config --with-fpm-user=www-data --with-fpm-group=www-data --enable-fpm --enable-sockets --enable-intl --enable-mysqlnd --with-mysqli=shared,mysqlnd --enable-bcmath --enable-dba --with-gmp --with-imap --with-imap-ssl --with-mhash --with-readline --enable-shmop --enable-soap --with-xmlrpc --with-xsl=/usr --enable-opcache --with-kerberos

Nota: el paquete recode se ha quitado porque no es compatible con imap:

--with-recode=/usr

make
make install

Configuración

php.ini

cp /usr/src/php-src/php.ini-production /usr/local/etc/php7/php.ini

php-fpm.conf

cp /usr/local/etc/php7/php-fpm.conf.default /usr/local/etc/php7/php-fpm.conf

Editamos: /usr/local/etc/php7/php-fpm.conf

pid = run/php7-fpm.pid

www.conf

cp /usr/local/etc/php7/php-fpm.d/www.conf.default /usr/local/etc/php7/php-fpm.d/www.conf

Editamos: /usr/local/etc/php7/php-fpm.d/www.conf

Lo que hacemos es comentar el puerto 9000 y activar la conexión por socket.
;listen = 127.0.0.1:9000
listen = /var/run/php7-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Servicio FPM

php7-fpm

Creamos el siguiente fichero: /etc/init.d/php7-fpm

#!/bin/sh
### BEGIN INIT INFO
# Provides:          php7-fpm
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts php7-fpm
# Description:       Starts The PHP FastCGI Process Manager Daemon
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/php7/sbin
DESC="PHP7 FastCGI Process Manager"
NAME=php-fpm
DAEMON=/usr/local/php7/sbin/$NAME
CONFFILE=/usr/local/etc/php7/php-fpm.conf
DAEMON_ARGS="–daemonize –fpm-config $CONFFILE"
CONF_PIDFILE=$(sed -n ‘s/^pid[ =]*//p’ $CONFFILE)
#PIDFILE=${CONF_PIDFILE:-/var/run/php7-fpm.pid}
PIDFILE=/usr/local/var/run/php7-fpm.pid}
TIMEOUT=30
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# Don‘t run if we are running upstart
if init_is_upstart; then
    exit 1
fi

#
# Function to check the correctness of the config file
#
do_check()
{
    # Run php-fpm with -t option to check the configuration file syntax
    errors=$($DAEMON –fpm-config $CONFFILE -t 2>&1 | grep "\[ERROR\]" || true);
    if [ -n "$errors" ]; then
        echo "Please fix your configuration file…"
        echo $errors
        return 1
    fi
    return 0
}

#
# Function that starts the daemon/service
#
do_start()
{
  # Return
  #   0 if daemon has been started
  #   1 if daemon was already running
  #   2 if daemon could not be started
  start-stop-daemon –start –quiet –pidfile $PIDFILE –exec $DAEMON –test > /dev/null \
    || return 1
  start-stop-daemon –start –quiet –pidfile $PIDFILE –exec $DAEMON — \
    $DAEMON_ARGS 2>/dev/null \
    || return 2
  # Add code here, if necessary, that waits for the process to be ready
  # to handle requests from services started subsequently which depend
  # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
  # Return
  #   0 if daemon has been stopped
  #   1 if daemon was already stopped
  #   2 if daemon could not be stopped
  #   other if a failure occurred
  start-stop-daemon –stop –quiet –retry=QUIT/$TIMEOUT/TERM/5/KILL/5 –pidfile $PIDFILE –name $NAME
  RETVAL="$?"
  [ "$RETVAL" = 2 ] && return 2
  # Wait for children to finish too if this is a daemon that forks
  # and if the daemon is only ever run from this initscript.
  # If the above conditions are not satisfied then add some other code
  # that waits for the process to drop all resources that could be
  # needed by services started subsequently.  A last resort is to
  # sleep for some time.
  start-stop-daemon –stop –quiet –oknodo –retry=0/30/TERM/5/KILL/5 –exec $DAEMON
  [ "$?" = 2 ] && return 2
  # Many daemons don’t delete their pidfiles when they exit.
  rm -f $PIDFILE
  return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
  #
  # If the daemon can reload its configuration without
  # restarting (for example, when it is sent a SIGHUP),
  # then implement that here.
  #
  start-stop-daemon –stop –signal USR2 –quiet –pidfile $PIDFILE –name $NAME
  return 0
}

case "$1" in
    start)
  [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
  do_check $VERBOSE
  case "$?" in
      0)
    do_start
    case "$?" in
        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
      1) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
    stop)
  [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
  esac
  ;;
    status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
    check)
        do_check yes
  ;;
    reload|force-reload)
  log_daemon_msg "Reloading $DESC" "$NAME"
  do_reload
  log_end_msg $?
  ;;
    reopen-logs)
  log_daemon_msg "Reopening $DESC logs" $NAME
  if start-stop-daemon –stop –signal USR1 –oknodo –quiet \
      –pidfile $PIDFILEexec $DAEMON
  then
      log_end_msg 0
  else
      log_end_msg 1
  fi
  ;;
    restart)
  log_daemon_msg "Restarting $DESC" "$NAME"
  do_stop
  case "$?" in
    0|1)
    do_start
    case "$?" in
      0) log_end_msg 0 ;;
      1) log_end_msg 1 ;; # Old process is still running
      *) log_end_msg 1 ;; # Failed to start
    esac
    ;;
    *)
      # Failed to stop
    log_end_msg 1
    ;;
  esac
  ;;
    *)
  echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2
  exit 1
    ;;
esac

:
 

Ajustamos los permisos del fichero

chmod 755 /etc/init.d/php7-fpm

Incluímos el servicio php7-fpm

/usr/lib/insserv/insserv php7-fpm

Creamos el fichero /lib/systemd/system/php7-fpm.service

[Unit]
Description=The PHP 7 FastCGI Process Manager  
After=network.target

[Service]
Type=simple  
PIDFile=/usr/local/var/run/php-fpm.pid  
ExecStart=/usr/local/php7/sbin/php-fpm –nodaemonize –fpm-config /usr/local/etc/php7/php-fpm.conf  
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target
 

Arrancamos el servicio php7-fpm

Si tu sistema soporta systemctl entonces debes activar lo siguiente:
systemctl enable php7-fpm.service
systemctl daemon-reload
service php7-fpm start

En caso que no, puedes hacer lo siguiente:
/etc/init.d/php7-fpm start

Con estos pasos ya puedes tener funcionado dos servicios de php, cada uno con su versión. A partir de ahí en cada virtualhost definimos mediante el módulo FastCGI a que socket debe conectarse y por consiguiente a que versión de PHP.

En este post solo hablo de la instalación de PHP7 para que pueda convivir con PHP5, no se explica como instalar y configurar PHP mediante FPM, en caso que pida es posible que haga otro post sobre la instalación de PHP-FPM, FastCGI y Apache.


Sobre esta entrada