一.penResty介绍 OpenResty 是我们构建高性能、高并发 Web 架构时不可或缺的利器。它不仅仅是一个 Web 服务器,更是一个基于 Nginx 与 Lua 的高性能 Web 平台 。
简单来说,OpenResty 将 Nginx (高性能反向代理/负载均衡器)与 LuaJIT (高性能即时编译器)以及一系列 Lua 模块完美集成,让你能够直接在 Nginx 内部编写业务逻辑,而无需依赖后端应用服务器(如 Java, Go, Python)来处理所有请求。
1.核心架构与原理 OpenResty 的核心在于 Nginx + LuaJIT + 丰富模块 的组合:
Nginx 基础 :继承了 Nginx 的事件驱动、异步非阻塞 I/O 模型和多进程架构(Master/Worker),能够轻松应对高并发连接 1 。
LuaJIT 加速 :内置了 LuaJIT (Lua Just-In-Time Compiler),它将 Lua 脚本编译成机器码直接执行,性能比标准 Lua 快数倍,几乎消除了脚本语言的开销 3 。
11 个执行阶段 :OpenResty 完美映射了 Nginx 的 11 个 HTTP 处理阶段(如 rewrite, access, content, log 等),允许你在每个阶段注入 Lua 代码来拦截、修改或生成响应
2.核心特性与优势
超高并发性能:
利用 Nginx 的非阻塞 I/O,单个 Worker 进程可处理数万并发连接。
LuaJIT 的即时编译使得 Lua 代码的执行效率接近 C 语言,响应时间通常减少 40-60% 1 。
动态内容生成:
无需启动后端应用,直接在 Nginx 层通过 Lua 生成动态页面或 API 响应,极大降低延迟。
灵活的请求处理:
访问控制 :在 access_by_lua 阶段进行复杂的身份验证、IP 黑白名单、API 限流 2 。
动态路由 :根据请求头、参数或数据库状态,动态决定将请求转发到哪个后端服务 2 。
协议转换 :轻松实现 HTTP 到 WebSocket、TCP/UDP 的转换。
丰富的内置模块:
**ngx_lua**:核心模块,提供 Lua 脚本执行能力。
**ngx_http_redis / resty.redis**:直接连接 Redis,实现高性能缓存 3 。
**ngx_http_lua_upstream**:在 Lua 中动态代理请求到上游服务器。
**ngx_http_headers_more**:灵活添加/删除 HTTP 响应头。
**ngx_stream_lua**:支持 TCP/UDP 流量的 Lua 处理(非 HTTP 协议)3 。
3. 典型应用场景 作为运维,OpenResty 常用于以下场景:
API 网关:
实现统一的鉴权(JWT 校验)、限流(基于 IP 或用户 ID)、熔断降级。
动态路由:根据版本号(/api/v1, /api/v2)将请求分发到不同后端 2 。
高性能缓存层:
利用 lua_shared_dict 实现进程间共享内存缓存,减少数据库压力。
直接连接 Redis 缓存热点数据,实现“边缘缓存” 2 。
动态负载均衡:
根据后端服务器的健康状态、负载情况,动态调整权重或剔除故障节点。
协议适配与转换:
将 HTTP 请求转换为内部 RPC 调用,或将 TCP 流量(如游戏服)进行逻辑处理。
安全防御:
第一步:下载与安装 OpenResty
下载: 前往 OpenResty 官网下载页 。
选择版本: 选择 Win64 版本(例如 openresty-1.29.2.1-win64.zip)。
解压: 将其解压到你服务器的路径,例如 D:\openresty-1.29.2.1-win64
第二步:准备 JWT 插件库 OpenResty 需要一个 Lua 库来处理 JWT。
下载 lua-resty-jwt 里的 jwt.lua 和 hmac.lua、string.lua。
下载地址:
https://raw.githubusercontent.com/SkyLothar/lua-resty-jwt/master/lib/resty/jwt.lua
https://raw.githubusercontent.com/openresty/lua-resty-string/master/lib/resty/string.lua
https://raw.githubusercontent.com/jkeys089/lua-resty-hmac/master/lib/resty/hmac.lua
将这些 .lua 文件放入 D:\openresty-1.29.2.1-win64\lualib\resty 目录下。
第三步:配置 HTTPS 证书 在D:\openresty-1.29.2.1-win64\conf\ssl 目录下放置你的 server.crt 和 server.key。 (如果没有,参考使用 OpenSSL 生成自签名证书)。
1 openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout server.key -out server.crt
第四步:编写核心配置文件 nginx.conf 编辑 D:\openresty-1.29.2.1-win64\conf\nginx.conf,清空内容并粘贴以下配置。该配置实现了:强制 HTTPS + API Key 校验 + JWT 令牌校验 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 worker_processes auto; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; # Lua 包路径 lua_package_path "D:/openresty-1.29.2.1-win64/lualib/?.lua;D:/openresty-1.29.2.1-win64/conf/lua/?.lua;;"; lua_package_cpath "D:/openresty-1.29.2.1-win64/lualib/?.dll;;"; # 【全局优化】增加请求体大小,防止模型输入长文本报错 client_max_body_size 50m; server { listen 80; server_name 192.168.11.12; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name 192.168.11.12; ssl_certificate D:/openresty-1.29.2.1-win64/conf/ssl/server.crt; ssl_certificate_key D:/openresty-1.29.2.1-win64/conf/ssl/server.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # ---------------------------------------------------- # 1. vLLM 模型服务转发 (匹配 /v1 路径,OpenAI 标准接口) # ---------------------------------------------------- location /v1/ { # 开启鉴权与白名单 access_by_lua_file D:/openresty-1.29.2.1-win64/conf/lua/auth_jwt.lua; proxy_pass http://192.168.11.15:10001; # --- vLLM 关键优化配置 --- proxy_buffering off; # 必须关闭缓存,支持流式输出(Stream) proxy_http_version 1.1; # 保持长连接 proxy_set_header Connection ""; proxy_read_timeout 600s; # 调大超时时间,防止长文本推理中断 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_set_header X-Forwarded-Proto https; } # ---------------------------------------------------- # 2. 原有的 8080 业务服务转发 (匹配其他所有路径) # ---------------------------------------------------- location / { # 同样开启鉴权与白名单 access_by_lua_file D:/openresty-1.29.2.1-win64/conf/lua/auth_jwt.lua; proxy_pass http://192.168.11.15:8080; 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_set_header X-Forwarded-Proto https; # 普通业务通常不需要关闭 buffering,保持默认即可 proxy_buffering on; } # ---------------------------------------------------- # 3. 公共路径(不需鉴权) # ---------------------------------------------------- location /health { access_by_lua_block { ngx.say("OK"); ngx.exit(200) } } location = /favicon.ico { log_not_found off; access_log off; return 204; } } }
第五步:编写auth_jwt.lua 在D:\openresty-1.29.2.1-win64\conf\lua下创建auth_jwt.lua,同时需要更改成自己的秘钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 -- ========================================== -- 生产环境稳妥版:IP 白名单 + JWT 鉴权脚本 -- ========================================== local jwt = require("resty.jwt") -- 【配置区 1】JWT 签名秘钥 (必须与签发端一致) local secret_key = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6ImFkbWluIiwibmFtZSI6IlRlc3QgVXNlciIsImlhdCI6MTc3NDQyMzE3NiwiZXhwIjoxNzc0NDI2Nzc2fQ.8iEvpWaOEirpgIcK20IPXEQBCGpY84EwNTBPqMwEAoA" -- 【配置区 2】白名单:完全匹配的特定 IP 地址 local whitelist_ips = { ["127.0.0.1"] = true, -- 本机测试 ["192.168.3.35"] = true, -- 示例:某台特定管理机 ["192.168.3.91"] = true, -- 示例:某台监控服务器 } -- 【配置区 3】白名单:网段前缀 (支持 1-2 个网段) -- 只要客户端 IP 是以这些字符串开头的,就直接放行 local whitelist_prefixes = { "192.168.13.", -- 示例网段 A:192.168.1.x 全部放行 "10.100.", -- 示例网段 B:10.10.x.x 全部放行 "172.16.5." -- 示例网段 C } -- ========================================== -- 核心逻辑开始 -- ========================================== -- 1. 获取客户端真实 IP local client_ip = ngx.var.remote_addr -- 2. 检查特定 IP 白名单 (完全匹配) if whitelist_ips[client_ip] then ngx.log(ngx.INFO, "[Auth] IP 在特定白名单中,放行: ", client_ip) return end -- 3. 检查网段前缀白名单 for _, prefix in ipairs(whitelist_prefixes) do if string.sub(client_ip, 1, string.len(prefix)) == prefix then ngx.log(ngx.INFO, "[Auth] IP 属于白名单网段,放行: ", client_ip) return end end -- 4. 如果 IP 不在白名单,则开始 JWT 强制校验 local auth_header = ngx.var.http_authorization -- 4.1 检查是否存在 Authorization Header if not auth_header then ngx.status = 401 ngx.header.content_type = "application/json; charset=utf-8" ngx.say('{"error": "Unauthorized", "message": "Missing Authorization Header", "client_ip": "' .. client_ip .. '"}') ngx.exit(401) end -- 4.2 提取 Bearer Token local _, _, token = string.find(auth_header, "Bearer%s+(.+)") if not token then ngx.status = 401 ngx.header.content_type = "application/json; charset=utf-8" ngx.say('{"error": "Unauthorized", "message": "Invalid Token Format (Bearer token required)"}') ngx.exit(401) end -- 4.3 校验 JWT 签名与有效期 local jwt_obj = jwt:verify(secret_key, token) if not jwt_obj.verified then ngx.status = 401 ngx.header.content_type = "application/json; charset=utf-8" -- jwt_obj.reason 会显示具体的失败原因(如:token expired, signature mismatch) ngx.say('{"error": "Unauthorized", "message": "JWT Verification Failed", "reason": "' .. (jwt_obj.reason or "unknown") .. '"}') ngx.exit(401) end -- 校验成功:Nginx 会继续转发请求到 proxy_pass
生成秘钥python脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #!/usr/bin/env python3 import jwt import time import json # ⚠️ 这个密钥必须与 auth_jwt.lua 中的 SECRET 完全一致 SECRET = "your-256-bit-secret-key-change-me-12345" # Token 有效期(秒) EXPIRY_SECONDS = 3600 # 1 小时 def generate_token(user_id, role="user", name=""): """生成 JWT token""" payload = { "sub": user_id, # 用户 ID "role": role, # 用户角色 "name": name, # 用户名 "iat": int(time.time()), # 签发时间 "exp": int(time.time()) + EXPIRY_SECONDS # 过期时间 } token = jwt.encode(payload, SECRET, algorithm="HS256") return token if __name__ == "__main__": print("=" * 70) print("JWT Token Generator") print("=" * 70) # 生成示例 token token = generate_token( user_id="user123", role="admin", name="Test User" ) print("\nToken:\n") print(token) print("\n" + "=" * 70) print("Usage:") print("=" * 70) print("\n1. curl test:") print(f' curl -k -H "Authorization: Bearer {token}" https://localhost/') print("\n2. PowerShell test:") print(f' $token = "{token}"') print(f' curl -k -H "Authorization: Bearer $token" https://localhost/') print("\n" + "=" * 70) print("Token Info:") print("=" * 70) # 解码显示 payload(不验证签名) decoded = jwt.decode(token, options={"verify_signature": False}) print(json.dumps(decoded, indent=2, ensure_ascii=False)) print(f"\nExpiry: {EXPIRY_SECONDS} seconds ({EXPIRY_SECONDS // 60} minutes)") print("=" * 70)
配置完成后启动D:\openresty-1.29.2.1-win64中的nginx即可。
The End