Skip to main content
Business Logic in Nginx

Business Logic in Nginx

·449 words·3 mins·
devops tools web
Table of Contents

Motivation
#

In some cases, you need a little bit more logic in your web proxy to handle certain traffic, especially if this traffic needs to be handled before being directed to the “upstream” application. In this case, the proxy should implement some logic to determine actions before the request is handled by the actual application.

Lua and OpenResty
#

OpenResty offers a platform with Nginx and Lua scripting capabilities (and more). Lua is a common programming language for embedding scripts in applications and is quite straightforward. For instance, Neovim also offers a Lua API and I wrote my whole Neovim configuration in Lua.

Example
#

To follow this example, you need Docker or Podman installed.

The following snippets illustrate a simple use case:

We want requests with a parameter id to be handled based on the value of said parameter. If id < 10 then we aim to redirect to Bing and if id >= 10 then we aim to redirect to Google.

Nginx conf
#

First, create a directory for our files:

mkdir nginx-logic
cd nginx-logic

Then we write the configuration file for Nginx with the Lua logic for handling the parameter.

touch default.conf

Edit default.conf with your editor of choice.

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        access_by_lua_block {
            local args = ngx.req.get_uri_args()
            for key, val in pairs(args) do
                if key == "id" then
                    if tonumber(val) >= 10 then
                        return ngx.redirect("https://google.com/?q=" .. val , ngx.HTTP_MOVED_PERMANENTLY)
                    end
                    if tonumber(val) < 10 then
                        return ngx.redirect("https://bing.com/?q=" .. val , ngx.HTTP_MOVED_PERMANENTLY)
                    end
                end
            end
        }
    }
}

The magic happens in the access_by_lua_block which should be self-explanatory. See the docs for more details and much more features.

Dockerfile
#

Now it is time to create our Dockerfile:

touch Dockerfile

Edit Dockerfile with your editor of choice.

FROM openresty/openresty
COPY default.conf /etc/nginx/conf.d/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Pretty simple, we copy our default.conf in to the image which is based on OpenResty.

Running
#

Build the Docker image with docker build . -t nginx-logic and run it with docker run -it --rm --name nginx-logic -p 3000:80 nginx-logic

Now let’s query our service (in my screenshots, I use httpie as curl alternative).

curl -I -L localhost:3000/?id=9
Our request is forwarded to Bing
curl -I -L localhost:3000/?id=11
Our request is forwarded to Google
curl -I -L localhost:3000
The default page; this might be your frontend

Conclusion
#

We implemented a simple use case, but you can imagine the flexibility this technique gives you. In general, I would prefer to implement business components in applications. However, in certain scenarios, it can be much cheaper to include such logic on the “infrastructure layer” instead of redesigning the application (architecture).