Serving precompressed content with Nginx and Zopfli

Frederic Cambus March 11, 2013 [Nginx]

Zopfli is a new compression algorithm which has recently been opensourced by Google. Being deflate compatible, it can create compressed files which can then be unpacked using zlib, and thus served to web browsers without any modifications on client side.

Zopfli is focused on output efficiency, not on runtime performance, making it impractical to use for doing on-the-fly compression. It shines at compressing static content, and I will show you how in this article using Ascii Codes website as an example.

We start by fetching and compiling Zopfli:

git clone https://code.google.com/p/zopfli/
cd zopfli
make

The available options are as follow:

Usage: zopfli [OPTION]... FILE
  -h    gives this help
  -c    write the result on standard output, instead of disk filename + '.gz'
  -v    verbose mode
  --gzip  output to gzip format (default)
  --deflate  output to deflate format instead of gzip
  --zlib  output to zlib format instead of gzip
  --i5  less compression, but faster
  --i10  less compression, but faster
  --i15  default compression, 15 iterations
  --i25  more compression, but slower
  --i50  more compression, but slower
  --i100  more compression, but slower
  --i250  more compression, but slower
  --i500  more compression, but slower
  --i1000  more compression, but slower

We now compress the content (in our example, we want to pack HTML and CSS files):

zopfli *html *css

Alternatively, for maximum compression (1000 iterations):

zopfli --i1000 *html *css

Now, let's test the actual server configuration (Nginx + standard Gzip module):

curl https://www.ascii-codes.com --silent --header "Accept-Encoding: gzip,deflate" | wc -c
    6124

The file size is 6,124 bytes: we are getting gzip content compressed on-the-fly.

We now modify our Nginx virtual host configuration to add the following directive:

gzip_static on;

Let's reload Nginx configuration:

nginx -s reload

And finally, we test again (Nginx + Gzip Precompression module):

curl https://www.ascii-codes.com --silent --header "Accept-Encoding: gzip,deflate" | wc -c
    5621

As we can see, the file size is 5,621 bytes: it now serves the Zopfli precompressed content.

For reference, here is a comparison matrix of file sizes:

  file name |  original size |        gzip -9 |         zopfli | zopfli --i1000
------------|----------------|----------------|----------------|----------------
 cp737.html |   36,567 bytes |    6,001 bytes |    5,499 bytes |    5,494 bytes
 cp775.html |   36,040 bytes |    6,063 bytes |    5,540 bytes |    5,538 bytes
 cp850.html |   36,047 bytes |    6,149 bytes |    5,651 bytes |    5,646 bytes
 cp852.html |   36,120 bytes |    6,027 bytes |    5,493 bytes |    5,489 bytes
 cp855.html |   36,388 bytes |    6,079 bytes |    5,581 bytes |    5,578 bytes
 cp857.html |   35,861 bytes |    6,052 bytes |    5,575 bytes |    5,570 bytes
 cp860.html |   36,506 bytes |    6,132 bytes |    5,657 bytes |    5,652 bytes
 cp861.html |   37,185 bytes |    6,619 bytes |    6,268 bytes |    6,254 bytes
 cp862.html |   36,078 bytes |    6,102 bytes |    5,580 bytes |    5,577 bytes
 cp863.html |   36,421 bytes |    6,144 bytes |    5,677 bytes |    5,672 bytes
 cp865.html |   36,347 bytes |    6,154 bytes |    5,661 bytes |    5,659 bytes
 cp866.html |   36,595 bytes |    6,042 bytes |    5,541 bytes |    5,533 bytes
 cp869.html |   36,014 bytes |    6,007 bytes |    5,479 bytes |    5,474 bytes
 index.html |   36,035 bytes |    6,124 bytes |    5,631 bytes |    5,621 bytes

The results look pretty good indeed, and we can definitely achieve a non-negligible gain in file size using Zopfli instead of Gzip.

Every byte counts!

Back to top