Creating Installable Packages for Dynamic Modules

NGINX 1.11.5 and NGINX Plus R11 introduced support for compiling dynamic modules independently of NGINX itself. This allows users of NGINX and NGINX Plus to use the official builds from the NGINX, Inc. repositories and load in the dynamic modules they need. There are several sources of dynamic modules:

This blog focuses on the use of third‑party dynamic modules with NGINX and NGINX Plus. We discuss best practices for building, deploying, and upgrading dynamic modules in a production environment. For more basic module‑compilation instructions suitable for development and test environments, see Compiling Third‑Party Dynamic Modules for NGINX and NGINX Plus.

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 specified by a load_module directive. Shared objects are typically loaded from /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 open source version 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 http://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 or apt 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 a yum or apt 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 with apt(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.

  1. 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
  2. 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
  3. 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
  4. 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

Note that the name of the package is the same as the filename produced by the build script, without the version and platform information.

When installation is complete, a banner explains how to configure NGINX to load the newly installed dynamic module.

----------------------------------------------------------------------

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

To ensure a seamless upgrade, first build a new version of the dynamic module against the version of NGINX or NGINX Plus you intend to upgrade to. The following example shows the steps required to upgrade NGINX Plus from R11 to R12 with the RTMP dynamic module installed.

  1. 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
  2. Repeat Steps 2 and 3 from Setting Up a Private Repository for Seamless Upgrades to update the private repository with the new dynamic module.

  3. 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]:

Summary

Dynamic modules for NGINX and NGINX Plus enable you to compile only the specific extensions you require while taking advantage of the prebuilt and tested packages from NGINX, Inc. The pkg‑oss tooling and the build_module.sh script provide a straightforward solution to creating, installing, and upgrading third‑party modules for production deployments of NGINX and NGINX Plus.

Cover image
Advanced Recipes for High Performance Load Balancing
Get the most out of NGINX and NGINX Plus with this exclusive O'Reilly ebook