Lo hice y lo entendí

El blog de Vicente Navarro
23 nov

Probando el mod_deflate de Apache

El RFC2616, de 1999, definió el protocolo HTTP 1.1. En el apartado 14.3, el estándar habla de la cabecera para peticiones Accept-Encoding, que le permite al cliente de HTTP (normalmente un navegador) especificarle al servidor que acepta contenido comprimido.

En efecto, si tomamos una traza de red (p.e. con WireShark) de una petición de un navegador (p.e. Iceweasel) a un servidor web, veremos que éste le dice al servidor web que acepta el contenido comprimido por gzip o por deflate (es decir, zlib):

GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.8) Gecko/20071004 Iceweasel/2.0.0.8 (Debian-2.0.0.8-1)
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

En Firefox, podemos usar el parámetro del about:config network.http.accept-encoding para especificar exactamente qué queremos tener para esa entrada de la cabecera, siendo el valor por defecto “gzip,deflate“.

Por su parte, el servidor web Apache 2 es capaz de atender esas peticiones de compresión por medio del módulo mod_deflate.

En Debian, el módulo ya viene en el paquete estándar de apache2:

# dpkg -S deflate.load
apache2.2-common: /etc/apache2/mods-available/deflate.load

Sin embargo, no viene activado por defecto. Para habilitarlo, tenemos que crear un enlace en el directorio mods-enabled:

# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/deflate.load deflate.load

Además, tendremos que elegir las opciones de configuración que más nos puedan interesar. Como la compresión de según qué tipos de ficheros con según qué versiones de navegador puede dar problemas, una solución que nos comprime prácticamente todos los ficheros de texto típicos de una página sin crear mayores problemas es usar la directiva AddOutputFilterByType diciéndole que comprima ficheros HTML, CSS, JavaScript y de texto:

AddOutputFilterByType DEFLATE text/html text/plain text/css application/x-javascript

Tras esto, es conveniente revisar que la sintaxis es correcta con un “apache2ctl configtest” y reinciar el servidor para que se use la nueva configuración sin cortar las conexiones existentes al servidor web con un “apache2ctl graceful“.

Tras aplicar estos cambios, la contestación del servidor web a la petición anterior del navegador será ésta, aceptando la compresión y enviando la página comprimida a continuación:

HTTP/1.1 200 OK
Date: Fri, 23 Nov 2007 16:14:42 GMT
Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch7
X-Powered-By: PHP/5.2.0-8+etch7
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Fri, 23 Nov 2007 16:14:43 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 22266
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

Si queremos comprobar el buen funcionamiento de este módulo, podemos usar el wget, versátil herramienta que nos permite descargar documentos desde línea de comandos mediante HTTP y FTP.

Por defecto, el wget manda unas cabeceras muy sencillas:

