OpenResty
High-performance web platform integrating Nginx and LuaJIT. Achieves native C-level performance while using scripting language. Specialized in API Gateway, microservices, and dynamic content processing.
Web Server
OpenResty
Overview
OpenResty is a high-performance web application platform that integrates Nginx and LuaJIT. By incorporating a Lua script execution environment into the Nginx core, it achieves native C-language-level performance despite being a scripting language. This innovative platform specializes in dynamic content processing, API Gateway, and microservices environments, balancing flexibility and high performance.
Details
OpenResty was started in 2009 by Yichun Zhang (agentzh), a Cloudflare engineer from China, and currently holds a 10.8% share of the global market. Adoption is particularly increasing in API Gateway and microservices architectures, with a rich Lua library ecosystem being built.
Key Technical Features
- LuaJIT Integration: High-speed script execution through Just-In-Time compiler
- Asynchronous I/O: Nginx-based event-driven architecture
- Rich Lua Libraries: Over 100 dedicated libraries available
- Real-time Processing: Lua execution at each phase of request processing
- Database Integration: Asynchronous access to MySQL, PostgreSQL, Redis, etc.
Use Cases
- API Gateway and proxy servers
- Dynamic content generation
- Real-time web applications
- Communication control between microservices
- High-performance web service development
Advantages and Disadvantages
Advantages
- Native-level Performance: C-language-level execution speed through LuaJIT
- Development Efficiency: Rapid development and deployment with scripting language
- Rich Libraries: Redis, MySQL, HTTP client, etc. available
- Flexible Processing: Custom logic execution at each request stage
- Nginx Compatibility: Can leverage existing Nginx configuration assets
- Scalability: High concurrent connection processing capability through asynchronous processing
Disadvantages
- Learning Cost: Knowledge of both Lua and Nginx required
- Debugging Difficulty: Combination of asynchronous processing and scripting
- Community Size: Smaller compared to Nginx or Apache
- Complex Configuration: Configuration complexity when using advanced features
- Memory Usage: Additional memory consumption due to Lua runtime
Reference Pages
Configuration Examples
Basic OpenResty Configuration
# nginx.conf
worker_processes auto;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
# Lua package path
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
server {
listen 80;
server_name example.com;
location /hello {
content_by_lua_block {
ngx.say("Hello, OpenResty!")
}
}
}
}
API Endpoint Using Lua File
-- /usr/local/openresty/nginx/lua/api.lua
local json = require "cjson"
local redis = require "resty.redis"
local _M = {}
function _M.get_user(user_id)
-- Redis connection
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
return ngx.exit(500)
end
-- Get user information
local user_data, err = red:get("user:" .. user_id)
if not user_data or user_data == ngx.null then
ngx.status = 404
ngx.say(json.encode({error = "User not found"}))
return
end
-- Return response
ngx.header.content_type = "application/json"
ngx.say(user_data)
red:close()
end
return _M
API Gateway Configuration Example
# API Gateway configuration
upstream backend_auth {
server auth-service:8080;
}
upstream backend_users {
server user-service:8080;
}
upstream backend_orders {
server order-service:8080;
}
server {
listen 80;
server_name api.example.com;
# Authentication check
location /auth {
internal;
proxy_pass http://backend_auth/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
# API v1 routing
location /api/v1/users {
access_by_lua_block {
local auth_result = ngx.location.capture("/auth")
if auth_result.status ~= 200 then
ngx.status = 401
ngx.say('{"error":"Unauthorized"}')
ngx.exit(401)
end
}
proxy_pass http://backend_users;
proxy_set_header X-User-ID $upstream_http_x_user_id;
}
location /api/v1/orders {
access_by_lua_file /usr/local/openresty/nginx/lua/auth_check.lua;
proxy_pass http://backend_orders;
}
}
Rate Limiting and Security
-- /usr/local/openresty/nginx/lua/rate_limit.lua
local limit_req = require "resty.limit.req"
-- Rate limiting configuration (100 requests per minute)
local lim, err = limit_req.new("rate_limit_store", 100, 60)
if not lim then
ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
return ngx.exit(500)
end
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
ngx.status = 429
ngx.header.content_type = "application/json"
ngx.say('{"error":"Too Many Requests"}')
ngx.exit(429)
end
ngx.log(ngx.ERR, "failed to limit req: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
ngx.sleep(delay)
end
Database Connection Example
-- /usr/local/openresty/nginx/lua/db_handler.lua
local mysql = require "resty.mysql"
local json = require "cjson"
local _M = {}
function _M.get_products()
local db, err = mysql:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
return ngx.exit(500)
end
db:set_timeout(1000)
local ok, err, errno, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "shop",
user = "app_user",
password = "password",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
if not ok then
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errno, " ", sqlstate)
return ngx.exit(500)
end
local query = "SELECT id, name, price FROM products WHERE active = 1 LIMIT 10"
local res, err, errno, sqlstate = db:query(query)
if not res then
ngx.log(ngx.ERR, "bad result: ", err, ": ", errno, ": ", sqlstate, ".")
return ngx.exit(500)
end
ngx.header.content_type = "application/json"
ngx.say(json.encode(res))
db:close()
end
return _M
WebSocket Proxy
# WebSocket-compatible proxy configuration
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name ws.example.com;
location /ws {
access_by_lua_block {
-- WebSocket connection authentication
local auth_token = ngx.var.arg_token
if not auth_token then
ngx.status = 401
ngx.say("Missing auth token")
ngx.exit(401)
end
-- Token verification logic
-- In actual implementation, call external authentication service
}
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 86400;
}
}
Logging and Monitoring
-- /usr/local/openresty/nginx/lua/logging.lua
local json = require "cjson"
-- Custom log output
local function log_request()
local log_data = {
timestamp = ngx.time(),
method = ngx.var.request_method,
uri = ngx.var.request_uri,
status = ngx.var.status,
response_time = ngx.var.request_time,
user_agent = ngx.var.http_user_agent,
remote_addr = ngx.var.remote_addr,
request_id = ngx.var.request_id
}
ngx.log(ngx.INFO, "REQUEST_LOG: ", json.encode(log_data))
end
-- Execute at request completion
ngx.ctx.log_request = log_request