In this guide I will be explaining how to compile the Brotli module for Nginx, a compression algorithm developed by Google, as an alternative to GZIP and Deflate. The reason for compiling the module is that Nginx has not officially supported the open source version, and in its Nginx Plus version it is supported.
Tested with systems:
- Debian 10 Buster
- Debian 11 Bullseye
- Ubuntu 20.04 Focal Fossa
- Ubuntu 22.04 LTS Jammy Jellyfish
Using Nginx versions:
- Nginx 1.14
- Nginx 1.18
Install Nginx
The first thing we need to do is install Nginx. If we are going to compile the module locally, we must use exactly the same distribution with the same repositories. Since we can simply copy it to production, but the environments must be the same. If in the final system we will use the nginx-full, nginx-extras or any other package, it is not a bad idea to install them as well, a small detail like this can take up many hours.
We install with:
sudo apt -y install nginx
Install dependencies
We update packages that have pending updates:
sudo apt update
sudo apt -y upgrade
We install the following packages:
sudo apt -y install git libpcre3 libpcre3-dev zlib1g zlib1g-dev libxslt1-dev openssl libssl-dev apt-src
Before the next step we edit our /etc/apt/sources.list
, and remove the #
symbol from the lines that have deb-src
, only from the repositories that are being used.
sudo nano /etc/apt/sources.list
In an Ubuntu installation, the repositories come like this:
deb http://archive.ubuntu.com/ubuntu focal main restricted
# deb-src http://archive.ubuntu.com/ubuntu focal main restricted
We have to uncomment each repository that we find under each deb
.
After editing it it should look like this:
deb http://archive.ubuntu.com/ubuntu focal main restricted
deb-src http://archive.ubuntu.com/ubuntu focal main restricted
Then update the apt and apt-src cache:
sudo apt update && sudo apt-src update
Download Nginx and Brotli source code
We create a directory to save everything in our user's home directory:
cd ~ && mkdir nginx-brotli && cd nginx-brotli
We start by downloading the Nginx source code with apt-src
so that it matches the installed version of the system:
sudo apt-src install nginx
Then we download the Brotli source code from the official Google repository:
cd ~/nginx-brotli
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli
git submodule update --init
Compile Brotli as a dynamic module
We change the directory to that of Nginx:
cd ~/nginx-brotli/nginx-*/
We execute the following:
sudo ./configure --with-compat --add-dynamic-module=../ngx_brotli
If no error appears, we run:
sudo make modules
And if everything went well, we go to the Nginx Configuration section.
In case of error using configure
When we get error while executing ./configure
above. We follow the following steps.
We run the following command to see the build options that the installed version of Nginx uses:
sudo nginx -V
We copy all the options after the text configure arguments:
, we remove all the options that begin with --add-dynamic-module
and we add them to the end separated with a space:
--add-dynamic-module=../ngx_brotli
At the beginning, we add sudo ./configure
and a space to separate the options. It should be something similar to the following:
sudo ./configure OPCIONES_DEL_COMANDO --add-dynamic-module=../ngx_brotli
The resulting command is usually several lines long, I summarized it with "COMMAND_OPTIONS" to make it more understandable. We execute it as a command.
We can use the following command to generate the complete command instead of doing it manually:
sudo nginx -V 2>&1 | grep '^configure arguments:' | sed -r 's/--add-dynamic-module=(\S)+(\s|$)//g; s/$/\-\-add\-dynamic\-module=\.\.\/ngx_brotli/g; s/configure arguments:/sudo \.\/configure/g'
The above command modifies the output of nginx -V
and turns it into the command we need to compile Nginx. We copy it and execute.
Copy from where it says sudo ./configure...
.
Lastly, we run:
sudo make modules
Nginx configuration
Copy the resulting files ngx_http_brotli_filter_module.so
and ngx_http_brotli_static_module.so
to the /etc/nginx/modules-available
directory:
sudo cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules-available
sudo cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules-available
We create the file /etc/nginx/modules-enabled/50-brotli.conf
:
sudo nano /etc/nginx/modules-enabled/50-brotli.conf
And we add the following references to the modules:
load_module /etc/nginx/modules-available/ngx_http_brotli_filter_module.so;
load_module /etc/nginx/modules-available/ngx_http_brotli_static_module.so;
We test the configuration and modules with:
sudo nginx -t
If everything is fine it will appear:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Otherwise, if there is any problem, the output will be:
nginx: [emerg] module ngx_http_brotli_filter_module.so is not binary compatible in nginx.conf...
If we do not know why we have errors, we must pay attention to the command, configure
and review all the errors that appear at the end. It would also not hurt to check if we are using the same version, and if the target system is different, even more so. As long as we do not restart Nginx, there would be no problem because the last command only reviews the configuration without making any changes.
To end the mess left behind, delete the used source files:
sudo rm -R ~/nginx-brotli/
Use in other production or development systems
Since everything is checked and the versions of the operating system and software match, we can copy the files that were left in /etc/nginx/modules-available
. Taking into account that every time there is an update, no matter how minimal, we have to recompile the modules to make them compatible. It wouldn't hurt to rename them so that they have the format, module-1.14-2.so
referring to the version of Nginx for which they were compiled. In addition to copying them, we have to perform the previous steps, such as re-editing the Nginx configuration file to load the modules and double-checking the configuration before rebooting.
Block Nginx package update
If we want to avoid accidents, we can use the apt-mark
utility to force the package manager not to update Nginx, but to update the rest of the packages.
Block installed version:
sudo apt-mark hold nginx
To unlock the package after placing new modules and checking your new configuration:
sudo apt-mark unhold nginx
Restart Nginx if there is no problem
To restart Nginx after checking that the modules are working, use:
sudo systemctl restart nginx
Activation and use of modules
At this point Nginx already has the modules loaded, we just need to activate and configure them, and at the end we will check if they are working.
We edit the nginx.conf
file:
nano /etc/nginx/nginx.conf
Exactly, below gzip on;
we place on a new line:
brotli on;
Then we look for a line that has gzip_types
, if it starts with "#" we remove it, copy it completely and place the new one below it, the result will be something similar:
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
Both lines must have the same arguments to take full advantage of the new compression algorithm.
We check that the configuration works with sudo nginx -t
and restart the service:
sudo systemctl restart nginx
For the ngx_http_brotli_static_module.so
module you have to use it the same as the gzip_static
option, we can check the directive in the Google repository, or the gzip_static directive in Nginx.
Checking the operation of the compression algorithm
For this we will need to use Firefox, Chrome, or any browser that supports this algorithm. If it is the same system where we have the package installed, we open 127.0.0.1 in the browser and open the developer tools with F12, and go to the Network tab. We click on the URL and verify that in Response Headers in Content-Encoding it appears "br", in Request Headers and Accept-Encoding we verify that it appears "gzip, deflate, br" in any order. If "br" does not appear in Content-Encoding, it means that the server did not send the content with the new algorithm, and if "br" does not appear in Accept-Encoding, it may be that the browser does not support it, or it is simply not activated for the type of document.
If we have problems with Firefox it could be because Brotli is not supported on connections without SSL, and since in this case we use localhost it may not work locally. To test without SSL, we can use Chrome, which at least in version 84 supports it without HTTPS.
I relied on this post from the Website for Students, although I had problems in the binary compatibility step. In the official Brotli repository comes little information about the build.