Module ngx_http_js_module

Planning your ingress-nginx migration? Start here:
kubernetes.nginx.org.

english
русский
news
about
download
security
documentation
faq
books
community
enterprise
community forum (new)
x.com
blog
njs
ingress controller
gateway fabric

Module ngx_http_js_module

Example Configuration
Directives
js_body_filter
js_access
js_content
js_context_reuse
js_engine
js_fetch_buffer_size
js_fetch_ciphers
js_fetch_max_response_buffer_size
js_fetch_protocols
js_fetch_timeout
js_fetch_trusted_certificate
js_fetch_verify
js_fetch_verify_depth
js_fetch_proxy
js_fetch_keepalive
js_fetch_keepalive_requests
js_fetch_keepalive_time
js_fetch_keepalive_timeout
js_header_filter
js_import
js_include
js_load_http_native_module
js_path
js_periodic
js_preload_object
js_set
js_shared_dict_zone
js_var
Request Argument

The ngx_http_js_module module is used to implement
location and variable handlers
in njs —
a subset of the JavaScript language.

Download and install instructions are available
here.

Example Configuration

The example works since
0.4.0.

http {
js_import http.js;

js_set $foo http.foo;
js_set $summary http.summary;
js_set $hash http.hash;

resolver 10.0.0.1;

server {
listen 8000;

location / {
add_header X-Foo $foo;
js_content http.baz;
}

location = /summary {
return 200 $summary;
}

location = /hello {
js_content http.hello;
}

# since 0.7.0
location = /fetch {
js_content http.fetch;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}

# since 0.7.0
location = /crypto {
add_header Hash $hash;
return 200;
}
}
}

The http.js file:

function foo(r) {
r.log("hello from foo() handler");
return "foo";
}

function summary(r) {
var a, s, h;

s = "JS summary\n\n";

s += "Method: " + r.method + "\n";
s += "HTTP version: " + r.httpVersion + "\n";
s += "Host: " + r.headersIn.host + "\n";
s += "Remote Address: " + r.remoteAddress + "\n";
s += "URI: " + r.uri + "\n";

s += "Headers:\n";
for (h in r.headersIn) {
s += " header '" + h + "' is '" + r.headersIn[h] + "'\n";
}

s += "Args:\n";
for (a in r.args) {
s += " arg '" + a + "' is '" + r.args[a] + "'\n";
}

return s;
}

function baz(r) {
r.status = 200;
r.headersOut.foo = 1234;
r.headersOut['Content-Type'] = "text/plain; charset=utf-8";
r.headersOut['Content-Length'] = 15;
r.sendHeader();
r.send("nginx");
r.send("java");
r.send("script");

r.finish();
}

function hello(r) {
r.return(200, "Hello world!");
}

// since 0.7.0
async function fetch(r) {
let results = await Promise.all([ngx.fetch('https://nginx.org/'),
ngx.fetch('https://nginx.org/en/')]);

r.return(200, JSON.stringify(results, undefined, 4));
}

// since 0.7.0
async function hash(r) {
let hash = await crypto.subtle.digest('SHA-512', r.headersIn.host);
r.setReturnValue(Buffer.from(hash).toString('hex'));
}

export default {foo, summary, baz, hello, fetch, hash};

Directives

Syntax:

js_body_filter module.function
[buffer_type=string | buffer];

Default:

—

Context:

location, if in location, limit_except

This directive appeared in version 0.5.2.

Sets an njs function as a response body filter.
The filter function is called for each data chunk of a response body
with the following arguments:

r

the HTTP request object

data

the incoming data chunk,
may be a string or Buffer
depending on the buffer_type value,
by default is a string.
Since 0.8.5, the
data value is implicitly converted to a valid UTF-8 string
by default.
For binary data, the buffer_type value
should be set to buffer.

flags

an object with the following properties:

last

a boolean value, true if data is a last buffer.

The filter function can pass its own modified version
of the input data chunk to the next body filter by calling
r.sendBuffer().
For example, to transform all the lowercase letters in the response body:

function filter(r, data, flags) {
r.sendBuffer(data.toLowerCase(), flags);
}

If the filter function changes the length of the response body, the
“Content-Length” response header (if present) should be cleared
in js_header_filter
to enforce chunked transfer encoding:

example.conf:
location /foo {
# proxy_pass http://localhost:8080;

js_header_filter main.clear_content_length;
js_body_filter main.filter;
}

example.js:
function clear_content_length(r) {
delete r.headersOut['Content-Length'];
}

To stop filtering and pass the data chunks to the client
without calling js_body_filter,
r.done()
can be used.
For example, to prepend some data to the response body:

function prepend(r, data, flags) {
r.sendBuffer("XXX");
r.sendBuffer(data, flags);
r.done();
}

