Oct 15, 2017

How to compile dynamic modules for NGINX (HTTP Redis as an example)

Alexey Doronin
Founder, developer, designer

Connecting additional modules to NGINX is not the most trivial thing for web developers. Consider this task in the example build NGINX with the HTTP Redis module (ngx_http_redis).

Previously, to connect modules to NGINX, it was necessary to fully compile both the web server and the required modules, but starting from version 1.9.11, you don't have to do that. Just use the make modules command, but you need to correctly configure the entire NGINX build.

So, first you need to know which version of NGINX is installed. If less than 1.9.11, then read Installing the latest NGINX.

nginx -v

##
nginx version: nginx/1.13.5

Download and unpack to the home directory the same version of NGINX (in our case 1.13.5):

wget https://nginx.ru/download/nginx-1.13.5.tar.gz
tar -xzvf nginx-1.13.5.tar.gz

Download and unpack HTTP Redis module:

wget https://people.freebsd.org/~osa/ngx_http_redis-0.3.8.tar.gz
tar -xzvf ngx_http_redis-0.3.8.tar.gz

So, we should have:

1. Installed and running NGINX> = 1.9.11

2. NGINX distribution of the same version as in clause 1

3. Downloaded HTTP Redis module

Now we can compile the module and connect it in the nginx.conf file with the command load_module my_module.so.

We need to know the current NGINX build configuration (remember result of this command):

nginx -V

Go to the directory where you unpacked the downloaded NGINX:

cd nginx-1.13.5/

Preparing for the build. It takes place in two stages: "configure" and "make".

Configure

You need to run the ./configure command with the options that were shown in nginx -V. In my case (Ubuntu 16, nginx 1.13.5) it looks like:

./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' --add-dynamic-module=../ngx_http_redis-0.3.8

At the end, the path to the dynamic module is added, which needs to be compiled (we are in the ~/nginx-1.13.5 directory). Don't forget to add it:

--add-dynamic-module=../ngx_http_redis-0.3.8

Press Enter. If you are lucky and there are no errors in the output, great!

Make

Next, make a module:

make modules

If there are no errors, you will have a file:

nginx-1.13.5/objs/ngx_http_redis_module.so

To connect this module to NGINX, you need to add a line with load_module to the /etc/nginx/nginx file.conf. To the top. Specify the full path to the file:

sudo nano /etc/nginx/nginx.conf
 
## Load our module:
load_module /home/vagrant/nginx-1.13.5/objs/ngx_http_redis_module.so;

Reload NGINX:

sudo nginx -s reload

If there is no error message, then everything is worked! You can copy the ngx_http_redis_module.so file to a more suitable place. And do not forget to change the path to it in nginx.conf.

NGINX update

The module is tied to a specific version of NGINX, if we update it, then most likely it will stop working. So you need the NGINX package to put on hold — block package from updates:

## sudo apt-mark hold <package>
sudo apt-mark hold nginx

## Remove HOLD
# sudo apt-mark unhold <package-name>

## Check HOLD
#apt-mark showhold

Issues and problems

«Configure» issues

1. The build configuration fails, the ./configure command returns an error (you cannot run make modules after this).

Errors like this: 

./configure: error: the HTTP gzip module requires the zlib library.
You can either disable the module by using --without-http_gzip_module
option, or install the zlib library into the system, or build the zlib library
statically from the source with nginx by using --with-zlib=<path> option.

In this example, if we change the configuration (to pass ./configure) and put --without-http_gzip_module, most likely, at the connection stage, the module will not work with nginx (see below).

In the process, there may be different requirements for libraries that are needed for the NGINX build (or not).These packages may need to be installed (or may already be installed):

1. "./configure: error: C compiler cc is not found"

sudo apt-get install build-essential

2. PCRE

sudo apt-get install libpcre3
sudo apt-get install libpcre3-dev

3. OpenSSL

sudo apt-get install libssl-dev

4. HTTP XSLT module requires the libxml2/libxslt

sudo apt-get install libxml2
sudo apt-get install libxml2-dev
sudo apt-get install libxslt-dev

5. «...the HTTP image filter module requires the GD library»

sudo apt-get install libgd-dev

6. GeoIP

sudo apt-get install libgeoip-dev

7. PAM authentication module

sudo apt-get install libpam-dev

Connectivity issues

When the module was compiled but the connection to NGINX is not working:

— Module module-name.so was compiled, but when you restart NGINX, a message is displayed that the version is not correct.  In this case it's necessary to double-check and download the appropriate version.

— «is not binary compatible» an error like this:

nginx: [emerg] module "/usr/share/nginx/modules/ngx_http_redis_module.so" is not binary compatible in /etc/nginx/nginx.conf:1

This means that the module build is configured incorrectly. You need to deal with ./configure options: incorrectly copied, not all dependencies installed and so on.