NGINX Unit

Working With Language Modules§

Languages supported by Unit fall into these two categories:

  • External (Go, Node.js): Run outside Unit with an interface layer to the native runtime.
  • Embedded (Java, Perl, PHP, Python, Ruby, WebAssembly): Execute in runtimes that Unit loads at startup.

For any specific language and its version, Unit needs a language module.

External Language Modules§

External modules are regular language libraries or packages that you install like any other. They provide common web functionality, communicating with Unit from the app’s runspace.

In Go, Unit support is implemented with a package that you import in your apps to make them Unit-aware.

In Node.js, Unit is supported by an npm-hosted package that you require in your app code. You can install the package from the npm repository; otherwise, build it for your version of Node.js using Unit’s sources.

For WebAssembly, Unit delegates bytecode execution to the Wasmtime runtime that is installed with the language module module or during a source build.

Embedded Language Modules§

Embedded modules are shared libraries that Unit loads at startup. Query Unit to find them in your system:

$ unitd -h

       ...
      --log FILE           set log filename
                           default: "/default/path/to/unit.log"

      --modules DIRECTORY  set modules directory name
                           default: "/default/modules/path/"

$ ps ax | grep unitd
      ...
      unit: main v1.34.0 [unitd --log /runtime/path/to/unit.log --modules /runtime/modules/path/ ... ]

$ ls /path/to/modules

      java.unit.so  php.unit.so     ruby.unit.so  wasm_wasi_component.unit.so
      perl.unit.so  python.unit.so  wasm.unit.so

To clarify the module versions, check the Unit log to see which modules were loaded at startup:

# less /path/to/unit.log
      ...
      discovery started
      module: <language> <version> "/path/to/modules/<module name>.unit.so"
      ...

If a language version is not listed, Unit can’t run apps that rely on it; however, you can add new modules:

  • If possible, use the official language packages for easy integration and maintenance.
  • If you installed Unit via a third-party repo, check whether a suitable language package is available there.
  • If you want a customized yet reusable solution, prepare your own package to be installed beside Unit.

Packaging Custom Modules§

There’s always a chance that you need to run a language version that isn’t yet available among the official Unit packages but still want to benefit from the convenience of a packaged installation. In this case, you can build your own package to be installed alongside the official distribution, adding the latter as a prerequisite.

Here, we are packaging a custom PHP 7.3 module to be installed next to the official Unit package; adjust the command samples as needed to fit your scenario.

Note

For details of building Unit language modules, see the source code howto; it also describes building Unit itself. For more packaging examples, see our package sources.

Assuming you are packaging for the current system and have the official Unit package installed:

  1. Make sure to install the prerequisites for the package. In our example, it’s PHP 7.3 on Debian 10:

    # apt update
    
    # apt install ca-certificates apt-transport-https debian-archive-keyring
    
    # curl --output /usr/share/keyrings/php-keyring.gpg  \
          https://packages.sury.org/php/apt.gpg
    
    # echo "deb [signed-by=/usr/share/keyrings/php-keyring.gpg]  \
          https://packages.sury.org/php/ buster main" > /etc/apt/sources.list.d/php.list
    
    # apt update
    
    # apt install php7.3
    
    # apt install php-dev libphp-embed
    
  2. Create a staging directory for your package:

    $ export UNITTMP=$(mktemp -d -p /tmp -t unit.XXXXXX)
    $ mkdir -p $UNITTMP/unit-php7.3/DEBIAN
    $ cd $UNITTMP
    

    This creates a folder structure fit for dpkg-deb; the DEBIAN folder will store the package definition.

  3. Run unitd --version and note the ./configure flags for later use, omitting --ld-opt and --njs:

    $ unitd --version
    
        unit version: 1.34.0
        configured as ./configure FLAGS
    
  4. Download Unit’s sources, configure and build your custom module, then put it where Unit will find it:

    $ curl -O https://sources.nginx.org/unit/unit-1.34.0.tar.gz
    $ tar xzf unit-1.34.0.tar.gz                                 # Puts Unit's sources in the unit-1.34.0 subdirectory
    $ cd unit-1.34.0
    $ ./configure FLAGS W/O --LD-OPT & --NJS                     # Use the ./configure flags noted in the previous step
    $ ./configure php --module=php7.3 --config=php-config        # Configures the module itself
    $ make php7.3                                                # Builds the module in the build/ subdirectory
    $ mkdir -p $UNITTMP/unit-php7.3/MODULESPATH                  # Use the module path set by ./configure or by default
    $ mv build/php7.3.unit.so $UNITTMP/unit-php7.3/MODULESPATH   # Adds the module to the package
    
  5. Create a $UNITTMP/unit-php7.3/DEBIAN/control file, listing unit with other dependencies:

    Package: unit-php7.3
    Version: 1.34.0
    Comment0: Use Unit's package version for consistency: 'apt show unit | grep Version'
    Architecture: amd64
    Comment1: To get current architecture, run 'dpkg --print-architecture'
    Comment2: For a list of other options, run 'dpkg-architecture -L'
    Depends: unit (= 1.34.0-1~buster), php7.3, libphp-embed
    Comment3: Specify Unit's package version to avoid issues when Unit updates
    Comment4: Again, run 'apt show unit | grep Version' to get this value
    Maintainer: Jane Doe <j.doe@example.com>
    Description: Custom PHP 7.3 language module for NGINX Unit 1.34.0
    

    Save and close the file.

  6. Build and install the package:

    $ dpkg-deb -b $UNITTMP/unit-php7.3
    # dpkg -i $UNITTMP/unit-php7.3.deb
    