As the js_body_filter handler
returns its result immediately, it supports
only synchronous operations.
Thus, asynchronous operations such as
r.subrequest()
or
setTimeout()
are not supported.

The directive can be specified inside the
if block
since 0.7.7.

Syntax:

js_access module.function;

Default:

—

Context:

location, if in location, limit_except

This directive appeared in version 0.9.9.

Sets an njs function as a handler in the
access phase.
Asynchronous operations such as
r.subrequest(),
ngx.fetch(),
and setTimeout()
are supported.

A handler that returns without calling
r.return()
or
r.decline()
grants access.
To deny access or send a custom response (for example, a redirect),
the handler may call
r.return().
To make the handler express no opinion, deferring the decision to other
access checkers under
satisfy any,
the handler may call
r.decline().

For example:

example.conf:
location /protected/ {
js_access main.auth;
proxy_pass http://upstream;
}

example.js:
async function auth(r) {
let reply = await ngx.fetch('http://authsvc/check', {
headers: {Authorization: r.headersIn.Authorization}
});

if (reply.status != 200) {
r.return(401);
return;
}
}

export default {auth};

Syntax:

js_content module.function;

Default:

—

Context:

location, if in location, limit_except

Sets an njs function as a location content handler.
Since 0.4.0,
a module function can be referenced.

The directive can be specified inside the
if block
since 0.7.7.

Syntax:

js_context_reuse number;

Default:

js_context_reuse 128;

Context:

http, server, location

This directive appeared in version 0.8.6.

Sets a maximum number of JS context to be reused for
QuickJS engine.
Each context is used for a single request.
The finished context is put into a pool of reusable contexts.
If the pool is full, the context is destroyed.

Syntax:

js_engine njs | qjs;

Default:

js_engine njs;

Context:

http, server, location

This directive appeared in version 0.8.6.

Sets a JavaScript engine
to be used for njs scripts.
The njs parameter sets the njs engine, also used by default.
The qjs parameter sets the QuickJS engine.

Syntax:

js_fetch_buffer_size size;

Default:

js_fetch_buffer_size 16k;

Context:

http, server, location

This directive appeared in version 0.7.4.

Sets the size of the buffer used for reading and writing
with Fetch API.

Syntax:

js_fetch_ciphers ciphers;

Default:

js_fetch_ciphers HIGH:!aNULL:!MD5;

Context:

http, server, location

This directive appeared in version 0.7.0.

Specifies the enabled ciphers for HTTPS requests
with Fetch API.
The ciphers are specified in the format understood by the
OpenSSL library.

The full list can be viewed using the
“openssl ciphers” command.

Syntax:

js_fetch_max_response_buffer_size size;

Default:

js_fetch_max_response_buffer_size 1m;

Context:

http, server, location

This directive appeared in version 0.7.4.

Sets the maximum size of the response received
with Fetch API.

Syntax:

js_fetch_protocols
[TLSv1]
[TLSv1.1]
[TLSv1.2]
[TLSv1.3];

Default:

js_fetch_protocols TLSv1 TLSv1.1 TLSv1.2;

Context:

http, server, location

This directive appeared in version 0.7.0.

Enables the specified protocols for HTTPS requests
with Fetch API.

Syntax:

js_fetch_timeout time;

Default:

js_fetch_timeout 60s;

Context:

http, server, location

This directive appeared in version 0.7.4.

Defines a timeout for reading and writing
for Fetch API.
The timeout is set only between two successive read/write operations,
not for the whole response.
If no data is transmitted within this time, the connection is closed.

Syntax:

js_fetch_trusted_certificate file;

Default:

—

Context:

http, server, location

This directive appeared in version 0.7.0.

Specifies a file with trusted CA certificates in the PEM format
used to
verify
the HTTPS certificate
with Fetch API.

Syntax:

js_fetch_verify on | off;

Default:

js_fetch_verify on;

Context:

http, server, location

This directive appeared in version 0.7.4.

Enables or disables verification of the HTTPS server certificate
with Fetch API.

Syntax:

js_fetch_verify_depth number;

Default:

js_fetch_verify_depth 100;

Context:

http, server, location

This directive appeared in version 0.7.0.

Sets the verification depth in the HTTPS server certificates chain
with Fetch API.

Syntax:

js_fetch_proxy url;

Default:

—

Context:

http, server, location

This directive appeared in version 0.9.4.

Configures a forward proxy URL
with Fetch API.
The url supports the HTTP scheme only
and can contain optional user credentials
in the format http://[user:password@]host:port
for Basic authentication.
Supports both HTTP and HTTPS connections to destination servers.
If the url is empty, proxy routing is disabled.
The parameter value can contain variables.

Example:

location /fetch {
js_fetch_proxy http://user:pass@proxy.example.com:3128;
js_content main.fetch_handler;
}

Syntax:

js_fetch_keepalive connections;

Default:

