Master OpenResty: Install, Hello World, and Real‑World Lua Routing
This tutorial walks through installing OpenResty, creating a simple hello‑world service, and implementing a practical Lua‑based request routing example that distinguishes single‑ versus multiple‑UID POST bodies, complete with Nginx configuration, Go backend code, and testing steps.
OpenResty Introduction
OpenResty aggregates a collection of well‑designed Nginx modules (mostly developed by the OpenResty team) to turn Nginx into a powerful general‑purpose web application platform. Developers can use Lua scripts to invoke various C and Lua modules, building high‑performance web systems that handle tens of thousands to millions of concurrent connections. OpenResty aims to run your web service inside Nginx, leveraging its non‑blocking I/O model for both HTTP client requests and backend services such as MySQL, PostgreSQL, Memcached, and Redis.
OpenResty Installation
Refer to http://openresty.org/en/linux-packages.html Example for CentOS:
wget https://openresty.org/package/centos/openresty.repo
mv openresty.repo /etc/yum.repos.d/
yum check-update
yum install openresty
Hello World Program
mkdir -p /home/roshi/opensty/conf /home/roshi/opensty/logs
Create a configuration that outputs "hello world"
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 6699;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("HelloWorld")
}
}
}
}Run
With the installation method above, Nginx is placed in /usr/local/openresty. Execute:
/usr/local/openresty/nginx/sbin/nginx -p /home/roshi/openresty -c /home/roshi/openresty/conf/nginx.confTest
curl http://127.0.0.1:6699Processing Flow
OpenResty processes a request as illustrated in the diagram below:
Practical Example
Nginx is often used as a reverse proxy, routing requests under the same domain to different backend clusters based on URL patterns, e.g.: http://example.com/user/1 and http://example.com/product/1 When routing criteria are not present in headers or URLs—such as when they reside in the POST body—native Nginx cannot handle it, but OpenResty’s Lua scripts can.
Scenario: a POST request contains a JSON body with an array of uids. If the array has a single element, route to backend A; if it contains multiple elements, route to backend B.
worker_processes 1;
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
upstream single.uid { server host.docker.internal:8888; }
upstream multiple.uids { server host.docker.internal:9999; }
server {
listen 6699;
location / {
default_type application/json;
set $upstream_name 'multiple.uids';
rewrite_by_lua_block {
cjson = require 'cjson.safe'
ngx.req.read_body()
local body = ngx.req.get_body_data()
if body then
ngx.log(ngx.INFO, "body=" .. body)
local data = cjson.decode(body)
if data and type(data) == "table" then
local count = 0
for k,v in pairs(data["uids"]) do count = count + 1 end
ngx.log(ngx.INFO, "count = " .. count)
if count == 1 then
ngx.var.upstream_name = "single.uid"
end
end
end
}
proxy_pass http://$upstream_name;
}
}
}The second line changes the log level to info for easier debugging.
Two upstream blocks correspond to different back‑end services; because OpenResty runs inside a Docker container, host.docker.internal is used to reach the host machine. rewrite_by_lua_block parses the request body with cjson and sets the upstream based on the number of uids.
Lua code accesses Nginx variables via ngx.var.
Backend services are written in Go using the Echo framework:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"os"
"strconv"
)
type Response struct {
Success bool `json:"success"`
Message string `json:"message"`
Port int `json:"port"`
Uids []int `json:"uids"`
}
type Request struct {
Uids []int `json:"uids"`
}
var port = 8888
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.POST("/post", post)
if len(os.Args) >= 2 {
p, err := strconv.Atoi(os.Args[1])
if err == nil {
port = p
}
}
e.Logger.Fatal(e.Start(":" + strconv.Itoa(port)))
}
func post(c echo.Context) error {
req := Request{}
err := c.Bind(&req)
if err != nil {
c.JSON(500, Response{Success: false, Port: port, Message: "bind body error"})
return err
}
response := Response{Success: true, Port: port}
for _, uid := range req.Uids {
response.Uids = append(response.Uids, uid+100)
}
c.JSON(200, response)
return nil
}The services listen on ports 8888 and 9999. After starting them, send requests to port 6699 (the Nginx listener) and observe the results:
Log output can be found in /home/roshi/openresty/logs/error.log:
Conclusion
This article introduced OpenResty from installation and basic principles to a real‑world example, demonstrating its capability to handle complex routing logic with Lua scripts. Readers should now be able to get started with OpenResty.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Xiao Lou's Tech Notes
Backend technology sharing, architecture design, performance optimization, source code reading, troubleshooting, and pitfall practices
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
