We’re happy to announce the availability of NGINX Plus Release 26 (R26). Based on NGINX Open Source, NGINX Plus is the only all-in-one software web server, load balancer, reverse proxy, content cache, and API gateway.
New and enhanced features in NGINX Plus R26 include:
http{}
context).async
and await
keywords and the Promise
object are now supported, and we have implemented the WebCrypto API for cryptographic operations (like generating random numbers or encrypting cookies).Rounding out this release are support for the IBM System Z (s390x) architecture, the ability to close each direction of a TCP connection independently, and support for version 2 of the Perl Compatible Regular Expression (PCRE) library.
js_include
As announced at the release of NGINX Plus R23, in version 0.4.0 of the NGINX JavaScript module the js_import
directive replaced the js_include
directive. The js_include
directive was deprecated at that time and as of this release is no longer supported.
Before upgrading to NGINX Plus R26, replace js_include
with js_import
in NGINX configuration files and also add an export
statement to JavaScript files for functions that are referenced in NGINX configuration. Follow these steps:
Edit NGINX configuration files:
Replace js_include
with js_import
and make a note of the implicit module_name (the JavaScript filename parameter to the directive, without the .js extension).
In each directive that references a JavaScript function, prefix the function name with the module_name. The function name is the first parameter to these directives:
It is the second parameter to the js_set
[HTTP][Stream] directive.
For example, change:
js_set $foo myFunction;
to:
js_set $foo module_name.myFunction;
Edit the JavaScript (module_name.js) files that define functions referenced in an NGINX configuration file. Add an export
statement like the following to each file, naming the referenced functions.
export default { myFunction, otherFunction }
The export
statement can appear anywhere in the .js file, but by convention it is placed either directly above the functions or at the end of the file.
The third‑party Cookie‑Flag module was deprecated in NGINX Plus R23 and as announced at that time is no longer available in the NGINX modules repository as of this release.
Before upgrading to NGINX Plus R26, edit your NGINX configuration to replace any occurrences of the set_cookie_flag
directive (defined in the deprecated module) with the built‑in proxy_cookie_flags
directive.
The way that NGINX establishes TLS and HTTP/2 connections has been updated. As part of the TLS handshake between NGINX and a client (usually a browser), they negotiate which communication protocol will be used in the session established by the handshake (most often, the negotiation upgrades the session from HTTP 1.x to HTTP/2). The Next Protocol Negotiation (NPN) extension to TLS was the first method used for this purpose, but NPN is now considered obsolete and is superseded by the Application‑Layer Protocol Negotiation (ALPN) extension, published as RFC 7301.
NGINX Plus R26 no longer supports NPN, so clients must now use ALPN exclusively.
In addition, our ALPN implementation has been extended and hardened – see Hardened TLS Handshakes.
At the release of NGINX Plus R24, the package repositories for all NGINX software were reorganized, resulting in changes to the NGINX Plus installation procedure.
When you install or upgrade NGINX Plus, the operating system’s package manager (apt
, yum
, or equivalent) is configured with the software repository for NGINX Plus.
If upgrading to NGINX Plus R26 on an existing system configured to use the old plus-pkgs.nginx.com repo (those running NGINX Plus R23 or earlier), you must update the package manager to refer to the new pkgs.nginx.com/plus repo. See the instructions in the F5 Knowledge Base.
If performing an initial installation of NGINX Plus R26, see Installing NGINX Plus in the NGINX Plus Admin Guide.
NGINX Plus R26 is not available in the old repository, which will not receive further updates.
The NGINX Plus software package no longer includes the YAML‑format OpenAPI specification and Swagger UI for the NGINX Plus API. You can now access them in the NGINX Plus Admin Guide.
New operating systems and architectures supported:
Older operating systems removed:
Older operating systems and architectures deprecated and scheduled for removal in NGINX Plus R27:
When validating JSON Web Tokens, NGINX uses a JSON Web Key Set (JWKS) to verify the token’s signature or decrypt the token. JWKSs can either be stored in configuration files or obtained from external services via an HTTP request. Additionally caching a JWKS in memory has several benefits:
To cache JWKSs in memory, include the new auth_jwt_key_cache
directive and specify the expiration time for each key set (in this example, 3 hours):
When JWKs are obtained from an external server, we also recommend configuring standard content caching and including the proxy_cache_use_stale
directive, which tells NGINX Plus to continue serving an expired JWKS while it’s being refreshed in the background.
The benefits of content caching in addition to JWKS caching are twofold:
Resiliency – The JWKS can be retrieved from the cache even when it has expired. This increases resiliency when the JWKS provider is temporarily unavailable, but there is a tradeoff of increased security risk.
Effect on the authorization server – Expiration of a cached JWKS affects the auth server differently depending on whether JWKS caching is used alone or in combination with content caching:
With JWKS caching alone, all incoming authorization requests are forwarded to the auth server until the cache is repopulated with a new version of the expired JWKS. If the auth server responds slowly, there can be a sudden increase in repeated HTTP requests for the JWKS. This extra load might overwhelm the auth service, making the problem worse.
When content caching is enabled with serving of expired JWKSs, only one request for the JWKS is forwarded to the auth server, with subsequent requests queued until NGINX can satisfy them after the content cache is populated. This results in lower demand (and thus lower resource consumption) on the auth service.
Attacks against TLS, such as ALPACA, are increasing. As part of our ongoing commitment to proactive defense against exploits, we have hardened NGINX’s handling of TLS connections.
Application‑Layer Protocol Negotiation (ALPN) is an optional extension to the TLS handshake, used by the client and server during the TLS handshake to choose the Layer 7 protocol they will use in the encrypted session established by the handshake. The most common use case for ALPN is to negotiate the upgrade from HTTP/1.x to HTTP/2 for the session between a browser and a web or app server.
NGINX Plus now rejects a TLS handshake if the client proposes a protocol via ALPN that doesn’t match the NGINX configuration context of the session being established. For example, a virtual server defined in the http{}
context requires an ALPN protocol ID for HTTP, while a virtual server in the mail{}
context requires a protocol ID for SMTP, POP, or IMAP.
NGINX Plus R26 introduces the $ssl_alpn_protocol
[HTTP][Stream] variable to capture the negotiated protocol. (The $ssl_preread_alpn_protocols
variable introduced in the stream{}
context in NGINX Plus R15 still captures the list of all protocols advertised by the client during the handshake.)
This snippet defines the alpn log format which uses $ssl_alpn_protocol
to include the protocol in the alpn=
field of entries in the access log.
The new ssl_alpn
directive in the stream{}
context defines which protocols NGINX Plus accepts. Omit the directive to enable NGINX Plus to consider all protocols presented by the client.
NGINX Plus R26 incorporates version 0.7.2 of the NGINX JavaScript module (njs) and includes two enhancements:
async
and await
keywords and Promise
object introduced in ECMAScript 6Note: This section assumes you understand the JavaScript constructs for asynchronous and cryptographic operations. A full analysis of the code snippets is outside the scope of this blog.
[Editor – The use cases described in this section are just some of the many use cases for the NGINX JavaScript module. For a complete list, see Use Cases for the NGINX JavaScript Module.]
In many commonly used scripting languages like PHP, commands and functions execute synchronously – that is, after a script invokes a function it pauses (stops executing) until the function returns a result.
JavaScript can also operate asynchronously: when a function is invoked asynchronously the script continues executing without waiting for the result to return from the function.
Take this sample script:
It returns an empty response because the njs runtime does not wait for the defined timeouts to elapse (if it did wait, the output would be b,a
):
$ curl http://127.0.0.1/
$
Handling asynchronous operations correctly is obviously crucial to getting the intended result. JavaScript provides a number of ways to do this, but in the common NGINX use cases, it’s often desirable simply to wrap an asynchronous function in a way that makes the execution flow synchronous. This is where the Promise
object and async
and await
keywords come into play.
ECMAScript 6 (the sixth edition of the ECMA‑262 language specification for JavasScript) defines the Promise
object as a return type for asynchronous functions. It exists in one of three states:
Defining a JavaScript function with the keyword async
sets the function’s return type to Promise
. The async
and await
keywords are important when you are writing njs functions dealing with Promise
objects.
Take this example:
The fs.readFile
function (line 12) returns a Promise
. It is wrapped in a custom async
function that ensures that fs.readFile()
is invoked only if the file is called user.text. Because of the await
keyword, the wrapping function then waits for the Promise
and returns the data.
Wrapping fs.readFile()
in another function makes it easier to catch errors; any exception in the async
function sets the state of the Promise
to rejected
. Another way to do this is to replace line 9 with a statement that returns a rejected Promise
:
You can also work directly with Promise
objects. In the following example, the Promise.resolve
functions return a Promise
for each of p1
and p2
. The Promise.all
function waits for the promises for both p1
and p2
to be resolved before returning a result.
Now the output from our curl
command is what we want (note that b
is returned first due to the shorter timeout value):
$ curl http://127.0.0.1/b,a
$
NGINX JavaScript now has access to enhanced cryptographic capabilities via the WebCrypto API. Common njs cryptographic use cases include:
This njs code generates a random number:
And this NGINX Plus configuration invokes the njs code:
The output of the function is a random number something like this:
$ curl 127.0.0.123225320050,3668407277,1101267190,2061939102,2687933029,2361833213,32543985,4162087386
The getRandomValues
function in WebCrypto is a great entry point to get started with secure random numbers and WebCrypto in general. Its implementation is quite simple, and the function returns results directly, as opposed to returning a Promise
.
Some of the other more intensive WebCrypto cryptographic functions operate asynchronously, however. For example, the documentation for сrypto.subtle.digest()
states:
Generates a digest of the given data. Takes as its arguments an identifier for the digest algorithm to use and the data to digest. Returns a Promise
which will be fulfilled with the digest.
Calling сrypto.subtle.digest()
directly, therefore, does not guarantee that its result will be available to the next step, unless it’s wrapped in an async
function. So here we wrap it in a function with the async
and the await
keywords to ensure that the hash variable is populated with a result before the function returns:
The js_set
directive in this NGINX Plus configuration populates the $hosthash
variable with the value returned by the setReturnValue
function (as wrapped in the host_hash
function):
Here’s an example that hashes the hostname example.com.
$ curl -H "Host: example.com" 127.0.0.1#
e8e624a82179b53b78364ae14d14d63dfeccd843b026bc8d959ffe0c39fc4ded1f4dcf4c8ebe871e657a12db6f11c3af87c9a1d4f2b096ba3deb56596f06b6f4
As modern applications colonize every available digital biome, it’s important that the essential life‑support components – like NGINX – travel with them, so we’re pleased to support NGINX Plus on the IBM Z (s390x) architecture with CentOS 8.1+, RHEL 8.1+, and Ubuntu 20.04. Organizations looking to host modern applications on their existing mainframe assets can now deploy NGINX and NGINX Plus as a software‑based web server, load balancer, reverse proxy, content cache, and API gateway.
The new proxy_half_close
directive enables independent closure of each direction of a TCP connection, for extra efficiency in stream{}
contexts.
Previous versions of NGINX Plus use the Perl Compatible Regular Expression (PCRE) library (version 1) to evaluate regular expressions used in NGINX configuration. This significant open source project has recently reached end of life, superseded by PCRE2. NGINX Plus is built with PCRE2, but it supports dynamic modules built with both PCRE and PCRE2, using the version available with the underlying operating system. No configuration changes are required.
If you’re running NGINX Plus, we strongly encourage you to upgrade to NGINX Plus R26 as soon as possible. You’ll also pick up several additional fixes and improvements, and it will help NGINX to help you when you need to raise a support ticket.
If you haven’t tried NGINX Plus, we encourage you to try it out – for security, load balancing, and API gateway, or as a fully supported web server with enhanced monitoring and management APIs. You can get started today with a free 30-day trial.
"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."