- The first post provides step-by-step instructions for compiling third‑party dynamic modules which can be loaded by NGINX or NGINX Plus at runtime.
- This post provides guidance and tooling for automating third‑party dynamic module builds for a production environment. It explains how to create installable packages for third‑party dynamic modules that include version dependency checking.
- Official repository of prebuilt NGINX Open Source packages and modules
- Official repository of NGINX Plus dynamic modules, which includes NGINX Plus Certified Modules
- Third‑party (community) modules
The Problem with .so Files
When you compile a dynamic module, the raw output is a shared object (.so file). At startup and reload, NGINX and NGINX Plus load each of the shared objects named by aload_module
directive (which by convention are in the main configuration file, nginx.conf). The conventional directory for shared objects is /etc/nginx/modules.
Dynamic modules are binary‑compatible with the official builds of NGINX and NGINX Plus. However, this binary compatibility has limitations. Dynamic modules must be compiled against the same version of NGINX they are loaded into. For NGINX Plus, dynamic modules must be compiled against the version of NGINX Open Source that NGINX Plus is built on. This means that upgrading NGINX or NGINX Plus without first installing a new version of the dynamic module built against the matching version results in a failed upgrade.
Manually managing the dependency between NGINX and its dynamic modules is error‑prone. Dynamic module .so files do not indicate which version of NGINX they were built against, which makes the process of manually copying them around somewhat precarious. In a development environment this is generally acceptable, but for production environments dependencies need to be protected and upgrades automated.
The goal is for all dynamic modules to be automatically upgraded when you upgrade NGINX or NGINX Plus, regardless of whether the module was provided by NGINX, a Certified Module vendor, or a third‑party provider.
Packaging Dynamic Modules with Dependencies
If you use the official repositories for NGINX or NGINX Plus then you are already familiar with using a package manager to install and upgrade NGINX –yum
for Red Hat/CentOS, apt
for Ubuntu/Debian. The official NGINX and NGINX Plus repositories also contain installable packages for a number of dynamic modules. The metadata of a dynamic module package indicates the NGINX version the module was compiled against, automatically triggering an upgrade of the module during NGINX or NGINX Plus upgrade.
Using installable packages for third‑party dynamic modules is the key to honoring the dependency with NGINX, avoiding upgrade failures, and facilitating seamless upgrades.
NGINX, Inc. uses automated tooling to create the dynamic module packages for our official repositories. This tooling, called pkg-oss, can also be used to create installable packages for third‑party modules.
You can use the pkg‑oss tooling to create an installable package for any dynamic module. It also includes a script, build_module.sh, that automates the process, as an example of how to create an installable package with the correct dependency on NGINX or NGINX Plus. Simply specify the version of NGINX or NGINX Plus and the location of the dynamic module sources. The module sources may be on the local disk, point at a GitHub repo, or be a general download link. The following example builds the RTMP module for NGINX Plus R11 on Ubuntu/Debian.
$ wget https://hg.nginx.org/pkg-oss/raw-file/default/build_module.sh
$ chmod a+x build_module.sh
$ ./build_module.sh -r 11 https://github.com/arut/nginx-rtmp-module.git
…
build_module.sh: INFO: Module packages created
~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb
~/debuild/nginx-plus-module-rtmp-dbg_1.11.5_amd64.deb
The filename indicates the module was built against the base NGINX version for NGINX Plus R11 (1.11.5
), and we can confirm that by examining the package metadata.
$ dpkg-deb -f ~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb Depends
libc6 (>= 2.14), nginx-plus (>> 1.11.4), nginx-plus (<< 1.11.6)
When using the build_module.sh script, take note of the following points.
Run the script in a build environment
In a production environment, it is best practice to install only the software necessary for correct operation, which does not include tools required for compiling and packaging dynamic modules. We recommend running the build_module.sh script in a separate build environment, but on the same platform as production.The script does not work for every module
The script has been tested successfully on the vast majority of third‑party modules available for NGINX. It even attempts to upgrade static modules to dynamic modules on the fly. However, some modules have additional compile‑time dependencies that the script cannot predict, or need to be packaged with other software components.Installable packages are not intended for redistribution
The script creates installable packages for internal use. There is no copyright, license, or documentation included in the package. If you are planning to redistribute a module as an installable package then you can use the pkg‑oss tooling to define a custom package.Seamless upgrades require a
yum
orapt
repository
The script provides a convenient way of building installable packages for dynamic modules, but it does not automatically provide a seamless upgrade solution unless the package is installed from ayum
orapt
repository. The remainder of this article describes how to achieve seamless upgrades.
Setting Up a Private Repository for Seamless Upgrades
Many organizations use private repositories for distributing software. After copying the .deb or .rpm files produced by the NGINX pkg‑oss tooling to such a repository, you can install, remove, and upgrade dynamic modules with the same package manager you use to install NGINX and NGINX Plus. If you do not have a private repository, then it is a simple exercise to create one locally on the server. To illustrate this process we show how to create a private repository for Ubuntu/Debian and Red Hat/CentOS so that our dynamic module can be installed withapt(8)
or yum(8)
respectively. Note that these steps require root
access. Also, we’ve omitted the command prompt in this section to facilitate copying and pasting.
Prepare dependencies and create the local repository for the package manager.
On Ubuntu/Debian systems:
$ mkdir /opt/deb $ echo “deb file:/opt deb/” > /etc/apt/sources.list.d/local.list
On Red Hat/CentOS systems:
$ yum install createrepo $ mkdir /opt/rpm $ cat << EOF > /etc/yum.repos.d/localrepo.repo [localrepo] name=Dynamic modules for NGINX baseurl=file:///opt/rpm gpgcheck=0 enabled=1 EOF
Copy the installable package for the dynamic module to the local repository.
On Ubuntu/Debian systems:
$ cp ~/debuild/nginx-plus-module-rtmp_1.11.5_amd64.deb /opt/deb
On Red Hat/CentOS systems:
$ cp ~/rpmbuild/RPMS/x86_64/nginx-plus-module-rtmp-1.11.5-1.el7.centos.ngx.x86_64.rpm /opt/rpm
Update the package manager to be aware of the dynamic module package.
On Ubuntu/Debian systems:
$ cd /opt && dpkg-scanpackages deb | gzip > deb/Packages.gz $ apt-get update
On Red Hat/CentOS systems:
$ createrepo -v /opt/rpm $ yum clean all $ yum update
Repeat Steps 2 and 3 for each module.
Installing a Module from a Private Repository
When a dynamic module is stored in a private repository, you can use the local package manager to install it.On Ubuntu/Debian systems:
$ apt-get install nginx-plus-module-rtmp
On Red Hat/CentOS systems:
$ yum install nginx-plus-module-rtmp
———————————————————————-
The rtmp dynamic module for nginx has been installed.
To enable this module, add the following to /etc/nginx/nginx.conf
and reload nginx:
load_module modules/ngx_rtmp_module.so;
———————————————————————-
Seamless Upgrade
With the dynamic module installed in this way, you are protected from version mismatch during upgrades of NGINX or NGINX Plus. If an upgrade of NGINX or NGINX Plus is attempted before installed dynamic modules are upgraded, the local package manager reports the problem.On Ubuntu/Debian systems:
$ apt install nginx-plus … The following packages will be REMOVED nginx-plus-module-rtmp The following packages will be upgraded: nginx-plus Do you want to continue? [Y/n]
On Red Hat/CentOS systems:
$ yum install nginx-plus … Error: Package: nginx-plus-module-rtmp-1.11.5-1.el7.centos.ngx.x86_64 (@localrepo) Requires: nginx-plus = 1.11.5
Build the dynamic module for NGINX Plus R12.
$ ./build_module.sh -r 12 https://github.com/arut/nginx-rtmp-module.git … build_module.sh: INFO: Module packages created ~/debuild/nginx-plus-module-rtmp_1.11.10_amd64.deb ~/debuild/nginx-plus-module-rtmp-dbg_1.11.10_amd64.deb
Repeat Steps 2 and 3 from Setting Up a Private Repository for Seamless Upgrades to update the private repository with the new dynamic module.
Upgrade NGINX Plus.
On Ubuntu/Debian systems:
$ apt-get install nginx-plus Reading package lists… Done Building dependency tree Reading state information… Done The following packages will be upgraded: nginx-plus nginx-plus-module-rtmp 2 to upgrade, 0 to newly install, 0 to remove Need to get 2,571 kB/2,731 kB of archives. After this operation, 411 kB of additional disk space will be used. Do you want to continue? [Y/n]
On Red Hat/CentOS systems:
$ yum install nginx-plus … Resolving Dependencies –> Running transaction check —> Package nginx-plus.x86_64 0:1.11.5-1.el7.ngx will be updated –> Processing Dependency: —> Package nginx-plus-module-rtmp.x86_64 0:1.11.5-1.el7.centos.ngx will be updated –> Finished Dependency Resolution Dependencies Resolved ========================================================================= Package Arch Version Repository Size ========================================================================= Updating: nginx-plus x86_64 1.11.10-3.el7.ngx nginx-plus 2.4 M Updating for dependencies: nginx-plus-module-rtmp x86_64 1.11.10-1.el7.centos.ngx localrepo 176 k Transaction Summary ========================================================================= Upgrade 1 Package (+1 Dependent package) Total download size: 2.6 M Is this ok [y/d/N]: