OpenResty - Lua and nginx

OpenResty (http://openresty.org/en/) is an nginx distribution that embeds a Lua (http://www.lua.org/) interpreter that can be used to script the web server.

Lua is an excellent, dynamically-typed programming language, which has a ;lightweight interpreter, yet, very fast. The language offers a complete set of features and has built-in async features. You can write coroutines directly in vanilla Lua.

For a Python developer, Lua feels quite Pythonic, and you can start to build scripts with it in a matter of hours once you know the basic syntax. It has functions, classes, and a standard library that will make you feel at home.

If you install Lua (refer to http://www.lua.org/start.html), you can play with the language using the Lua Read Eval Print Loop (REPL) exactly like how you would do with Python:

$ lua 
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio 
> io.write("Hello world
") 
Hello world 
> mytable = {} 
> mytable["user"] = "tarek" 
> = mytable["user"] 
tarek 
> = string.upper(mytable["user"]) 
TAREK 
To discover the Lua language, this is your starting page ;http://www.lua.org/docs.html.

Lua is often a language of choice to get embedded in compiled apps. Its memory footprint is ridiculously small, and it allows to add fast dynamic scripting features. That is what is happening in OpenResty. Instead of building nginx modules that require compiling nginx with them, you can extend the web server using Lua scripts and deploy them directly with OpenResty.

When you invoke some Lua code from your nginx configuration, the LuaJIT (http://luajit.org/) interpreter that's employed by OpenResty will run them in a very efficient way, and won't be slower than nginx code itself. Some performance benchmarks find that Lua can be faster than C or C++ in some cases (refer to http://luajit.org/performance.html).

The functions you can add in nginx that way are coroutines that will run asynchronously in nginx, so the overhead is minimal even when your server receives a lot of concurrent requests, which is exactly our need for a WAF.

OpenResty comes as ;Docker image and a package for some Linux distributions. It can also be compiled from the ground, refer to http://openresty.org/en/installation.html. On macOS, you can use Brew and the ;brew install openresty ;command.

Once OpenResty is installed, you will get an openresty command, and you can use it exactly like nginx to serve your apps.

In the following example, the nginx configuration will proxy calls to a Flask application running on port 5000:

    daemon off; 
    worker_processes  1; 
    pid openresty.pid; 
    error_log /dev/stdout info; 
    events { 
      worker_connections  1024; 
    } 
    http { 
      include       mime.types; 
      default_type  application/octet-stream; 
      sendfile        on; 
      keepalive_timeout  65; 
      access_log /dev/stdout; 
      server { 
        listen       8888; 
        server_name  localhost; 
        location / { 
          proxy_pass http://localhost:5000; 
          proxy_set_header Host $host; 
          proxy_set_header X-Real-IP $remote_addr; 
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        } 
      }  
    } 

This configuration can be used with the openresty command line and will run in the foreground (daemon off) on port 8888 to proxy pass all requests to the Flask app running on port 5000.

$ openresty -c resty.conf
2017/07/14 12:10:12 [notice] 49704#524185: using the "kqueue" event method
2017/07/14 12:10:12 [notice] 49704#524185: openresty/1.11.2.3
2017/07/14 12:10:12 [notice] 49704#524185: built by clang 8.0.0 (clang-800.0.38)
2017/07/14 12:10:12 [notice] 49704#524185: OS: Darwin 16.6.0
2017/07/14 12:10:12 [notice] 49704#524185: hw.ncpu: 4
2017/07/14 12:10:12 [notice] 49704#524185: net.inet.tcp.sendspace: 1042560
2017/07/14 12:10:12 [notice] 49704#524185: kern.ipc.somaxconn: 2048
2017/07/14 12:10:12 [notice] 49704#524185: getrlimit(RLIMIT_NOFILE): 7168:9223372036854775807
2017/07/14 12:10:12 [notice] 49704#524185: start worker processes
2017/07/14 12:10:12 [notice] 49704#524185: start worker process 49705

Note that this configuration can also be used in a plain nginx server, since we're not using any Lua yet. That's what's nice with OpenResty: it's a drop-in replacement for nginx and can run your existing configuration files.

The code and configuration demonstrated in this section can be found at https://github.com/Runnerly/waf.

Lua can be invoked at different moments when a request comes in, the two that are attractive to this chapter are:

  • access_by_lua_block: This is called on every incoming request before a response is built. This is where we can build access rules in our WAF.
  • content_by_lua_block: This uses Lua to generate a response.

Let's see in the next section how we can rate-limit incoming requests.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset