What is brotli?

brotli is a compression algorithm based on lz77 and huffman. Special about it is that it uses a dictionary of common words and phrases to achieve a better compression ratio than ordinary compression algorithms. See wikipedia for more details.

What is required to use brotli - client side?

Most modern browsers such as Firefox (since 44) and Chrome (50+) and Opera (36+) support brotli out of the box. They send an Accept-Encoding: gzip, deflate, br (or similar) header, with br for brotli.

What is required to use brotli - server side?

You'll need the brotli libraries and Apache httpd 2.4.26 or higher with mod_brotli.

Even though nginx also supports brotli, this document only covers Apache httpd.

httpd server configuration

This configuration falls back to mod_deflate either if mod_brotli is not found or the client doesn't know about brotli.

# Load filter module
LoadModule filter_module modules/mod_filter.so

# Load brotli module
LoadModule brotli_module modules/mod_brotli.so

# Load deflate module as fallback
LoadModule deflate_module modules/mod_deflate.so
<IfModule filter_module>

    <IfModule brotli_module>
        # declare a filter for brotli compression
        FilterDeclare  COMPRESS_BR CONTENT_SET
        # only compress certain content types 
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/html\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/plain\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/css\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/javascript\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^text/x-component\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/javascript\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/x-javascript\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/json\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/xhtml\+xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/rss\+xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/atom\+xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/vnd\.ms-fontobject\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^image/svg\+xml\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^image/x-icon\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^image/vnd\.microsoft\.icon\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/x-font-ttf\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/font-sfnt\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^application/vnd\.ms-fontobject\b#"
        FilterProvider COMPRESS_BR BROTLI_COMPRESS "%{Content_Type} =~ m#^font/opentype\b#"
        FilterProtocol COMPRESS_BR BROTLI_COMPRESS change=yes;byteranges=no
    </IfModule>

    <IfModule deflate_module>
        <IfModule setenvif_module>
            BrowserMatch ^Mozilla/4 gzip-only-text/html
            BrowserMatch ^Mozilla/4\.0[678] no-gzip
            BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        </IfModule>
        # declare a filter for deflate/gzip compression
        FilterDeclare  COMPRESS_GZ CONTENT_SET
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/html\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/plain\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/css\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/javascript\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^text/x-component\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/javascript\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/x-javascript\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/json\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/xhtml\+xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/rss\+xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/atom\+xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/vnd\.ms-fontobject\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^image/svg\+xml\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^image/x-icon\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^image/vnd\.microsoft\.icon\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/x-font-ttf\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/font-sfnt\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^application/vnd\.ms-fontobject\b#"
        FilterProvider COMPRESS_GZ DEFLATE "%{Content_Type} =~ m#^font/opentype\b#"
        FilterProtocol COMPRESS_GZ DEFLATE change=yes;byteranges=no
        FilterTrace    COMPRESS_GZ 1
    </IfModule>

    # client accepts brotli
    <If "%{HTTP:Accept-Encoding} =~ /\bbr\b/">
        <IfModule brotli_module>
            # we have brotli support
            FilterChain COMPRESS_BR
        </IfModule>
        <IfModule !brotli_module>
            # we do not have brotli support, fallback to deflate if the client supports it
            <If "%{HTTP:Accept-Encoding} =~ /\bdeflate\b/">
                <IfModule deflate_module>
                    FilterChain COMPRESS_GZ
                </IfModule>
            </If>
        </IfModule>
    </If>

    # client does not accept brotli, check for deflate support
    <ElseIf "%{HTTP:Accept-Encoding} =~ /\bdeflate\b/">
        <IfModule deflate_module>
            FilterChain COMPRESS_GZ
        </IfModule>
    </ElseIf>

</IfModule>

Testing

Request the brotli encoded website:
$ curl -s -i -H 'Accept-Encoding: gzip,deflate,br' https://www.unixadm.org/ | \
    sed -n '/^content-encoding:/Ip;/^\r$/q'
content-encoding: br
Test fallback to deflate/gzip:
$ curl -s -i -H 'Accept-Encoding: gzip,deflate' https://www.unixadm.org/ | \
    sed -n '/^content-encoding:/Ip;/^\r$/q'
content-encoding: gzip