2022

Unit 1.29.0 Released

We are happy to announce Unit 1.29.0! This release enhances the configuration experience when managing Unit and provides programmability within the configuration.

  • NGINX JavaScript (njs) is now built with official Unit packages, enabling JavaScript expressions within configuration values.
  • First-time users benefit from a setup script that configures Unit with a helpful welcome page.
  • A simple command-line curl(1) wrapper simplifies configuring a running instance in real time.

In addition, Unit’s isolation capabilities have been extended so that each application can run in a new or a pre-existing Linux cgroup, but this is only a sampler of even richer per-application observability. Read on for full details of these enhancements, smaller features, and bug fixes.

NGINX JavaScript Integration

NGINX JavaScript (njs) is a server-side JavaScript runtime, optimized for ultra-fast initialization, with a virtual machine that lives and dies with each request. Originally designed for extending NGINX, the njs architecture lends itself to integration, and now it also extends Unit!

This release brings the initial integration of the NGINX JavaScript engine to Unit. Future releases will extend these capabilities to enable more elaborate uses. With Unit 1.29.0, JavaScript template literals may be used in configuration strings to execute JavaScript expressions. A simple example is to use the ternary operator to make a routing decision.

# curl --unix-socket /var/run/control.unit.sock http://localhost/config/routes
[
    {
        "action": {
            "pass": "`applications/${new Date().getHours() < 12 ? 'am' : 'pm'}`"
        }
    }
]

Here, requests are passed between different applications depending on the time of day. Note that a template literal is enclosed in backticks (\``), and ${}` encloses the JavaScript expression. Template literals may be used wherever Unit supports variables, and multiple expressions can appear in a single template literal.

Also, this embedded JavaScript code can access various HTTP request properties:

  • Scalars: host, uri, remoteAddr
  • Objects: args, cookies, headers

Let’s use these properties to redirect clients to the HTTPS login page if there is no session cookie:

# curl --unix-socket /var/run/control.unit.sock http://localhost/config/routes/0
{
    "match": {
        "scheme": "http"
    },

    "action": {
        "return": 302,
        "location": "`https://${host}${cookies['session'] === undefined ? '/login' : uri}`"
    }
}

More complex logic can be implemented using the immediately invoked function expressions (IIFE) in the template literal: an entire JavaScript function can be defined, comprising multiple statements and local variables.

This defines a simple key-value log format that parses a JSON Web Token (JWT) to extract the sub claim:

