An Apache httpd .conf file and an apple being compressed, because I couldn't find an image of broccoli.

Building mod_brotli for Apache httpd on Amazon Linux AMI

Other than a few shouts into the wind around the web, I couldn't find anyone talking about using Apache httpd's mod_brotli on Amazon Linux. Apache shipped mod_brotli in version 2.4.26. As of writing, Amazon has the latest version of httpd available via their repository (v2.4.41), but it seems they must just not build their version with the very required --enable-brotli flag! Today, I'll show you how to build it yourself, and configure your httpd install to load it up and start serving brotli compressed content!

A Few Assumptions First

First, I want to outline a few assumptions I'm making here. Mostly they're just "out of the box" defaults for the the Amazon Linux AMI, but I just want to clarify them for any other non-Amazon Linux users. Note that what I'm doing here applies to the original Amazon Linux AMI. It may very well work for Amazon Linux 2, but I haven't yet tested that. It’s possible that AL2's httpd may come with mod_brotli! (If you use AL2, and it does come standard, or these instructions worked for you, please let me know!) On that note, on with the assumptions:

  • I installed httpd via yum install httpd24.
  • I'm using httpd 2.4.41, the latest available via the amzn-main repo. (Check via httpd -v if you're curious.)
  • My httpd directory is /etc/httpd (this is the directory with conf, conf.d, conf.modules.d, and modules in it.)
  • My httpd service is named httpd. I'm using the default sysvinit scripts that come with httpd on Amazon Linux.
  • I'm running all the commands below as superuser, via sudo su.
    • All of the commands below do not need root, but yum and editing httpd config both will, at minimum. If you decide to follow in my footsteps, just be careful!

Getting Prerequisites

The default Amazon Linux AMI available on EC2 comes with what Amazon touts is a secure, lightweight configuration. Because of this, some of the development tools used to build software aren't installed by default. Over time, on my development instance, I've added several different tools, but there were a few more I needed in order to build httpd. At minimum, you're going to need to add EPEL as a repository; Amazon's repo doesn't have the brotli library we need, but EPEL does. EPEL is the "Extra Packages for Enterprise Linux" repository, it is managed by the Fedora Project.

Fortunately, it's easy enough to install the repo, via yum directly!

# install epel as a yum repo source, via yum!
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# after the install, turn the repo on.
yum-config-manager --enable epel # enable epel

We're also going to be getting copies of code repos from the Apache Software Foundation. As the group behind subversion, that's what they use for source control, so we'll need that too!

yum install subversion

Apache httpd makes use of a handful of different tools as part of their build chain. The ones I'm installing here are the ones I needed to add to my system for this particular build. You may need more packages (such as `gcc, etc.), so install those as you need. You will however need:

# libtool is used by httpd's ./buildconf script, as well as part of the actual build process.
yum install libtool
# expat-devel is an xml parsing library httpd uses,
# pcre-devel is a library for regular expressions,
# and brotli-devel is the actual compression library mod_brotli will use.
yum install expat-devel pcre-devel brotli-devel

Getting the Source