GET / HTTP/1.0
User-Agent: Wget/1.10.2
Accept: */*
Host: www.example.com
Connection: Keep-Alive

Vemos que usa HTTP 1.0 y no indica ningún Accept-Encoding. Sin embargo, podemos usar la opción de línea de comandos --header para modificar las cabeceras y aceptar compresión.

Así, vemos que el fichero raíz de un servidor web que ocupa 78 KiB:

$ wget http://www.example.com
--18:10:02--  http://www.example.com
           => `index.html'
Resolving www.example.com... 10.12.34.56
Connecting to www.example.com|10.12.34.56|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]

    [        <=>                          ] 80,206        40.26K/s

18:10:05 (40.18 KB/s) - `index.html' saved [80206]

únicamente ocupa 22 KiB si se pide comprimido:

$ wget --header="Accept-Encoding: gzip" http://www.example.com
--18:13:51--  http://www.example.com
           => `index.html'
Resolving www.example.com... 10.12.34.56
Connecting to www.example.com|10.12.34.56|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 22,143 (22K) [text/html]

100%[====================================>] 22,143        --.--K/s

18:13:55 (5.19 MB/s) - `index.html' saved [22143/22143]

Sin embargo, si examinamos ese fichero descargado, vemos que no es el fichero HTML que esperábamos, sino un fichero comprimido con gzip:

$ file index.html
index.html: gzip compressed data, from Unix

Sería necesario descomprimir el fichero para encontrar que tiene el tamaño y el contenido esperado:

$ mv index.html index.html.gz
$ gzip -d index.html.gz
$ ll index.html
-rw-r--r-- 1 root root 80206 2007-11-23 18:13 index.html
$ file index.html
index.html: HTML document text

Comprimir las páginas web antes de enviarlas supone una gran ventaja en circunstancias de ancho de banda limitado. Sin embargo, no hay que olvidar que el servidor tiene que estar permanentemente comprimiendo ficheros, lo que puede ocasionar que la CPU no dé abasto. Por tanto, hay que tener muy presente, antes de habilitar esta opción, si en situaciones de carga extraordinaria la limitación de nuestro servidor web está en la carga de CPU o en el ancho de banda disponible.

Finalmente, comentar que en la página www.http-compression.com podemos leer sobre qué navegadores soportan la compresión de las páginas, que son prácticamente todas las versiones modernas de los navegadores comunes: Firefox, Konqueror, Opera e Internet Explorer.

Por cierto, ¿sabías que example.com, example.org y example.net son dominios reservados para usar como ejemplo en la documentación?

:wq

Entradas relacionadas

14 Comentarios a “Probando el mod_deflate de Apache”

  • Bytecoders dice:

    Interesante, haciendo las pruebas la página principal del blog pasa de 33,4 K a 8 K estando comprimida en gzip.
    La verdad es que en casa el ancho de banda no abunda y la carga que tiene el PC no es mucha, por tanto creo que es un escenario ideal.
    Sobre los dominios example no tenía ni idea.

  • @Bytecoders Me alegro de que te haya parecido interesante. La verdad es que es precisamente en entornos como el de hospedaje doméstico cuando más interesante puede ser esta configuración.

  • Iván dice:

    Muy interesante lo que nos cuentas de la compresión. Como dices, para servidores caseros en los que no vamos muy sobrados de ancho de banda puede ser una opción muy útil.
    Ahora una pregunta. No se podrían cachear de alguna manera las páginas comprimidas para no tener que estar constantemente comprimiendo el mismo contenido?.

    Saludos, Iván.

  • @Iván Hablando de contenido dinámico es difícil que Apache lo pueda cachear. Si tratamos con WordPress sería mejor pensar en algo como el WP-Cache de Ricardo Galli que cachea y permite comprimir a la vez.

    Para contenidos estáticos se podría combinar el mod_deflate con el mod_cache para dejar los contenidos cacheados y sin volver a comprimirlos.

  • Iván dice:

    Yo lo decía porque aunque sea contenido dinámico, realmente un post es siempre estático y lo único que cambia es la parte de los comentarios. Aunque supongo que si se utiliza wp-cache o similares no debería haber demasiados problemas.

    Saludos, Iván.

  • El WP-Cache permite cachear las entradas de WordPress, de forma que las páginas dinámicas que no hayan cambiado sean servidas desde un fichero estático. Sin embargo, no permite dejar dichas páginas comprimidas y evitar así que la CPU las tenga que comprimir cada vez.

    El artículo Modifying WP-Cache 2.0 to generate and cache gzipped output once and serve it multiple times cuenta cómo modificar el WP-Cache para que las páginas almacenadas en la caché se almacenen ya comprimidas para no tener que comprimirlas cada vez.

    El 1 Blog Cache parece que ya lo permite por defecto.

  • zarta dice:

    Me ha parecido un artículo interesante, y sobretodo el modo de utilizar esta opción en wget (para mis futuras descargas de iso de mis distribuciones preferidas jajaja)

    Aparte, voy a aplicar esto en mi pequeño web/wiki/caja de pruebas de casa.

  • @zarta ¡Gracias! Me alegro de que te haya gustado.

  • Robert dice:

    Para activar y desactivar los módulos puedes usar el a2enmod y el a2dismod, que en combinación con el bash_completion te ahorran un par de tecleos :) Por ejemplo para el deflate “a2enmod deflate”

    También existen a2ensite y a2dissite

  • @Robert No los conocía, pero me parecen muy útiles. ¡Muchas gracias por el apunte!

Trackbacks y pingbacks:

Tema LHYLE09, creado por Vicente Navarro