BLOG | NGINX

NGINX Unit Greets Autumn 2022 with New Features (a Statistics Engine!) and Exciting Plans

NGINX-Part-of-F5-horiz-black-type-RGB
Artem Konev Thumbnail
Artem Konev
Published October 27, 2022

First things first: it’s been quite a while since we shared news from the NGINX Unit team – these tumultuous times have affected everyone, and we’re no exception. This March, two founding members of the Unit team, Valentin Bartenev and Maxim Romanov, decided to move on to other opportunities after putting years of work and tons of creativity into NGINX Unit. Let’s give credit where credit is due: without them, NGINX Unit wouldn’t be where it is now. Kudos, guys.

Still, our resolve stays strong, as does our commitment to bringing NGINX co‑founder Igor Sysoev’s original aspirations for NGINX Unit to fruition. The arrival of the two newest team members, Alejandro Colomar and Andrew Clayton, has boosted the development effort, so now we have quite a few noteworthy items from NGINX Unit versions 1.25 through 1.28 to share with you.

Observability Is a Thing Now

One of Unit’s key aspirations has always been observability, and version 1.28.0 includes the first iteration of one of the most eagerly awaited features: a statistics engine. Its output is exposed at the new /status API endpoint:

$ curl --unix-socket /var/run/control.unit.sock http://localhost/status

{
    "connections": {
        "accepted": 1067,
        "active": 13,
        "idle": 4,
        "closed": 1050
    },

    "requests": {
        "total": 1307
    },

    "applications": {
        "wp": {
            "processes": {
                "running": 14,
                "starting": 0,
                "idle": 4
            },

            "requests": {
                "active": 10
            }
        }
    }
}

Most of the fields here are self‑descriptive: connections (line 2) and requests (line 9) provide instance‑wide data, whereas the applications object (line 13) mirrors /config/applications, covering processes and requests that specifically concern the application.

Lines 3–6 show the four categories of connections tracked by NGINX Unit: accepted, active, idle, and closed. The categories for processes are running, starting, and idle (lines 16–18). These categories reflect the internal representation of connections and processes, so now you know just as much about them as your server does.

Seems terse? That’s pretty much all there is to know for now. Sure, we’re working to expose more useful metrics; however, you already can query this API from your command line to see what’s going on at your server and even plug the output into a dashboard or your choice for a more fanciful approach. Maybe you don’t have a dashboard? Well, some of our plans include providing a built‑in one, so follow us to see how this plays out.

For more details, see Usage Statistics in the NGINX Unit documentation.

More Variables, More Places to Use Them

The list of variables introduced since version 1.24 is quite extensive and includes $body_bytes_sent, $header_referer, $header_user_agent, $remote_addr, $request_line, $request_uri, $status, and $time_local.

Most of these are rather straightforward, but here are some of the more noteworthy:

  • $request_uri contains the path and query from the requested URI with browser encoding preserved
  • The similarly named $request_line stores the entire request, such as GET /docs/help.html HTTP/1.1, and is intended for logging…
  • As is $status which contains the HTTP response status code

Did you notice? We mentioned responses. Yes, we’re moving into that territory as well: the variables in earlier Unit versions focused on incoming requests, but now we have variables that capture the response properties as well, such as $status and $body_bytes_sent.

Regarding new places to use variables, the first to mention is the new customizable access log format. Want to use JSON in NGINX Unit’s log entries? In addition to specifying a simple path string, the access_log option can be an object that also sets the format of log entries:


{ 
    "access_log": {
        "path": "/var/log/unit/access.log", 
        "format": "{ \"remote_addr\":\"$remote_addr\", "time\":\"$time_local\", \"request\":\"$request_line\", \"response\":\"$status\", \"header_referer\":\"$header_referer\", \"header_user_agent\":\"$header_user_agent\" }" 
    } 
}

Thus, you can go beyond the usual log format any way you like.

A second noteworthy use case for variables is the location value of a route action:


{ 
    "action": { 
        "return": 301, 
        "location": "https://$host$request_uri" 
    } 
 }

Here we’re using $request_uri to relay the request, including the query part, to the same website over HTTPS.

The chroot option now supports variables just as the share option does, which is only logical:


{ 
    "action": { 
        "share": "/www$uri",
        "chroot": "/www/data/$host/" 
    } 
} 

