What if there is a conflict between Lua rules and NGINX configuration?

API7.ai

October 13, 2022

OpenResty (NGINX + Lua)

1. The name and language of OpenResty

Q: I haven't understood the origin of the name OpenResty until now. Also, OpenResty takes wings with the Lua language, so why not with other scripting languages? For example, Shell, etc.

A: OpenResty started as a corporate project of Yahoo!, which began in October 2007. The name "Open" was taken from OpenAPI, and "Resty" was taken from rest API. Initially, OpenResty was not intended to be a web server and development platform but an application like a website.

When OpenResty was open-sourced over a decade ago, very few languages supported synchronous non-blocking. Even now, not many back-end languages can achieve this level of performance with OpenResty. Currently, more developers are using OpenResty in API gateways and soft WAFs, which is a natural choice for developers.

As for the language, OpenResty is not the only project that embeds other development languages into NGINX. For example, NGINX officially embeds JS; there are also open source projects that embed PHP into NGINX.

Typically, the choice of language to leverage is based on factors such as concurrency, JIT, and language popularity. For OpenResty, back in 2007, Lua was indeed the best choice. OpenResty took a detour by choosing perl over Lua in its earliest versions.

2. The rule priority of the configuration

Q: When the Lua rules in OpenResty conflict with NGINX configuration file, for example, NGINX configured rewrite rules, and at the same time refer to rewrite_by_lua_file, then what is the priority of these two rules?

A: Actually, it depends on how the NGINX configuration rewrite rule is written, whether it is a break or last, which is stated in the official OpenResty documentation, with a sample code:

 location /foo {
     rewrite ^ /bar;
     rewrite_by_lua 'ngx.exit(503)';
 }
 location /bar {
     ...
 }

In this configuration of the sample code, ngx.exit(503) will not be executed.

However, if you write it like the following, ngx.exit(503) will be executed.

rewrite ^ /bar break.

However, I recommend using OpenResty for rewrite instead of NGINX configuration. To avoid this ambiguity, a lot of NGINX configuration is relatively obscure and requires you to consult the documentation to understand it repeatedly.

3. Why does my code report an error?

Q: In the table function of the LuaJIT extension, why do the following two lines of code give an error "moudule not found" when executed by LuaJIT? I'm using LuaJIT version 2.0.5.

local new_tab = require('table.new')
# or
require('table.clear')

# The execution will report an error
luajit: table_luajit.lua:1: module 'table.new' not found:

A: These two lines of code require LuaJIT version 2.1 to run, documented here: https://github.com/LuaJIT/LuaJIT/blob/v2.1/doc/extensions.html#L218, You can find out about it.

As we mentioned, you need to pay special attention when using OpenResty, which requires a specific version of LuaJIT to run correctly. OpenResty is based on the LuaJIT 2.1 branch and has made a lot of its extensions to LuaJIT.

So, when running the code in this column, please remember to use the official OpenResty installation. If you add the lua-nginx-module to compile on top of NGINX, you will still step in many holes!

4. Confusion about null values

Q: Some confusing things I've encountered are ngx.null, nil, null, and "". When I searched the web, I saw that someone said null is a definition of ngx.null. When Redis returns, it often determines whether the returned result is null or not, so which value is it compared to when making the determination? Are there any other pitfalls regarding the use of these values? I don't understand these values clearly.

A: Before I answer your question, I suggest you use the following code to find a key in lua-resty-redis.

local res, err = red:get("dog")

This is because Lua's nil cannot be used as the table's value, so OpenResty introduces ngx.null as the null value in the table.

We can print out ngx.null and its type with the following code.

# print ngx.null
$ resty -e 'print(ngx.null)'
null
# Print the type
$ resty -e 'print(type(ngx.null))'
userdata

As you can see, ngx.null is not nil, but is of type userdata.

Further, there are many null values in OpenResty, such as cjson.null, cdata``:NULL and so on, which I will discuss later.

The only false values in OpenResty are nil and false. So, when you write code like if not res then, you must be careful, and it is better to change it to explicit if res ~= nil and res ~= false then, with something like this, and with corresponding test case coverage.

5. What exactly is the API gateway?

Q: What is the API gateway that has been mentioned in the article? And NGINX, Tomcat, Apache, and other web servers?

A: API gateway is a gateway used to unify the management services. For example, payment, user login, etc., are all services provided in the form of APIs, and they all need a gateway to do unified security and authentication.

API gateway can replace the traditional NGINX, Apache to deal with north-south traffic, but also in the microservices environment to deal with east-west traffic, is closer to the business of a middleware, rather than the underlying Web server.

For more information about the introduction and implementation of the API gateway, please refer to the Apache APISIX; Apache APISIX is based on the OpenResty implementation.