Integrating Lua with Nginx for High-Performance Scripting

Lua Syntax Fundamentals

Nginx and Lua Environment

Objective: Use Nginx combined with Lua to implement a canary release strategy.

  1. Lua Overview
    A lightweight, compact, and highly extensible scripting language.
  2. Nginx+Lua Advantages
    Combines the efficient concurrency handling of Nginx's event-driven mechanism (epoll) with the agility of Lua, making it ideal for high-concurrency scenarios requiring simple logic execution.

Lua Syntax Basics

Variables
  • data = [[raw string \"content\"]]
  • data = 'escaped\nstring'
  • data = '\97lo\10\04923'

Boolean types consider only nil and false as false; numeric 0 and empty strings are evaluated as true. By default, variables are global unless explicitly declared local.

Loops
total = 0
i = 1
while i <= 100 do
  total = total + i
  i = i + 1
end
print("Total sum: ", total)
-- Lua does not support ++ or += operators

-- For loop example
aggregate = 0
for k = 1, 100 do
  aggregate = aggregate + k
end
Conditional Logic
if user_age == 30 and gender == "female" then
    print("30 year old female")
elseif user_age > 30 and gender ~= "male" then
    print("Older non-male")
else
    local input_age = io.read()
    print("Entered age: " .. input_age)
end

Reference: Lua Tutorial


Nginx and Lua Deployment

Deployment Guide Reference: Article Link

  1. Install LuaJIT
    wget http://luajit.org/download/LuaJIT-2.0.2.tar.gz
    tar -zxvf LuaJIT-2.0.2.tar.gz
    cd LuaJIT-2.0.2
    make install PREFIX=/usr/local/LuaJIT
    
    # Append environment variables to /etc/profile
    export LUAJIT_LIB=/usr/local/lib
    export LUAJIT_INC=/usr/local/include/luajit-2.0
    
  2. Download Modules
    cd /opt/download
    wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
    wget https://github.com/openresty/lua-nginx-module/archive/v0.10.9rc7.tar.gz
    # Extract both archives for inclusion during compilation
    
  3. Recompile Nginx
    # Download Nginx Source
    cd /data
    wget http://nginx.org/download/nginx-1.12.1.tar.gz
    tar -zxvf nginx-1.12.1.tar.gz;cd nginx-1.12.1
    
    # Install Prerequisites
    yum install openssl openssl-devel -y
    yum install zlib zlib-devel -y
    yum install pcre-devel -y
    
    # Compile Configuration
    ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --add-module=/data/ngx_devel_kit-0.3.0 --add-module=/data/lua-nginx-module-0.10.9rc7
    
    make && make install
    
    echo "/usr/local/lib" >> /etc/ld.so.conf
    ldconfig
    
    # Verify installation
    nginx -V
    

Verifying Lua Integration

# Add to /etc/nginx/conf.d/default.conf

server {
    listen       80;
    server_name web01.fadewalk.com;

    location /lua {
        set $message "hello,world";
        content_by_lua '
            ngx.header.content_type="text/plain"
            ngx.say(ngx.var.message)';

    }
}

Nginx Lua Module Directives

Nginx processes requests through 11 distinct phases. Lua modules can hook into specific stages of this lifecycle.

  • set_by_lua / set_by_lua_file: Assigns values to Nginx variables, enabling complex logic during variable assignment.
  • access_by_lua / access_by_lua_file: Executes during the access phase, typically used for access control and authentication.
  • content_by_lua / content_by_lua_file: Handles the content generation phase, processing requests and outputting responses.

Key Lua API Functions

  • ngx.var: Access to Nginx variables.
  • ngx.req.get_headers(): Retrieves HTTP request headers.
  • ngx.req.get_uri_args(): Retrieves URL query parameters.
  • ngx.redirect: Performs an HTTP redirect.
  • ngx.print: Outputs response body data.
  • ngx.say: Similar to ngx.print but appends a newline character.
  • ngx.header: Modifies output response headers.

Implementing Canary Release

Canary release involves rolling out new code versions to a subset of users to ensure stability before a full deployment. This strategy relies on differentiation logic such as user cookies, geographical location, or specific IP ranges.

dep.conf Configuration

server {
    listen       80;
    server_name  localhost;

    access_log  /var/log/nginx/log/host.access.log  main;
    
    location /hello {
        default_type 'text/plain';
        content_by_lua 'ngx.say("hello, lua")';
    }
 
    location /myip {
        default_type 'text/plain';
        content_by_lua '
            local cli_ip = ngx.req.get_headers()["x_forwarded_for"]
            ngx.say("Client IP:", cli_ip)';
    }

    location / {
        default_type "text/html"; 
        content_by_lua_file /opt/app/lua/dep.lua;
    }

    location @production_server{
        proxy_pass http://127.0.0.1:9090;
    }

    location @canary_server{
        proxy_pass http://127.0.0.1:8080;
    }

    error_page   500 502 503 504 404  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

dep.lua Script

-- Determine Client IP
local client_ip = ngx.req.get_headers()["X-Real-IP"]
if client_ip == nil then
    client_ip = ngx.req.get_headers()["x_forwarded_for"]
end
if client_ip == nil then
    client_ip = ngx.var.remote_addr
end

-- Connect to Memcached
local memcached = require "resty.memcached"
local memc, err = memcached:new()
if not memc then
    ngx.say("failed to instantiate memc: ", err)
    return
end

local ok, err = memc:connect("127.0.0.1", 11211)
if not ok then
    ngx.say("failed to connect: ", err)
    return
end

-- Check Feature Flag in Cache
local res, flags, err = memc:get(client_ip)

if err then
    ngx.say("failed to get clientIP ", err)
    return
end

ngx.say("lookup result: ", res, " for IP: ", client_ip)

if res == "1" then
    -- Redirect to Canary Environment
    ngx.exec("@canary_server")
    return
end

-- Default to Production
ngx.exec("@production_server")

Tags: nginx Lua LuaJIT web development Canary Release

Posted on Thu, 07 May 2026 13:09:47 +0000 by jdpatrick