NGINX Unit now supports dynamic variables too. Request arguments, cookies, and headers are exposed as variables: for instance, the query string Type=car&Color=red results in two argument variables, $arg_Type and $arg_Color. At runtime, these variables expand into dynamic values; if you reference a non‑existent variable, it is considered empty.

For more details, see Variables in the NGINX Unit documentation.

Extensive Support for the X-Forwarded-* Headers

You asked, and we delivered. Starting in version 1.25.0, NGINX Unit has offered some TLS configuration facilities for its listeners, including a degree of X-Forwarded-* awareness; now, you can configure client IP addresses and protocol replacement in the configuration for your listeners:


{
    "listeners": {
        "*:80": {
            "pass": "routes/my-app",
            "forwarded": {
                "client_ip": "X-Forwarded-For",
                "protocol": "X-Forwarded-Proto",
                "recursive": false,
                "source": [
                    "198.51.100.1-198.51.100.254",
                    "!198.51.100.128/26",
                    "203.0.113.195"
                ]
            }
        }
    },
    ...
}

Note: This new syntax deprecates the previous client_ip syntax, which will be removed in a future release.

For more details, see IP, Protocol Forwarding in the NGINX Unit documentation.

The Revamped share Option

NGINX Unit version 1.11.0 introduced the share routing option for serving static content. It’s comparable to the root directive in NGINX:


{
    "share": "/path/to/dir/"
}

Initially, the share option specified the so‑called document root directory. To determine which file to serve, Unit simply appended the URI from the request to this share path. For example, in response to a simple GET request for /some/file.html, Unit served /path/to/dir/some/file.html. Still, we kept bumping into border cases that required finer control over the file path, so we decided to evolve. Starting with version 1.26.0, the share option specifies the entire path to a shared file rather than just the document root.

You want to serve a specific file? Fine:


{
    "share": "/path/to/a/file.html"
}

Use variables within the path? Cool, not a problem:


{
    "share": "/www/data/$host/app.html"
}

But how do you go about imitating the behavior you’re already used to from NGINX and previous Unit versions? You know, the document root thing that we deemed obsolete a few paragraphs ago? We have a solution.

You can now rewrite configurations like this:


{
    "share": "/www/data/"
}

as follows, appending the requested URI to the path, but explicitly!


{
    "share": "/www/data/$uri"
}

Finally, the share directive now can accept an array of paths, trying them one by one until it finds a file:


{
    "share": [
        "/www/$host$uri",
        "/www/static$uri",
        "/www/app.html"
    ]
}

If no file is found, routing passes to a fallback action; if there’s no fallback, the 404 (Not Found) status code is returned.

For more details, see Static Files in the NGINX Unit documentation.

Plans: njs, URI Rewrite, Action Chaining, OpenAPI

As you read this, we’re already at work on the next release; here’s a glimpse of what we have up our sleeves.

First, we’re integrating NGINX Unit with the NGINX JavaScript module (njs), another workhorse project under active development at NGINX. In short, this means NGINX Unit will support invoking JavaScript modules. Consider this:


var hellonjs = {}

hellonjs.hello = function(vars) {
    if ('unitvar' in vars) {
        return vars.unitvar;

    } else {
        return 'default';
    }
}

export default hellonjs

After importing the module in NGINX Unit, you’ll be able to do some neat stuff with the configuration:


{
    "match": {
        "uri": "~(?.*)"
    },
    "action": {
        "share": "`/www/html${hellonjs.hello(vars)}`"
    }
}

Also, we’re aiming to introduce something akin to the ever‑popular NGINX rewrite directive:


{
    "match": {
        "uri": "/app/old_path"
     },
     
    "action": {
        "rewrite": "/app/new_path",
        "pass": "routes"
    }
}

Our plans don’t stop there, though. How about tying NGINX Unit’s routing to the output from the apps themselves (AKA action chaining)?


{
    "action": [
        {
            "pass": "applications/auth_check"
        },
        {
            "pass": "applications/my_app"
        }
    ]
}

The idea here is that the auth_check app authenticates the incoming request and returns a status code to indicate the result. If authentication succeeds, 200 OK is returned and the request passes on to my_app.

Meanwhile, we’re also working on an OpenAPI specification to define once and for all NGINX Unit’s API and its exact capabilities. Wish us luck, for this is a behemoth undertaking.

If that’s still not enough to satisfy your curiosity, refer to our roadmap for a fine‑grained dissection of our plans; it’s interactive, so any input from you, dear reader, is most welcome.


"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous NGINX.com links will redirect to similar NGINX content on F5.com."