HOWTO: Use Apache mod_deflate To Compress Web Content (Accept-Encoding: gzip)

| 2 TrackBacks
After setting up my first mobile blog portal (http://kolich.mobi), I started looking for ways to improve the content delivery speed of kolich.mobi to mobile devices.  On the server-side, I'm fairly sure I implemented just about every hack imaginable to squeeze every bit of performance I could from the PHP engine.  At this point, my only bottleneck was the actual content delivery chain.  I can't control how fast my data is transferred over a wireless (2G/3G?) network because of factors outside of my control, but I can help grease the skid.  To do so, I activated Apache's mod_deflate extension which compresses the content of an HTTP response before its delivered to the client.

The mod_deflate extension (err, module) uses gzip to deflate the HTTP response body.  Obviously, since the response is compressed, that means there's less data to transfer.  Hence, it takes less "cycles" (packets, octets, whatever) to get the data to the client.  In short, using compression within the confines of HTTP can often dramatically improve the "speed" of your site or mobile portal on a wireless network.  Of course, not only wireless clients benefit from the performance improvement, but typically wireless devices see more of an improvement than an average broadband user.
First, I verified that mod_deflate is installed and pre-activated with Apache on my CentOS 5 box:

#/~> cat /etc/httpd/conf/httpd.conf | grep mod_deflate
LoadModule deflate_module modules/mod_deflate.so

Luckily, I didn't have to do anything special to set it up, and I would guess most Apache users are in the same boat.  However, if you do need to compile and install mod_deflate from source, I would recommend you check out this helpful post.

Second, I hacked my http://kolich.mobi VirtualHost configuration a bit to activate the mod_deflate output filter.  Using the instructions on the mod_deflate homepage, I configured my kolich.mobi VirtualHost to use the highest compression level possible on every response except for binary image data.  I also defined a custom "deflate" log so I can check the compression ratio on any responses:

<VirtualHost *:80>

DocumentRoot /my/server/root/kolich.mobi/
ServerName www.kolich.mobi
ServerAlias kolich.mobi
ServerAdmin support@example.com

DeflateCompressionLevel 9
SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary

DeflateFilterNote ratio
LogFormat '"%r" %b (%{ratio}n%%) "%{User-agent}i"' deflate
CustomLog logs/kolich.mobi-deflate_log deflate

ErrorLog logs/kolich.mobi-error_log
CustomLog logs/kolich.mobi-access_log combined

</VirtualHost>

This works quite nicely.  Looking at the custom deflate log, my kolich.mobi content compression ratio is about 40-50% on average.  Not bad for less than 5 minutes of work!

Here are some things to consider when using mod_deflate:

  • It wasn't immediately clear to me if mod_deflate looked for the "Accept-Encoding" HTTP request header to verify that the client supports gzip compression.  At least, there was no mention of this on the mod_deflate homepage.  But as it turns out, yes, mod_deflate does look through the HTTP request headers for "Accept-Encoding: gzip".  The module will not compress the response if the client does not support it (I proved this below using lwp-request).

  • Of course, not all clients support compression.

  • Compression will use additional CPU cycles on the client and the server.  If a large majority of your target audience is using slow mobile devices, then you might want to think twice about HTTP compression.  Generally speaking though, todays mobile clients should have plenty of CPU power to handle simple gzip compression.

  • High-traffic sites will want to think twice about compression.  You wouldn't want the added CPU consumption from compression to impact your overall site experience.

If you want to prove to yourself that compression is working, you can use the lwp-request command to examine the HTTP response headers (and body).  First, let's verify that compression is working when the client says it supports it:

#/~> lwp-request -e -d -H 'Accept-Encoding: gzip' http://kolich.mobi/ | \
grep -i -e length -e encoding
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 1377

Yep, sure enough the client says it supports gzip encoding, and the server responded correctly.  Now, let's verify that clients that don't support compression are handled accordingly:

#/~> lwp-request -e -d http://kolich.mobi/ | \
grep -i -e length -e encoding
Vary: Accept-Encoding,User-Agent
Content-Length: 3078

Perfect, clients that don't support compression won't get a compressed response.  Note that the Content-Length of the non-compressed response was 3078 bytes, compared to 1377 bytes in the compressed response.  Less bytes, faster delivery.

Enjoy.

Did You Find this Helpful?

Did you find this post helpful, or at least, interesting?

  

About Mark

A Silicon Valley native, Mark Kolich is a full-time Software Engineer and a consultant for hire. A web technologies expert, his current focus is on building powerful and robust cloud-driven web-applications using Java, PHP, Perl, AJAX, DHTML, CSS, and JavaScript. His favorite programming languages are PHP, Java and JavaScript. He uses Linux, enjoys biking to work, loves building great software, and always writes elegant, readable, and maintainable code.

2 TrackBacks

I never paid much attention to the HTTP Vary header.  In fact, I've been fortunate enough to avoid it for this long and never really had to care much about it.  Well, it turns out when you're configuring a high-performance... Read More

Update 1/21/11: I recently discovered that you can embed binary image data using the data URI scheme in JSON too!If you've ever looked at the code for some of the more popular mobile web-portals, you might have noticed that many... Read More

Twitter (@markkolich)

Translate

About this Entry

This page contains a single entry by Mark Kolich published on April 4, 2009 8:45 PM.

Kolich.com Is Now Mobile Device Ready at http://kolich.mobi was the previous entry in this blog.

Configuring Ant To Use javac's -Xlint:unchecked Option is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.