Comprimir las respuestas de texto (HTML, CSS, JavaScript, JSON, SVG) reduce su tamaño entre un 60 % y un 90 %, con lo que las páginas cargan antes y se consume menos ancho de banda. Todos los navegadores actuales admiten Gzip y Brotli, y este último consigue ficheros algo más pequeños con un coste de CPU similar. En este tutorial activarás Gzip y Brotli en Nginx y en Apache sobre Ubuntu 24.04 y comprobarás con curl qué codificación sirve el servidor en cada caso. Sigue solo la parte del servidor web que uses.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Nginx (sudo apt install nginx) o Apache (sudo apt install apache2) instalado y sirviendo una web.
  • curl para las comprobaciones (viene instalado por defecto).

Qué comprimir y qué no

La compresión solo tiene sentido para formatos de texto. Las imágenes JPEG, PNG y WebP, los vídeos, los ficheros ZIP y las fuentes WOFF2 ya están comprimidos, y volver a comprimirlos gasta CPU sin reducir su tamaño. Los tipos MIME que conviene comprimir son:

Tipo de contenidoTipos MIME
HTMLtext/html
Hojas de estilotext/css
JavaScripttext/javascript, application/javascript
Datosapplication/json, application/xml, text/xml, application/rss+xml
Texto planotext/plain
Gráficos vectorialesimage/svg+xml

Tampoco merece la pena comprimir respuestas muy pequeñas: por debajo de unos cientos de bytes, la cabecera de compresión puede ocupar más de lo que se ahorra.

Nginx

Paso 1: Configurar Gzip

Nginx en Ubuntu trae el módulo gzip y lo activa en /etc/nginx/nginx.conf con gzip on;, pero con la configuración por defecto solo comprime text/html. Las demás opciones aparecen comentadas en ese fichero. En lugar de editarlo, crea un fichero propio en conf.d, que Nginx carga dentro del bloque http:

sudo nano /etc/nginx/conf.d/compression.conf
# Gzip (gzip on ya está en nginx.conf)
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/javascript
    application/json
    application/xml
    application/rss+xml
    image/svg+xml;

Qué hace cada directiva:

  • gzip_vary on: añade la cabecera Vary: Accept-Encoding para que las cachés intermedias y las CDN guarden por separado la versión comprimida y la sin comprimir.
  • gzip_proxied any: comprime también las respuestas a peticiones que llegan a través de un proxy o CDN.
  • gzip_comp_level 5: nivel de 1 a 9. A partir de 5 o 6 la reducción de tamaño es mínima y el coste de CPU sigue subiendo.
  • gzip_min_length 256: no comprime respuestas de menos de 256 bytes.
  • gzip_types: tipos MIME a comprimir, además de text/html, que se comprime siempre.

No declares ninguna de estas directivas también en nginx.conf sin comentar, o Nginx dará un error de directiva duplicada.

Comprueba la configuración y recarga:

sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Paso 2: Instalar y configurar Brotli

Ubuntu 24.04 incluye el módulo de Brotli para Nginx en dos paquetes: libnginx-mod-http-brotli-filter, que comprime al vuelo, y libnginx-mod-http-brotli-static, que sirve ficheros .br precomprimidos. Instálalos:

sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static

Los paquetes cargan los módulos automáticamente mediante enlaces en /etc/nginx/modules-enabled/:

ls /etc/nginx/modules-enabled/
50-mod-http-brotli-filter.conf
50-mod-http-brotli-static.conf

Añade la configuración de Brotli al mismo fichero compression.conf:

sudo nano /etc/nginx/conf.d/compression.conf
# Brotli
brotli on;
brotli_comp_level 5;
brotli_min_length 256;
brotli_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/javascript
    application/json
    application/xml
    application/rss+xml
    image/svg+xml;

# Servir ficheros precomprimidos .br y .gz si existen junto al original
brotli_static on;
gzip_static on;

Cuando el navegador acepta ambos formatos, Nginx sirve Brotli; los clientes que solo admiten Gzip siguen recibiendo Gzip. Con brotli_static y gzip_static, si existe app.js.br o app.js.gz junto a app.js, Nginx envía directamente el fichero precomprimido sin gastar CPU. Muchas herramientas de build de frontend pueden generar estos ficheros.

Comprueba y recarga:

sudo nginx -t
sudo systemctl reload nginx

Apache

Paso 1: Revisar Gzip (mod_deflate)

En Apache la compresión Gzip la hace mod_deflate, que en Ubuntu viene activado por defecto con una lista de tipos en /etc/apache2/mods-available/deflate.conf. Compruébalo:

apache2ctl -M | grep -E 'deflate|filter'
 deflate_module (shared)
 filter_module (shared)

Si solo necesitas Gzip, ya lo tienes funcionando y puedes pasar a la sección de verificación.

