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
andclosed
are total values accumulated over the instance’s lifetime; restarting Unit resets the total values. -
In contrast,
active
andidle
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.
Bothconnections
andrequests
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 ofopenjdk
-
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