Monday, July 6, 2009

How To Serve Pre-Compressed Static Files in Apache

There are example snippets in various corners of the web on how to do this, but surprisingly it's hard to find real working examples.

Here's a snippet of Apache configuration that will serve out pre-compressed gzip files for javascript and css and set the proper Content-Type and Content-Encoding. For example, if the client requested myfile.js and accepts gzip encoding, Apache will look for a file named myfile.js.gz and send the contents of the compressed file instead. If the compressed file doesn't exist, it sends the uncompressed version.

Also note that this is proxy caching server friendly.

# Netscape 4.x has some problems... only compress html files
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 has problems... don't compress anything
BrowserMatch ^Mozilla/4\.0[678] no-gzip

# MSIE masquerades as Netscape
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

RewriteEngine on

# If the browser accepts gzip and the requested file exists with
# a .gz appended, then rewrite the request to the .gz file
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule (.*\.(css|js))$ $1\.gz [L]

#Set content type to JavaScript and the encoding to gzip
<FilesMatch ".*\.js\.gz$">
ForceType application/x-javascript
Header set Content-Encoding gzip

#Set content type to CSS and the encoding to gzip
<FilesMatch ".*\.css\.gz$">
ForceType text/css
Header set Content-Encoding gzip

# Tell caching proxy servers to cache the file based on both
# browser type and encoding
Header append Vary User-Agent
Header append Vary Accept-Encoding

# Do this to set proper ETags for server clusters
FileETag MTime Size


  1. One note about this. It does not work when the file system is different than the URL (aliases, war file, etc.). The only way to support this directly is to either use the RewriteCond with a -F flag or always guarantee that a .gz file exists with any files you're serving like this.

    However, beware of using the -F or -U flag because they cause a subrequest to itself. If you're doing this for performance reasons, it defeats the purpose of pre-compressing the file in the first place (i.e. you might as well use mod_deflate).