Once you've got those, we can set up our staging area and grab a copy of the httpd source. Since we actually aren't going to install the copy of httpd we build (because we've already got a running httpd,) it's not super important where you put it. I kept it in my home directory.

# make a folder for us to grab code in.
# my home directory is /root, as I'm running this as such.
cd ~
mkdir httpd-asf

# switch into it,
cd httpd-asf

# make an 'install' folder, though we aren't going
# to use it, I was afraid to upset autoconf.
mkdir 2.4.41-install

# grab a copy of httpd 2.4.41!
# this is from the tag, so it's going to be all
# the code exactly as it shipped for 2.4.41.
# this is going to take a bit as it copies the files from the web.
svn co http://svn.apache.org/repos/asf/httpd/httpd/tags/2.4.41

# switch into that newly created folder.
cd 2.4.41

# grab a copy of Apache Portable Runtime (https://apr.apache.org/)
# httpd expects it, and if it's right in srclib/apr, it won't need you to tell it where to look!
svn co http://svn.apache.org/repos/asf/apr/apr/trunk srclib/apr

Building Apache httpd

Now we've got all the bits we need. Now it's time for just three commands. ./buildconf, as the INSTALL file explains, will bootstrap the installation environment, ensuring you've got python, autoconf, and libtool. If it gives you any errors, it should be very exact about the things you're missing and need to install. They're almost certainly a yum install away.

Second, we're going to run ./configure. Anyone familiar with GNU Autoconf will know this auto-generated script. It's job is to search your system for headers, tools, and libraries the project depends on. It's going to take a good while to run, and may very well error out on you. Multiple times. Don't stress, just figure out which package it may need, install it, and go again.

Once you've made it over that hurdle, the rest should be smooth sailing. One call to make and you're well on your way to your own fresh httpd binaries. Only the speed of your CPU can slow you down at this point!

# buildconf is pretty friendly about telling you what
# you need if it can't find a tool it expects
./buildconf

# configure is less friendly, but between the power of yum
# (and a little googling if yum search isn't helping),
# you should be able to find everything it asks for.
# the flags we're passing here do two things
#
# --prefix=/root/httpd-asf/2.4.21-install
#   will tell make where the 'install' will go, if you did it.
#
# --enable-brotli
#   mod_brotli won't build if you don't pass this flag.
#
# there's a good number of other options httpd will build with,
# but we don't care, so we'll skip them for now.
#
./configure --prefix=/root/httpd-asf/2.4.41-install --enable-brotli

# if you're here, you've made it over those hurdles.
# now's time to press 5 keys, sit back, relax, and watch code compile!
make

If you're seeing a lot of 'Leaving directory' and not heaps of errors, then that is good news! You just built httpd and are ready to pluck a fresh mod_brotli.so (the shared library that httpd loads as a module) from the build to use with your httpd! Let's copy and plop it right in our modules folder.

# copy mod_brotli.so to your modules folder
cp ./modules/filters/.libs/mod_brotli.so /etc/httpd/modules/mod_brotli.so

Loading & Configuring mod_brotli

The last thing to do now, is to just tell httpd about the module you just copied in!

# head to our modules configuration folder,
cd /etc/httpd/conf.modules.d

# create a new .conf file that will be in charge of loading mod_brotli
# obviously you can use whatever text editor you want here.
/your/preferred/text/editor 05-brotli.conf

The minimum you need to do in the conf file is just the LoadModule modules/mod_brotli.so line to tell httpd to load the module. You're very likely going to want to tell httpd that it should go ahead and feel free to compress some common file types, using AddOutputFilterByType. Apache has documentation on mod_brotli that explains how to configure the module. I personally went ahead and defined some other configuration options; But that's entirely up to you.

Here's my 05-brotli.conf if you don't feel like writing your own.

# See https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html
# for configuration directive explanation and more!

# Load mod_brotli!
LoadModule brotli_module modules/mod_brotli.so

<IfModule mod_brotli.c>

        # Let ETags point out the data was compressed with brotli (default AddSuffix, other options: NoChange, Remove)
        BrotliAlterETag AddSuffix

        # Set the max input block to the minimum, to save on server memory (16-24, default automatic)
        BrotliCompressionMaxInputBlock 16

        # Set the compression quality level, lower will be faster but worse compression (0-11, default 5)
        BrotliCompressionQuality 5

        # Set the compression window size, larger is better quality, but needs more memory (10-24, default 18)
        BrotliCompressionWindow 18

        # See the documentation for BrotliFilterNote if you want to log input/output/ratio numbers:
        # https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html#brotlifilternote

        # Globally configure to compress common text types!
        AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/javascript
</IfModule>

Save and exit your editor... and that's basically it! Let's just check our work and let httpd reload!

# have httpd tell us if we made a typo in our config,
# or if things won't load for some reason
service httpd configtest

# if you see "Syntax OK", you're good to go, gracefully reload httpd!
service httpd graceful

Assuming httpd comes back up, you're done! Fire up Chrome (or your favorite brotli enabled HTTP request maker,) and make a request to a file type you marked as should be filtered, and enjoy your wonderful compression goodness.

Wrapping Up

I realize this is a super focused retelling of my experience; However as I couldn't find anyone else that had described how to get mod_brotli going on Amazon Linux. I wanted to, so I thought I'd share and hopefully help someone else along the way.

If you don't want to try and go through the process of building all this yourself, and you're just crazy enough to run code built by me, you're welcome to give my mod_brotli.so a shot. It's licensed under the Apache License 2.0, the same as Apache httpd itself. The sha256sum for my build is e30de06bc662ede2c2d3024c45fc3e1f4bacb0ca5cd7bbdd9e221da902398379.

If you have things you think I should add or change here, please don't hesitate to reach out! If I helped you out and you you'd like to buy me a coffee, I'd love it, but certainly don't expect it.