NGINX.COM
Web Server Load Balancing with NGINX Plus

Editor – This post describes an early version of nginScript, which is now called the NGINX JavaScript module. For a description of the current implementation of the module, which became generally available in NGINX Plus R12, see Harnessing the Power and Convenience of JavaScript for Each Request with the NGINX JavaScript Module.

I’ve been wanting to add more scripting capabilities to NGINX for a long time. Scripting lets people do more in NGINX without having to write C modules, for example. Lua is a good tool in this area, but it’s not as widely known as some other languages.

JavaScript was the most obvious language to add next. It’s the most popular language – #1 on GitHub for the past three years. JavaScript is also a good fit for the way we configure NGINX.

I recently announced a working prototype of a JavaScript virtual machine (VM) that would be embedded within NGINX. Today we announced the launch of the first preview of this software, nginScript.

This is another milestone in the development of NGINX open source software and NGINX Plus. I want to take the opportunity to explain what nginScript is, describe why it’s needed, share some examples, and talk about the future.

What nginScript Is

nginScript is a robust implementation of much of JavaScript, including the parts most useful for configuring NGINX. Some less‑used parts of JavaScript and some less relevant built‑in objects are not supported.

nginScript can be used for quick fixes, making NGINX configuration more convenient and operations more efficient. But, because it runs at the application delivery level, it will also enable you to refactor your applications for greater long‑term stability, security, and scale.

nginScript has two parts:

  1. A custom virtual machine (VM) and byte‑code compiler with a very fast start‑up and tear‑down time. Blocking operations, such as an HTTP subrequest, can be suspended and resumed, in the same way as other blocking operations in JavaScript.
  2. A configuration syntax for embedding snippets of JavaScript in your NGINX configuration. These snippets are evaluated at runtime, as HTTP transactions proceed. You can create powerful conditional configurations, modify requests and responses on the fly, and adjust the internal operations of NGINX specifically for each request.

There are currently several popular JavaScript VMs out there, but they are optimized for use with browsers. The nginScript VM is focused on server requirements. We run a separate VM for each request, so there’s no need for garbage collection. And an nginScript VM can be pre‑empted so NGINX code can run.

What nginScript Makes Possible

nginScript has a wide range of potential uses. The following capabilities are available today, and they will be extended over time:

  • Defend against security threats – nginScript can dynamically respond to abusive traffic sources by rate‑limiting or denying requests.
  • Gain richer control over traffic – You can implement flexible control over how traffic is routed using information in the request or other sources.
  • Consolidate functions across applications – You can move duplicated functionality out of applications and into the application delivery platform.
  • Speed application development with function libraries – nginScript code can be developed, reused, improved, stored, and shared.

In the future, we’ll add more capabilities to nginScript and broaden its scope, so you can use it for tasks such as fixing application bugs, changing business rules, personalizing the user experience, and sharding requests across servers and aggregating the replies.

[Editor – For a list of use cases for NGINX JavaScript, see Use Cases for the NGINX JavaScript Module.]

nginScript in Action

There are two new directives that can be used to insert JavaScript code into NGINX, js_set and js_run.

[Editor – The following configuration examples use an early form of nginScript syntax that is deprecated since the NGINX JavaScript module became generally available in NGINX Plus R12. For details on the standardized syntax, see Harnessing the Power and Convenience of JavaScript for Each Request with the NGINX JavaScript Module and the reference documentation for the HTTP and Stream NGINX JavaScript modules.]

The js_set Directive

The js_set directive sets the value of a variable to the result of the execution of JavaScript code:

# This example uses DEPRECATED syntax; see note above
http {
    js_set $hello_world "
            var str = 'Hello World!';
            // JavaScript
            str;
    ";
 
    server {
        # ...
        location /{
            return 200 $hello_world;
        }
    }
}

In the above example, the value of $hello_world is set to the value of the last statement in the JavaScript code. The client is then returned the value of this variable: “Hello World!”.

A variable set by js_set can be used in any NGINX directive that takes a variable parameter, such as limit_req_zone, proxy_pass, and sub_filter.

