En esta guía estaré explicando como compilar el módulo Brotli para Nginx, un algoritmo de compresión desarrollado por Google, como alternativa a Gzip y Deflate. La razón de compilar el módulo es que Nginx no ha dado soporte oficial a la versión de código abierto, siendo que en su versión Nginx Plus si lo tiene soportado.
El entorno usado fue Debian Bullseye y Ubuntu Focal con Nginx 1.14.2 y Nginx 1.18.0.
1. Instalar Nginx
Lo primero que necesitamos hacer es instalar Nginx. Si vamos a compilar el módulo de manera local hay que usar exactamente la misma distribución con los mismos repositorios. Ya que podemos simplemente copiarlo a producción, pero los entornos deben ser los mismos. Si en el sistema final usaremos el paquete nginx-full, nginx-extras o cualquier otro, no es mala idea instalarlos también, un pequeño detalle como este puede quitarnos muchas horas.
Instalamos con:
sudo apt -y install nginx
⇧
2. Instalar dependencias
Actualizamos los paquetes que tengan actualizaciones pendientes:
sudo apt update
sudo apt -y upgrade
Instalamos los siguientes paquetes:
sudo apt -y install git libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev apt-src
Antes del siguiente paso editamos nuestro /etc/apt/sources.list, y quitamos el símbolo "#" de las líneas que tengan "deb-src", solo de los repositorios que sí se estén usando.
sudo nano /etc/apt/sources.list
En una instalación con Ubuntu viene así:
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://archive.ubuntu.com/ubuntu focal main restricted
# deb-src http://archive.ubuntu.com/ubuntu focal main restricted
Luego de editarlo:
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://archive.ubuntu.com/ubuntu focal main restricted
deb-src http://archive.ubuntu.com/ubuntu focal main restricted
Después actualizamos la caché de apt y de apt-src:
⇧sudo apt update
sudo apt-src update
3. Descargar código fuente de Nginx y Brotli
Creamos un directorio para guardar todo:
cd ~
mkdir nginx-brotli
cd nginx-brotli
Empezamos descargando el código fuente de Nginx con apt-src para que haga juego con la versión instalada en el sistema:
sudo apt-src install nginx
Luego descargamos el código fuente de Brotli del repositorio oficial de Google:
⇧cd ~/nginx-brotli
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli
git submodule update --init
4. Compilar Brotli como módulo dinámico
Cambiamos de directorio al de Nginx:
cd ~/nginx-brotli/nginx-*/
Ejecutamos el siguiente comando para ver las opciones de compilación que la versión de Nginx instalada uso:
sudo nginx -V
Copiamos todas las opciones después del texto configure arguments:, le quitamos todas las opciones que comiencen con --add-dynamic-module y le agregamos al final separado con un espacio:
--add-dynamic-module=../ngx_brotli
Al principio le agregamos sudo ./configure y un espacio para separar las opciones. Debe ser algo similar a lo siguiente:
sudo ./configure --with-cc-opt... --with-strea... --add-dynamic-module=../ngx_brotli
El comando resultante normalmente es de varias líneas, lo resumí con las partes marcadas para que sea más comprensible. Lo ejecutamos como un comando.
Podemos usar el siguiente comando para generar el comando completo en lugar de hacerlo manualmente:
sudo nginx -V 2>&1 | grep '^configure arguments:' | sed -r 's/--add-dynamic-module=(\S)+(\s|$)//g; s/$/\-\-add\-dynamic\-module=\.\.\/ngx_brotli/g; s/configure arguments:/sudo \.\/configure/g'
El comando anterior modifica la salida de nginx -V y lo convierte en el comando que necesitamos para compilar Nginx. Lo copiamos y ejecutamos.
Si nos aparece el error:
./configure: error: the HTTP XSLT module requires the libxml2/libxslt
Instalamos el siguiente paquete:
sudo apt install -y libxslt1-dev
Y lo volvemos a ejecutar.
Si no aparece ningún error ejecutamos:
sudo make modules
⇧
5. Configuración de Nginx
Copiamos los archivos resultantes ngx_http_brotli_filter_module.so y ngx_http_brotli_static_module.so al directorio /etc/nginx/modules-available:
sudo cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules-available
sudo cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules-available
Editamos el archivo /etc/nginx/nginx.conf:
sudo nano /etc/nginx/nginx.conf
Y le agregamos al principio antes de todo lo demás:
load_module /etc/nginx/modules-available/ngx_http_brotli_filter_module.so;
load_module /etc/nginx/modules-available/ngx_http_brotli_static_module.so;
Probamos la configuración y los módulos con:
sudo nginx -t
Si todo está bien nos aparecerá:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
De lo contrario si existe algún problema la salida será:
nginx: [emerg] module ngx_http_brotli_filter_module.so is not binary compatible in nginx.conf...
Si no sabemos por qué tenemos errores hay que prestar atención al comando configure y revisar al final todos los errores que aparecen. También no estaría de más revisar si estamos usando la misma versión, y en el caso de que el sistema destino sea diferente con mayor razón. Mientras no reiniciemos Nginx no habría ningún problema porque el último comando solo revisa la configuración sin realizar cambio alguno.
Para terminar con todo el desastre que quedó, eliminamos los archivos de código fuente usados:
sudo rm -R ~/nginx-brotli/
⇧
6. Uso en otros sistemas producción o en desarrollo
Ya que todo está comprobado y, las versiones del sistema operativo y software coinciden podemos copiar los archivos que quedaron en /etc/nginx/modules-available. Teniendo en cuenta que cada que exista una actualización por mínima que sea tenemos que recompilar los módulos para que sean compatibles. No estaría de más renombrarlos para que tengan el formato módulo-1.14-2.so haciendo referencia a la versión de Nginx para la que fueron compilados. Además de copiarlos, tenemos que realizar los pasos anteriores, como el de volver a editar el archivo de configuración de Nginx para cargar los módulos y volver a comprobar la configuración antes de reiniciar.
6.1. Bloquear actualización de paquete Nginx
Si queremos evitar accidentes podemos usar la utilidad apt-mark para forzar al gestor de paquetes a que no actualice Nginx, pero si el resto de los paquetes.
Bloquear versión instalada:
sudo apt-mark hold nginx
Para desbloquear el paquete después de colocarle nuevos módulos y comprobar su configuración nueva:
sudo apt-mark unhold nginx
6.2. Reiniciar Nginx si no hay ningún problema
Para reiniciar Nginx después de comprobar que los módulos si están funcionando usar:
sudo systemctl restart nginx
⇧
7. Activación y uso de los módulos
Hasta este momento Nginx ya tiene cargados los módulos, solo falta activarlos y configurarlos, y al final comprobaremos si están funcionando.
Editamos el archivo nginx.conf:
nano /etc/nginx/nginx.conf
Exactamente debajo de gzip on;
colocamos en una nueva línea:
brotli on;
Después buscamos una línea que tenga gzip_types
, si empieza con "#" se lo quitamos, la copiamos completamente y colocamos la nueva debajo, el resultado será algo similar:
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
Ambas líneas deben tener los mismos argumentos para aprovechar al máximo el nuevo algoritmo.
Comprobamos que la configuración funcione con sudo nginx -t
y reiniciamos el servicio:
sudo systemctl restart nginx
Para el módulo "ngx_http_brotli_static_module.so" hay que usarlo igual que la opción gzip_static
, podemos revisar la directiva en el repositorio de Google, o la directiva gzip_static en Nginx.
8. Comprobando funcionamiento del algoritmo de compresión
Para esto vamos a necesitar usar Firefox, Chrome, o cualquier navegador que soporte este algoritmo. En el caso que sea el mismo sistema en donde tenemos instalado el paquete, abrimos 127.0.0.1 en el navegador y abrimos las herramientas para desarrolladores con F12, y nos dirigimos a la pestaña Red o Network. Hacemos clic en la URL y verificamos que en Response Headers en Content-Encoding salga "br", en Request Headers y Accept-Encoding verificamos que salga "gzip, deflate, br" en cualquier orden. Si en Content-Encoding no aparece "br", significa que el servidor no mandó el contenido con el nuevo algoritmo, y si en Accept-Encoding no aparece "br" puede ser que el navegador no lo soporte o simplemente no se encuentra activado para el tipo de documento.
Si tenemos problemas con Firefox podría tratarse porque Brotli no está soportado en conexiones sin SSL, y como en este caso usamos localhost puede no funcionar localmente. Si queremos probar sin SSL podemos usar Chrome, este al menos en la versión 84 lo soporta sin HTTPS.
Me basé en esta entrada de Website for Students, aunque tuve problemas en el paso de la compatibilidad del binario. En el repositorio oficial de Brotli viene un poco de información acerca de la compilación.
⇧