Paso 2: Activar Brotli (mod_brotli)

El módulo mod_brotli viene incluido en el paquete apache2 de Ubuntu 24.04, pero desactivado. Actívalo:

sudo a2enmod brotli

Hay un detalle importante: si dejas la configuración de deflate.conf tal como está y añades Brotli por separado, Apache aplica primero Gzip y el navegador nunca recibe Brotli. La solución es declarar ambos filtros en una sola directiva, en el orden BROTLI_COMPRESS;DEFLATE: Brotli comprime si el cliente lo admite y, si no, lo hace Gzip.

Primero desactiva las líneas por defecto de deflate.conf:

sudo nano /etc/apache2/mods-available/deflate.conf

Comenta las líneas AddOutputFilterByType para que el fichero quede así:

<IfModule mod_filter.c>
	# AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
	# AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
	# AddOutputFilterByType DEFLATE application/rss+xml
	# AddOutputFilterByType DEFLATE application/wasm
	# AddOutputFilterByType DEFLATE application/xml
</IfModule>

Después crea un fichero de configuración propio con los dos filtros encadenados:

sudo nano /etc/apache2/conf-available/compression.conf
<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS;DEFLATE text/html text/plain text/css text/xml text/javascript application/javascript application/json application/xml application/rss+xml image/svg+xml
    BrotliCompressionQuality 5
</IfModule>

BrotliCompressionQuality va de 0 a 11 y por defecto es 5, un buen equilibrio para compresión al vuelo. Los valores altos (10 u 11) son muy lentos y solo tienen sentido para ficheros precomprimidos.

Activa la configuración, comprueba la sintaxis y recarga Apache:

sudo a2enconf compression
sudo apache2ctl configtest
sudo systemctl reload apache2
Syntax OK

Verificar la compresión

La comprobación es la misma para Nginx y Apache. Pide una página indicando qué codificaciones acepta el cliente con la cabecera Accept-Encoding y mira la cabecera Content-Encoding de la respuesta. Sustituye your_domain por tu dominio o la IP del servidor.

Un cliente que acepta Gzip y Brotli, como cualquier navegador moderno, debe recibir Brotli:

curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip, deflate, br' http://your_domain/ | grep -i -E 'content-encoding|vary'
Vary: Accept-Encoding
Content-Encoding: br

Un cliente que solo acepta Gzip debe recibir Gzip:

curl -s -o /dev/null -D - -H 'Accept-Encoding: gzip' http://your_domain/ | grep -i -E 'content-encoding|vary'
Vary: Accept-Encoding
Content-Encoding: gzip

Para ver el ahorro, compara los bytes descargados sin compresión y con Brotli:

curl -s -o /dev/null -w 'sin compresión: %{size_download} bytes\n' http://your_domain/
curl -s -o /dev/null -w 'brotli: %{size_download} bytes\n' -H 'Accept-Encoding: br' http://your_domain/
sin compresión: 10671 bytes
brotli: 2722 bytes

Repite la prueba con un fichero CSS o JavaScript de tu web, por ejemplo http://your_domain/assets/app.css. También puedes comprobarlo en el navegador: en las herramientas de desarrollo, pestaña Red, la columna o cabecera Content-Encoding muestra br o gzip para cada recurso.

Solución de problemas

  • No aparece Content-Encoding: la respuesta es más pequeña que el mínimo configurado o su tipo MIME no está en la lista. Comprueba el tipo con curl -sI http://your_domain/ruta | grep -i content-type.
  • Apache sirve Gzip aunque el cliente acepta Brotli: siguen activas las líneas AddOutputFilterByType DEFLATE de deflate.conf u otra directiva DEFLATE en tus virtual hosts o en un .htaccess. Elimínalas y deja solo la cadena BROTLI_COMPRESS;DEFLATE.
  • unknown directive "brotli" en Nginx: el módulo no está cargado. Comprueba que los paquetes están instalados y que existen los enlaces en /etc/nginx/modules-enabled/.
  • Detrás de Cloudflare u otra CDN: la CDN puede recomprimir o descomprimir las respuestas hacia el visitante. Comprueba las cabeceras directamente contra la IP del servidor para aislar el comportamiento de tu origen.
  • Uso de CPU alto: baja gzip_comp_level, brotli_comp_level o BrotliCompressionQuality, y sirve ficheros estáticos precomprimidos cuando sea posible.

Conclusión

Tu servidor web comprime ahora las respuestas de texto con Brotli para los navegadores que lo admiten y con Gzip para el resto, y sabes comprobarlo con curl. Como siguientes pasos, configura cabeceras de caché del navegador para los ficheros estáticos, activa HTTP/2 junto con HTTPS y mide el efecto de cada cambio con Apache Bench o con las herramientas de desarrollo del navegador.