# curl --unix-socket /var/run/control.unit.sock http://localhost/config/access_log
{
    "path": "/var/log/unit/access_kv.log",
    "format": "`timestamp=${new Date().toISOString()} ip=${remoteAddr} uri=${uri} sub=${(() => { var authz = headers['Authorization']; if (authz === undefined) { return '-'; } else { var parts = authz.slice(7).split('.').slice(0,2).map(v=>Buffer.from(v, 'base64url').toString()).map(JSON.parse); return parts[1].sub; } } )()}
`"
}

Embedding IIFE code in the configuration is extremely powerful, but is typically long, difficult to read, and challenging to debug. The njs command line utility can be used to help develop JavaScript expressions.

Future releases will support loading JavaScript modules into a separate storage and later using module-based functions in the configuration.

Configuration Tools

This release introduces two new command-line tools to simplify Unit’s installation and configuration.

setup-unit

The setup-unit tool automates configuring the software repository prior to installing Unit. It also verifies a fresh installation by configuring and serving a “welcome” web page. This takes some of the guesswork out of the installation process for first-time users and guides them to their next steps. Installing and running Unit on a typical Linux system is now as simple as this:

$ wget https://unit.nginx.org/_downloads/setup-unit && chmod +x setup-unit
# ./setup-unit repo-config
# apt install unit || yum install unit
# ./setup-unit welcome

The setup-unit tool has other useful functions you can explore by running setup-unit --help.

unitc

The unitc tool provides a command-line interface as a wrapper for curl(1) for daily configuration and management of Unit instances.

$ unitc /config
$ cat conf.json | unitc /config

Per-Application Cgroups

With Unit 1.29.0, we support the cgroup V2 API to provide the ability to place each application into its own cgroup or have multiple applications in a single cgroup. The following configuration illustrates the newly added configuration syntax:

"applications": {
    "cgroup-demo": {
        "type": "python",
        "path": "/path/to/app/dir",
        "module": "app",
        "isolation": {
            "cgroup": {
                "path": "unit/cgroup-demo"
            }
        }
    }
}

Unit Not Impacted By CVE-2022-35256, CVE-2022-40674

This is a brief announcement to notify our users that NGINX Unit is not impacted by CVE-2022-40674 and CVE-2022-35256; we don’t use libexpat and implement our own HTTP stack when integrating with Node.js.


Unit 1.28.0 Released

We are happy to announce Unit 1.28! This release sets the first milestone for observability:

  • It is now possible to get basic information about connections, requests, and other per-application metrics

  • All this is now available via our powerful RESTful API

In addition, we introduce new variables and the ability to use them to customize the access log format. Besides the long-awaited statistics and logging use cases, we also present:

  • Enhanced forward header handling with new configuration syntax and X-Forwarded-Proto support

  • Support for abstract UNIX domain sockets in listeners on Linux-like systems

  • Fixes for several community-reported bugs

Metrics and Statistics

With 1.28, the Unit API has a new endpoint available; the /status endpoint is exposed at the root level, as with the /config and /certificates endpoints:

curl --unix-socket /var/run/control.unit.sock http://localhost
{
    "config": {
        "listeners": {
        },

        "applications": {
        }
    },

    "status": {
        "connections": {
            "accepted": 0,
            "active": 0,
            "idle": 0,
            "closed": 0
        },

        "requests": {
            "total": 0
        },

        "applications": {}
    }
}

The status object contains three nested objects:

  • The connections object provides detailed information about the client connections to the Unit instance or, specifically, to its listeners. Here, accepted and closed are total values accumulated over the instance’s lifetime; restarting Unit resets the total values.

  • In contrast, active and idle are spot values representing the number of active or idle requests at one of the listeners that Unit exposes.

The requests object holds the total number of requests to all exposed listeners since the last restart.

Note:
Both connections and requests count requests to Unit’s listeners, NOT the config API itself.
  • The applications section follows the /config/applications tree in the API; again, there’s no special setup required because Unit automatically maintains per-app metrics for all applications in /config/applications, and the apps’ names identify them respectively.

Consider the following applications configuration as an example:

{
    "my-app":{
        "type": "external",
        "working_directory": "/www/chat",
        "executable": "bin/chat_app",
        "processes":{
            "max": 10,
            "spare": 5,
            "idle_timeout": 20
        }
    }
}

The interesting part is the processes configuration. We defined a maximum of 10 and a spare number of 5 processes; the idle_timeout is 20 seconds. After a couple of requests, let’s look at the app statistics:

{
    "my-app":{
        "processes":{
            "running": 9,
            "starting": 0,
            "idle": 2
        },

        "requests":{
            "active": 9
        }
    }
}

Knowing the process configuration of my-app, this is quite easy to understand. Currently, there are 9 out of 10 total processes running, while 0 are currently starting. The two idles are inactive app processes that have not reached the idle_timeout yet; these will be removed when the configured timeout of 20 seconds elapses, so the number of running processes will drop to 7.

So, with Unit 1.28, you now can see your basic workload and process statistics for the Unit instance itself as well as individual applications. This is but a first, very important step to increased visibility for us.

Full Changelog

Changes with Unit 1.28.0                                         13 Sep 2022

    *) Change: increased the applications' startup timeout.

    *) Feature: basic statistics API.

    *) Feature: customizable access log format.

    *) Feature: more HTTP variables support.

    *) Feature: forwarded header to replace client address and protocol.

    *) Feature: ability to get dynamic variables.

    *) Feature: support for abstract Unix sockets.

    *) Bugfix: the Ruby application process could crash on SIGINT.

    *) Bugfix: mutex leak in the C API.

Platform Updates

Docker Images

  • The Unit JSC11 image is now based on eclipse-temurin instead of openjdk

  • Go version bump: 1.18 → 1.19

  • Perl version bump: 5.34 → 5.36


Unit 1.27.0 Released

We are pleased to announce NGINX Unit 1.27. This release brings a new level of maturity to Unit for serving static assets. We love using Unit as a cloud-native web server, and this release brings some missing features to this use case.

  • Redirecting HTTP requests to HTTPS
  • Configurable filename for path-only URIs

Redirecting HTTP Requests to HTTPS

Since we added TLS support and certificate management to Unit, we’ve been asked to simplify redirecting plaintext HTTP requests to the TLS-enabled listener. This is now possible by configuring the location value of a route action to contain variables. Indeed, a new variable, $request_uri, is now available that contains the path-and-query parts of the original URI, preserving any encoding needed by the browser.

A full example is provided below.

{
    "listeners": {
        "*:443": {
            "tls": {
                "certificate": "example.com"
            },
            "pass": "routes"
        },
        "*:80": {
            "pass": "routes"
        }
    },

    "routes": [
        {
            "match": {
                "scheme": "http"
            },
            "action": {
                "return": 301,
                "location": "https://${host}${request_uri}"
            }
        }
    ]
}

This configuration enables Unit to listen on plaintext and TLS-enabled ports, ensuring that any requests received on the plaintext port notify the browser to resubmit on the TLS-enabled port. See more details in the documentation.

Configurable Filename for Path-Only URIs

While it is conventional for index.html to represent the resource to be served when a path-only URI is requested, i.e., one without a filename suffix, this convention is rooted in history. It comes from a time in the early 1990s when HTTP was used exclusively to index and navigate HTML pages.

You can now use a different default filename by specifying the index for a route action. A full example is provided below.

"routes": [
    {
        "match": {
            "uri": "/cms/*"
        },
        "action": {
            "share": "/var/cms$uri",
            "index": "default.html"
        }
    },
    {
        "action": {
            "share": "/var/www$uri"
        }
    }
]

This configuration enables Unit to serve default.html for path-only URIs made to /cms/* and the default index.html filename for all other path-only URIs. See more details in the documentation.

Full Changelog

Changes with Unit 1.27.0                                         02 Jun 2022

    *) Feature: ability to specify a custom index file name when serving
       static files.

    *) Feature: variables support in the "location" option of the "return"
       action.

    *) Feature: support empty strings in the "location" option of the
       "return" action.

    *) Feature: added a new variable, $request_uri, that includes both the
       path and the query parts as per RFC 3986, sections 3-4.

    *) Feature: Ruby Rack environment parameter "SCRIPT_NAME" support.

    *) Feature: compatibility with GCC 12.

    *) Bugfix: Ruby Sinatra applications don't work without custom logging.

    *) Bugfix: the controller process could crash when a chain of more than
       four certificates was uploaded.

    *) Bugfix: some Perl applications failed to process the request body,
       notably with Plack.

    *) Bugfix: some Spring Boot applications failed to start, notably with
       Grails.

    *) Bugfix: incorrect Python protocol auto-detection (ASGI or WSGI) for
       native callable object, notably with Falcon.

    *) Bugfix: ECMAScript modules did not work with the recent Node.js
       versions.

Platform Updates

Official packages are now available for the following Linux distributions:

  • Fedora 36
  • RHEL 9
  • Ubuntu 22.04

Docker images have been updated to use the latest language versions:

  • Go 1.18
  • PHP 8.1
  • Ruby 3.1

Community, Roadmap, and Open Issues

We continue to receive valuable bug reports and feature requests to our GitHub issues page. Although we are a small team, every issue is reviewed, and we aim to respond within 2-3 days. Since the last release, we refreshed our GitHub README with a super-quick-start guide and added contribution guidelines to help you get involved. For other discussions, please join us at the #unit-users channel on the NGINX Community Slack or the mailing list.

Although this release focuses on bug fixes and web server features, we have advanced in several other projects that you can expect to see in forthcoming releases this year:

  • Custom logging (which brings lots of new variables and places you can use them)
  • JavaScript-in-the-configuration (already available as an experimental patch)
  • Statistics API to provide true observability for Unit
  • CLI tool for easier command-line management of Unit

Last modified February 11, 2025