Compiling dynamic NGINX modules is something that's kind of hard to find online. Especially if you want to compile them for an existing compiled copy of NGINX. This guide is going to walk through compiling the Upload module for NGINX on Ubuntu 18.04 using nginx from their repositories.
NGINX has already been compiled for us with various different options. If you install the nginx-extras
package you get NGINX compiled with a bunch of modules, but you can also use the nginx-full
or just nginx
packages to get less modules.
To compile our new dynamic module, we'll need to download the source code for NGINX, install any dependencies used when the Ubuntu package maintainers compiled it, and use the same flags they did.
Installing dependencies
You'll first need to install any dependencies for the NGINX modules you're compiling. For me, I needed the following:
sudo apt install libperl-dev libgeoip-dev libgd-dev
Downloading NGINX and module source code
You'll need to compile this against the same version of NGINX that's currently installed. You can find that by running nginx -v
. For me, we're using 1.14.0
so we'll download the source for that version.
wget https://nginx.org/download/nginx-1.14.0.tar.gz
tar zxf nginx-1.14.0.tar.gz
Then we need to download the source for our module. We're using the Upload module which can be found on Github. We'll grab the latest zip.
wget https://github.com/fdintino/nginx-upload-module/archive/master.zip
unzip master.zip
Find the NGINX compile flags
To make our module compatible with the existing NGINX binary, we need to use the same compile flags. We can find those by running the following command:
nginx -V
# nginx version: nginx/1.14.0 (Ubuntu)
built with OpenSSL 1.1.0g 2 Nov 2017
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-mcUg8N/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-headers-more-filter --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-auth-pam --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-cache-purge --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-dav-ext --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-ndk --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-echo --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-fancyindex --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/nchan --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-lua --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/rtmp --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-uploadprogress --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-upstream-fair --add-dynamic-module=/build/nginx-mcUg8N/nginx-1.14.0/debian/modules/http-subs-filter
Now this is a LOT of flags, but we can ignore any of the ones for --add-dynamic-module
because we don't need to compile those modules, just our new one. That leaves us with the following flags:
--with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-mcUg8N/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module
WARNING If you don't do this, you'll end up with an error later on when you try to load the module that looks like this: # module "/usr/lib/nginx/modules/ngx_http_upload_module.so" is not binary compatible in /etc/nginx/modules-enabled/50-mod-http-upload.conf:1
Make sure you use these same flags when compiling so you don't get this error.
Compiling the module
Now we just need to hop into the nginx source directory and compile the module. We will add the flag to compile our new dynamic module at the end after the other flags --add-dynamic-module=../nginx-upload-module-master
cd nginx-1.14.0
./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-mcUg8N/nginx-1.14.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --add-dynamic-module=../nginx-upload-module-master
make modules
If you're missing any dependencies, these configure and make commands might fail. Make sure you install any dependencies that are missing and try again.
Installing the compiled module
The last step is just to move the compiled module to a place that NGINX can find and tell NGINX to load it. We'll move the compiled dynamic module to /usr/lib/nginx/modules
where the other modules live and then create a config file telling NGINX to load that module.
sudo mv objs/ngx_http_upload_module.so /usr/lib/nginx/modules
echo 'load_module /usr/lib/nginx/modules/ngx_http_upload_module.so;' | sudo tee /etc/nginx/modules-enabled/50-mod-http-upload.conf
Testing the module
Last but not least we want to confirm everything is working. A quick check is we can run the following command to verify our config. If everything went well, you should get the following output.
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
And for the real test, you can add the module's lines to your nginx server block, restart nginx, and make sure they actually work.
Conclusion
Dynamic modules are awesome. While they might be a bit harder to compile, we don't have to worry about recompiling ALL of NGINX anymore if we want to use some new plugin. Hopefully this guide helps you get modules compiled for your OS so you can continue using your repository-provided copy of NGINX.