The js_run Directive

The js_run directive is evaluated at the content‑generation stage. It’s used to execute JavaScript natively and generate an HTTP response. It goes inside a location block and triggers execution of JavaScript code when the location matches a request URL.

# This example uses DEPRECATED syntax; see note above
location / {
    js_run "
        var res;
        res = $r.response;
        res.status = 200;
        res.send('Hello World!');
        res.finish();
    ";
}

Request Parameters

With nginScript you have full access to the request parameters, with the $r variable. The following example returns the request parameters back to the requester.

# This example uses DEPRECATED syntax; see note above
http {
    js_set $summary "
    var a, s, h;
 
    s = 'JS summarynn';
 
    s += 'Method: ' + $r.method + 'n';
    s += 'HTTP version: ' + $r.httpVersion + 'n';
    s += 'Host: ' + $r.headers.host + 'n';
    s += 'Remote Address: ' + $r.remoteAddress + 'n';
    s += 'URI: ' + $r.uri + 'n';
 
    s += 'Headers:n';
    for (h in $r.headers) {
        s += '  header "' + h + '" is "' + $r.headers[h] + '"n';
    }
 
    s += 'Args:n';
    for (a in $r.args) {
        s += '  arg "' + a + '" is "' + $r.args[a] + '"n';
    }
 
    s;
    ";
 
    server {
    listen 8000;
 
    location /summary {
        return 200 $summary;
    }
}

Custom Request Routing

With the location block in NGINX you can route traffic based on URI. With nginScript you can route traffic based on any data in the request, including cookies, headers, arguments, or any keywords in the request body. The following example routes traffic based on the presence of an argument named upstream:

# This example uses DEPRECATED syntax; see note above
upstream my_upstream0 {
    server server1.example.com;
    server server2.example.com;
}
upstream my_upstream1 {
    server server3.example.com;
    server server4.example.com;
}
 
js_set $my_upstream "
    var s, upstream, upstream_num;
 
    upstream = $r.args.upstream;
 
    // convert upstream number to integer
    upstream_num = +upstream | 0;
 
    if (upstream_num < 0 || upstream_num > 1) {
        upstream_num = 0;
    }
 
    s = 'my_upstream' + upstream_num;
 
    s;
";
 
server {
    listen 80;
 
    location / {
        proxy_set_header Host $host;
        proxy_pass http://$my_upstream;
    }
}

The Future of nginScript

Our goal is to make NGINX the connective tissue and traffic management layer for all modern web applications. Embedding JavaScript in NGINX is a major step in this direction. nginScript joins Lua, Perl, and modules as robust ways to extend NGINX.

nginScript is not intended to replace Lua or other embedded languages in NGINX. JavaScript has now been added to the existing community of extensions to NGINX, and we expect the number of alternatives continues to grow in the future.

nginScript enables testing and prototyping, functionality and security fixes, and strategic refactoring of application development and deployment. We look forward to your feedback as you try out nginScript and consider its long‑term place in your application development and delivery strategy.

For more information, check out these resources:

To provide feedback, please use our mailing list.

[Editor – To learn more about how and why we tailored nginScript to work seamlessly with NGINX, see nginScript – Why Are We Creating Our Own JavaScript Implementation?]

Hero image
Free O'Reilly eBook: The Complete NGINX Cookbook

Updated for 2024 – Your guide to everything NGINX



About The Author

Igor Sysoev

Igor Sysoev

Senior Architect

Igor Sysoev’s passion for solving the C10K problem led him to become the author of NGINX, which was initially released in 2004. NGINX’s popularity and use became so widespread that Igor co‑founded NGINX, Inc. in 2011 and served as its Chief Technology Officer. He has 15 years of experience in deeply technical roles and is a Senior Architect at F5.

About F5 NGINX

F5, Inc. is the company behind NGINX, the popular open source project. We offer a suite of technologies for developing and delivering modern applications. Together with F5, our combined solution bridges the gap between NetOps and DevOps, with multi-cloud application services that span from code to customer.

Learn more at nginx.com or join the conversation by following @nginx on Twitter.