js_fetch_keepalive 0;

Context:

http, server, location

This directive appeared in version 0.9.2.

Activates the cache for connections to destination servers.
When the value is greater than 0,
enables keepalive connections for
Fetch API.

The connections parameter sets the maximum number of idle
keepalive connections to destination servers that are preserved in the cache
of each worker process.
When this number is exceeded, the least recently used connections are closed.

Example:

location /fetch {
js_fetch_keepalive 32;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
js_content main.fetch_handler;
}

Syntax:

js_fetch_keepalive_requests number;

Default:

js_fetch_keepalive_requests 1000;

Context:

http, server, location

This directive appeared in version 0.9.2.

Sets the maximum number of requests that can be served through one keepalive
connection with Fetch API.
After the maximum number of requests is made, the connection is closed.

Closing connections periodically is necessary to free per-connection memory
allocations.
Therefore, using too high maximum number of requests could result in
excessive memory usage and not recommended.

Syntax:

js_fetch_keepalive_time time;

Default:

js_fetch_keepalive_time 1h;

Context:

http, server, location

This directive appeared in version 0.9.2.

Limits the maximum time during which requests can be processed through one
keepalive connection with Fetch API.
After this time is reached, the connection is closed following the subsequent
request processing.

Syntax:

js_fetch_keepalive_timeout time;

Default:

js_fetch_keepalive_timeout 60s;

Context:

http, server, location

This directive appeared in version 0.9.2.

Sets a timeout during which an idle keepalive connection to a destination server
will stay open with Fetch API.

Syntax:

js_header_filter module.function;

Default:

—

Context:

location, if in location, limit_except

This directive appeared in version 0.5.1.

Sets an njs function as a response header filter.
The directive allows changing arbitrary header fields of a response header.

As the js_header_filter handler
returns its result immediately, it supports
only synchronous operations.
Thus, asynchronous operations such as
r.subrequest()
or
setTimeout()
are not supported.

The directive can be specified inside the
if block
since 0.7.7.

Syntax:

js_import module.js |
export_name from module.js;

Default:

—

Context:

http, server, location

This directive appeared in version 0.4.0.

Imports a module that implements location and variable handlers in njs.
The export_name is used as a namespace
to access module functions.
If the export_name is not specified,
the module name will be used as a namespace.

js_import http.js;

Here, the module name http is used as a namespace
while accessing exports.
If the imported module exports foo(),
http.foo is used to refer to it.

Several js_import directives can be specified.

When js_import is specified inside a
location,
the imported modules are visible only if no JavaScript code
has been invoked earlier in the request.
A single VM is created per request when a
js_set variable is first accessed
or when a js_content, js_header_filter,
js_body_filter, or js_access handler
is first invoked.
The VM is cloned from the configuration scope active at that moment,
and all subsequent JavaScript invocations within the request reuse it.
Thus, if any of the above is referenced before the request is mapped
to its final location, for example from a server-level
set,
the VM is bound to the import set of the outer scope, and modules
imported in the matched location will not be visible.
To avoid this, declare such imports in a common parent scope.

The directive can be specified on the
server and location level
since 0.7.7.

Syntax:

js_include file;

Default:

—

Context:

http

Specifies a file that implements location and variable handlers in njs:

nginx.conf:
js_include http.js;
location /version {
js_content version;
}

http.js:
function version(r) {
r.return(200, njs.version);
}

The directive was made obsolete in version
0.4.0
and was removed in version
0.7.1.
The js_import directive should be used instead.

Syntax:

js_load_http_native_module path [as name];

Default:

—

Context:

main

This directive appeared in version 0.9.5.

Loads a native module
(shared library) for use in HTTP JavaScript code.
The directive is
QuickJS-only
and is not available when using the njs built-in JavaScript engine.

The path parameter
specifies the absolute path to the shared library file.
The optional as name parameter
provides an alias name for importing the module in JavaScript code.
If not specified, the module can be imported using its filename.

Example:

js_load_http_native_module /path/to/mylib.so;
js_load_http_native_module /path/to/other.so as myalias;

http {
js_import main.js;
# ... rest of http configuration
}

In JavaScript code:

// Import by filename
import * as mylib from 'mylib.so';

// Import by alias
import * as myalias from 'myalias';

// Use exported functions
let result = mylib.add(5, 10);

For security reasons, this directive is only allowed
in the main configuration context.
Native modules run with full process privileges;
use absolute paths and ensure proper code review.

Syntax:

js_path
path;

Default:

—

Context:

http, server, location

This directive appeared in version 0.3.0.

Sets an additional path for njs modules.

The directive can be specified on the
server and location level
since 0.7.7.

Syntax:

js_periodic module.function
[interval=time]
[jitter=number]
[worker_affinity=mask];

Default:

—

Context:

location

This directive appeared in version 0.8.1.

