How To Enable Static Brotli Compression In Apache 2.4

Web servers have been able to compress the content they serve for quite a while now. When they receive a request for an asset that lends itself to compression, usually a text file such as HTML or CSS it will compress it before sending it to the browser. The browser will then decompress the file and load it. This process cuts down on the amount of data that is served and also speeds up website loading.

The compression tool that has been used for this has been gzip. This is a solid compression algorithm but is getting quite old now. Google have developed a newer algorithm called Brotli that can be used in place of gzip.

Brotli has the advantage that for the same amount of CPU work a smaller compressed file is created. This magnifies the advantages of using compression to serve site content. In a dynamic configuration Apache will compress the website files every time they are served.

This can be avoided by pre-compressing the website files and getting Apache to serve the compressed files. This means that you only have to compress them once.

All the major browser - Chrome, Firefox, Safari, Edge - support brotli so lets configure Apache to use it.

Note, Apache is able to continue serving pages with gzip in addition to brotli and will only serve brotli compressed files to browsers that support it.

Install Brotli

This is usually a single package. On Debian, Ubuntu the following will work:

apt install brotli

And on CentOS and Fedora:

dnf install brotli

Compress some files

Not all browsers support brotli compression so you need to leave an uncompressed version next to the compressed file. This command will compress a file with brotli leaving the uncompressed original:

brotli -Z index.html

The -Z option tells brotli to use the most aggressive compression level resulting in the smallest file.

Configure Apache

Apache ships with the brotli module and so it just needs enabling, along with mod_rewriteon Ubuntu and Debian:

a2enmod brotli
a2enmod rewrite

Then restart Apache:

systemctl restart apache2

Now, open the VirtualHost entry for the site you want to serve the static files for. Add the following section:

<Files *.html.br>
    AddType "text/html" .gz
    AddEncoding br .br
</Files>

This tells Apache about .html.br files. If you also want to compress .js. .css and .svg (which you should) also add the following:

<Files *.js.br>
    AddType "text/javascript" .br
    AddEncoding br .br
</Files>
<Files *.css.br>
    AddType "text/css" .br
    AddEncoding br .br
</Files>
<Files *.svg.br>
    AddType "image/svg+xml" .br
    AddEncoding br .br
</Files>

Also, add the following rewrite rules that will send browsers that support brotli the compressed files:

RewriteEngine On
RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{REQUEST_FILENAME}.br -f
RewriteRule ^(.*)$ $1.br [L]

Here is a complete, example VirtualHost file:

<VirtualHost 1.2.3.4:443>

    DocumentRoot /var/www/
    ServerName example.com

    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    CustomLog /var/log/apache2/example.com.access.log common
    ErrorLog /var/log/apache2/example.com.error.log

    <Files *.html.br>
        AddType "text/html" .br
        AddEncoding br .br
    </Files>
    <Files *.js.br>
        AddType "text/javascript" .br
        AddEncoding br .br
    </Files>
    <Files *.css.br>
        AddType "text/css" .br
        AddEncoding br .br
    </Files>
    <Files *.svg.br>
        AddType "image/svg+xml" .br
        AddEncoding br .br
    </Files>

    RewriteEngine On
    RewriteCond %{HTTP:Accept-Encoding} br
    RewriteCond %{REQUEST_FILENAME}.br -f
    RewriteRule ^(.*)$ $1.br [L]

</VirtualHost> 

Finally, reload Apache:

systemctl restart apache2.service

Your webserver will now serve pre-compressed brotli content to browsers that support brotli.