Cómo usar Redis para gestionar la sesión en Symfony

En este artículo quiero explicaros los pasos a seguir para configurar Redis como gestor de sesiones en un proyecto desarrollado mediante Symfony. Me he decidido a hacerlo ya que me ha costado bastante encontrar documentación al respecto, pues si bien en la página de Symfony se menciona la existencia de RedisSessionHandler , la forma en que debemos de configurar este Handler no aparece por ningún lado. Así que, ¡vamos a ello!

Requisitos iniciales

Antes de nada deciros que lo que voy a contar a continuación está pensado para un proyecto que emplee la versión 4 de Symfony instalada sobre un servidor con Ubuntu 18.

Si tenéis una versión más antigua de Symfony (3.x, 2.x) no os puedo que los pasos descritos os vayan a servir, ya que las pruebas que he realizado han sido para proyectos de Symfony 4.

En cuanto al servidor, pese a haber usado Ubuntu, los pasos para instalar la extensión Redis entiendo que serán similares para otras distros como Centos o Amazon Ami, por lo que no deberíais encontraros con ningún problema.

1. Instalar Redis en Ubuntu

Lo primero que haremos será instalar y configurar Redis en nuestro servidor, para lo cual ejecutaremos:

sudo apt update
sudo apt install redis-server

Una vez instalado correctamente, tendremos que introducir una pequeña configuración para la librería en el archivo etc/redis/redis.conf . Dentro de él, buscaremos la directiva supervised y modificaremos su valor por systemd :

supervised systemd

A continuación, reiniciaremos Redis mediante el comando:

sudo systemctl restart redis.service

Algunos “trucos” sencillos

Si queréis comprobar que Redis está funcionando correctamente podéis emplear el siguiente comando:

sudo systemctl status redis

El cual mostrará una salida como ésta si todo está en orden:

Output
● redis-server.service - Advanced key-value store
Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2018-06-27 18:48:52 UTC; 12s ago
Docs: http://redis.io/documentation,
man:redis-server(1)
Process: 2421 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS)
Process: 2424 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)
Main PID: 2445 (redis-server)
Tasks: 4 (limit: 4704)
CGroup: /system.slice/redis-server.service
└─2445 /usr/bin/redis-server 127.0.0.1:6379
. . .

Por otra parte, si queréis acceder a la consola de Redis podéis escribir lo siguiente:

redis-cli

Una vez dentro, podemos ejecutar el comando ping para ver si obtenemos respuesta desde el servidor de Redis:

127.0.0.1:6379> ping

Lo cual nos devolverá:

Output
PONG

También podremos establecer variables:

127.0.0.1:6379> set test "Hola mundo"

y obtenerlas de nuevo mediante:

127.0.0.1:6379> get test
Output
"Hola mundo"

Esto nos permitirá asegurarnos de que Redis está funcionando bien antes de avanzar al siguiente paso.

2. Instalar la extensión Redis para php

Una vez que ya tenemos Redis instalado y funcionando en Ubuntu, el siguiente paso será instalar la extensión de PHP que nos permita conectarnos a él. Para ello, primero ejecutaremos lo siguiente:

sudo apt-get install redis-tools php-redis

Y, a continuación, instalaremos la librería phpredis :

Lo cual haremos mediante pecl :

pecl install redis

Si os salta un error advirtiéndoos de que no tenéis la librería phpize , ejecutad primero:

sudo apt install php-dev

Y a continuación volver a correr el comando. Durante la instalación de phpredis se os plantearán dos preguntas:

enable igbinary serializer support? [no] :
enable lzf compression support? [no] :

A las cuales yo he respondido no (he realizado la instalación para un proyecto que todavía se encuentra en beta por lo que probablemente no necesite dichas optimizaciones, pero esto ya va según vuestras preferencias o necesidades).

Hecho esto, ya tendréis la librería instalada y tan solo necesitaremos habilitarla tal y como nos pide el propio comando pecl :

You should add "extension=redis.so" to php.ini

Para ello, editaremos el archivo php.ini que en mi caso se encuentra en:

nano /etc/php/7.2/fpm/php.ini

y añadiremos al final una nueva línea con:

extension=redis.so

Hecho esto, reiniciaremos php-fpm y, si todo ha ido bien, ya tendremos Redis conectado a PHP:

sudo service php7.2-fpm restart

Paso 3. Configurar Redis como gestor de sesiones en Symfony

Con Redis instalado en el servidor y conectado con PHP, tan solo necesitaremos decirle a Symfony que lo emplee como gestor de sesiones en vez del gestor por defecto.

Servicio RedisSessionHandler

Para activar el servicio RedisSessionHandler añadiremos lo siguiente en el archivo services_prod.yaml

Nota. Es probable que no tengáis dicho archivo. Si es vuestro caso, podéis crearlo en la ruta config/services_prod.yaml . He decidido hacerlo así ya que en mi entorno local no tengo redis , por lo que tan solo quiero definir el servicio en producción.

# config/services_prod.yaml
services:
  Redis:
    class: Redis
    calls:
      - method: connect
    arguments:
      - '%env(REDIS_HOST)%'
      - '%env(int:REDIS_PORT)%'
Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler:
     arguments:
       - '@Redis'

Hecho esto, añadiremos en nuestro archivo .env las variables REDIS_HOST y REDIS_PORT cuyos valores serán (al menos si habéis configurado Redis en el mismo servidor donde corre el proyecto):

REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Establecer Redis como gestor de sesiones

Finalmente configuraremos el archivo framework.yaml para que Symfony emplee Redis como gestor de sesiones. Nuevamente realizaré la configuración solo para el entorno de producción por lo que añadiré lo siguiente en el archivo config/packages/prod/framework.yaml :

framework:
  session:
  handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler

Hecho esto, ya podremos desplegar nuestra aplicación en el servidor y probar que podemos iniciar sesión normalmente

Autenticar en Redis (actualización 6 de mayo)

Puesto que el servidor de Redis lo tenemos abierto al mundo, es una buena práctica protegerlo por medio de contraseña, de modo que no se puedan ejecutar comandos sin antes haberla introducido.

Lo primero que haremos será añadir dicha contraseña en el archivo /etc/redis/redis.conf en la línea encabezadarequirepass (no os olvidéis de descomentarla).

A continuación, iremos a nuestro archivo services_prod.yaml y añadiremos una nueva llamada dentro de la clase Redis, de modo que se autentique tras realizar la conexión. ¡Ojo! El orden de las llamadas es importante, es decir, primero conectar y luego autenticar, si no, no os va a funcionar:

Como podeis observar, tras el método connect , añado una llamada al método auth de la clase Redis pasándole como argumento la contraseña que hayamos escogido y que estableceremos como una nueva variable de entorno.

Hecho esto, Redis seguirá funcionando normalmente pero ahora con una contraseña como medida adicional de seguridad.