Specifies a content handler to run at regular interval.
The handler receives a
session object
as its first argument,
it also has access to global objects such as
ngx.

The optional interval parameter
sets the interval between two consecutive runs,
by default, 5 seconds.

The optional jitter parameter sets the time within which
the location content handler will be randomly delayed,
by default, there is no delay.

By default, the js_handler is executed on worker process 0.
The optional worker_affinity parameter
allows specifying particular worker processes
where the location content handler should be executed.
Each worker process set is represented by a bitmask of allowed worker processes.
The all mask allows the handler to be executed
in all worker processes.

Example:

example.conf:

location @periodics {
# to be run at 1 minute intervals in worker process 0
js_periodic main.handler interval=60s;

# to be run at 1 minute intervals in all worker processes
js_periodic main.handler interval=60s worker_affinity=all;

# to be run at 1 minute intervals in worker processes 1 and 3
js_periodic main.handler interval=60s worker_affinity=0101;

resolver 10.0.0.1;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}

example.js:

async function handler(s) {
let reply = await ngx.fetch('https://nginx.org/en/docs/njs/');
let body = await reply.text();

ngx.log(ngx.INFO, body);
}

Syntax:

js_preload_object name.json |
name from file.json;

Default:

—

Context:

http, server, location

This directive appeared in version 0.7.8.

Preloads an
immutable object
at configure time.
The name is used as a name of the global variable
though which the object is available in njs code.
If the name is not specified,
the file name will be used instead.

js_preload_object map.json;

Here, the map is used as a name
while accessing the preloaded object.

Several js_preload_object directives can be specified.

Syntax:

js_set
$variable
module.function
[nocache];

Default:

—

Context:

http, server, location

Sets an njs function
for the specified variable.
Since 0.4.0,
a module function can be referenced.

The function is called when
the variable is referenced for the first time for a given request.
The exact moment depends on a
phase
at which the variable is referenced.
This can be used to perform some logic
not related to variable evaluation.
For example, if the variable is referenced only in the
log_format directive,
its handler will not be executed until the log phase.
This handler can be used to do some cleanup
right before the request is freed.

Since 0.8.6,
if an optional argument nocache is specified,
the handler is called every time it is referenced.
Due to current limitations
of the rewrite module,
when a nocache variable is referenced by the
set directive
its handler should always return a fixed-length value.

As the js_set handler
returns its result immediately, it supports
only synchronous operations.
Thus, asynchronous operations such as
r.subrequest()
or
setTimeout()
are not supported.

The directive can be specified on the
server and location level
since 0.7.7.

Syntax:

js_shared_dict_zone
zone=name:size
[timeout=time]
[type=string|number]
[evict]
[state=file];

Default:

—

Context:

http

This directive appeared in version 0.8.0.

Sets the name and size of the shared memory zone
that keeps the
key-value dictionary
shared between worker processes.

By default the shared dictionary uses a string as a key and a value.
The optional type parameter
allows redefining the value type to number.

The optional timeout parameter sets
the time in milliseconds
after which all shared dictionary entries are removed from the zone.
If some entries require a different removal time, it can be set
with the timeout argument of the
add,
incr, and
set
methods
(0.8.5).

The optional evict parameter removes the oldest
key-value pair when the zone storage is exhausted.

The optional state parameter specifies a file
that keeps the shared dictionary state
in JSON format and makes it persistent across nginx restarts
(0.9.1).

Example:

example.conf:
# Creates a 1Mb dictionary with string values,
# removes key-value pairs after 60 seconds of inactivity:
js_shared_dict_zone zone=foo:1M timeout=60s;

# Creates a 512Kb dictionary with string values,
# forcibly removes oldest key-value pairs when the zone is exhausted:
js_shared_dict_zone zone=bar:512K timeout=30s evict;

# Creates a 32Kb permanent dictionary with number values:
js_shared_dict_zone zone=num:32k type=number;

# Creates a 1Mb dictionary with string values and persistent state:
js_shared_dict_zone zone=persistent:1M state=/tmp/dict.json;

example.js:
function get(r) {
r.return(200, ngx.shared.foo.get(r.args.key));
}

function set(r) {
r.return(200, ngx.shared.foo.set(r.args.key, r.args.value));
}

function del(r) {
r.return(200, ngx.shared.bar.delete(r.args.key));
}

function increment(r) {
r.return(200, ngx.shared.num.incr(r.args.key, 2));
}

Syntax:

js_var $variable [value];

Default:

—

Context:

http, server, location

This directive appeared in version 0.5.3.

Declares
a writable
variable.
The value can contain text, variables, and their combination.
The variable is not overwritten after a redirect
unlike variables created with the
set directive.

The directive can be specified on the
server and location level
since 0.7.7.

Request Argument

Each HTTP njs handler receives one argument, a request
object.