Assuming you are packaging for the current system and have the official Unit package installed:

  1. Make sure to install the prerequisites for the package. In our example, it’s PHP 7.3 on Fedora 30:

    # yum install -y php-7.3.8
    
    # yum install php-devel php-embedded
    
  2. Install RPM development tools and prepare the directory structure:

    # yum install -y rpmdevtools
    
    $ rpmdev-setuptree
    
  3. Create a .spec file to store build commands for your custom package:

    $ cd ~/rpmbuild/SPECS
    
    $ rpmdev-newspec unit-php7.3
    
  4. Run unitd --version and note the ./configure flags for later use, omitting --ld-opt and --njs:

    $ unitd --version
    
        unit version: 1.34.0
        configured as ./configure FLAGS
    
  5. Edit the unit-php7.3.spec file, adding the commands that download Unit’s sources, configure and build your custom module, then put it where Unit will find it:

    Name:           unit-php7.3
    Version:        1.34.0
    # Use Unit's package version for consistency: 'yum info unit | grep Version'
    Release:        1%{?dist}
    Summary:        Custom language module for NGINX Unit
    
    License:        ASL 2.0
    # Unit uses ASL 2.0; your license depends on the language you are packaging
    URL:            https://example.com
    BuildRequires:  gcc
    BuildRequires:  make
    BuildRequires:  php-devel
    BuildRequires:  php-embedded
    Requires:       unit = 1.34.0
    # Specify Unit's package version to avoid issues when Unit updates
    # Again, run 'yum info unit | grep Version' to get this value
    Requires:       php >= 7.3
    Requires:       php-embedded
    
    %description
    Custom language module for NGINX Unit 1.34.0 (https://unit.nginx.org).
    
    Maintainer: Jane Doe <j.doe@example.com>
    
    %prep
    curl -O https://sources.nginx.org/unit/unit-1.34.0.tar.gz
    # Downloads Unit's sources
    tar --strip-components=1 -xzf unit-1.34.0.tar.gz
    # Extracts them locally for compilation steps in the %build section
    
    %build
    ./configure FLAGS W/O --LD-OPT & --NJS
    # Configures the build; use the ./configure flags noted in the previous step
    ./configure php --module=php7.3 --config=php-config
    # Configures the module itself
    make php7.3
    # Builds the module
    
    %install
    DESTDIR=%{buildroot} make php7.3-install
    # Adds the module to the package
    
    %files
    %attr(0755, root, root) "MODULESPATH/php7.3.unit.so"
    # Lists the module as package contents to include it in the package build
    # Use the module path set by ./configure or by default
    

    Save and close the file.

  6. Build and install the package:

    $ rpmbuild -bb unit-php7.3.spec
    
        ...
        Wrote: /home/user/rpmbuild/RPMS/<arch>/unit-php7.3-<moduleversion>.<arch>.rpm
        ...
    
    # yum install -y /home/user/rpmbuild/RPMS/<arch>/unit-php7.3-<moduleversion>.<arch>.rpm