Serving compressed (gzipped) static files from Amazon S3 or CloudFront

It’s generally a good idea to serve gzipped versions of plain-text static assets (primarily CSS and JavaScript files) to web browsers. This can significantly reduce file size, which increases perceived website speed. All modern web browsers can transparently decompress gzipped files, thus the only real downside is a bit of additional CPU overhead.

Most default installations of Apache take care of this automatically via mod_deflate (Nginx uses the equivalent HttpGzipModule). Files are compressed on-the-fly and a Content-Encoding: gzip HTTP header is added to the response. However, since Amazon S3 is just a place to store files it lacks the ability to gzip files in real-time before delivering them. When using a website speed test application like WebPageTest, this can result in informational warnings that look like this:

Use gzip compression for transferring compressable responses: 90/100
FAILED - (52.1 KB, compressed = 40.6 KB - savings of 11.5 KB) -

To resolve this, files have to be compressed before being uploaded to S3. From Linux or OSX, this can be easily done with gzip -9 awesomeness.css, which creates a new, compressed version of “awesomeness.css.”

This new file is then uploaded to S3 and the following metadata is set on the bucket object:

Setting content-encoding and content-type on S3 bucket objects

The Content-Type header informs the web browser that the actual contents of the file is CSS markup while Content-Encoding specifies that it’s a gzipped file. Both HTTP headers (“metadata” in AWS-speak) are required for the browser to correctly interprete the file.

Gettin’ fancy

Manually gzipping each file and setting the correct metadata can get very tedious, very quickly. I would recommend that this process be automated as a build step on a continuous integration (CI) server (at RBN we use Jenkins): a post-commit hook on the source repository fires, triggering a build. The CI server performs a SVN export or Git clone, executes a shell script that gzips the files, and uploads them to S3 and sets the proper object metadata. If you’re not currently using CI in your development workflow, a more basic version of this process can be hacked together using only commit hooks. Though I would argue that this would be an opportune time to dip your toes into continuous integration.