Launching NginScript

Datetime:2016-08-23 00:55:59          Topic: nginScript           Share

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 recentlyannounced 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 , atnginx.conf 2015.

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 – the most useful parts 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 startup 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 that allows you to embed 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 the browser. The virtual machine for nginScript is focused on server requirements. We run a separate virtual machine for each request, so there’s no need for garbage collection. And an nginScript 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 extend with time:

  1. Defend against security threats – nginScript can dynamically respond to abusive traffic sources by rate-limiting or denying requests.
  2. Gain richer control over traffic – You can implement flexible control over how traffic is routed using information in the request or other sources.
  3. Consolidate functions across applications – You can move duplicated functionality out of applications and into the application delivery platform.
  4. 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.

nginScript in Action

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

js_set

js_set – Sets the value of a variable to the result of the execution of JavaScript code:

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 .

js_run

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.

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 example below returns the request parameters back to the requester.

http {
	js_set $summary "
	var a, s, h;
	s = 'JS summary\n\n';
	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 present in the request. Traffic can be routed based on the presence of a cookie, a header, an argument, or any keywords in the request body. The example below routes traffic based on the presence of an argument named upstream:

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;
	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 NGINX and 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 adds 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.





About List