Nginx/OpenResty 反代配置最佳实践
引言
大家好,今天来聊聊 Nginx 和 OpenResty 反向代理配置的那些事儿。说起来,反向代理可以说是咱们日常开发中最常用的技术手段之一了,不管是前后端分离架构、负载均衡,还是 API 网关,都离不开它。我自己在项目里也踩过不少坑,今天就把这些经验整理一下,分享给各位。
咱们今天不聊太基础的东西,假设你已经知道什么是反向代理、怎么安装 Nginx。主要来看看,在生产环境中,哪些配置能让你的反代更稳、更快、更安全。
一、基础反代配置:这些坑别再踩了
先说最基础的配置。很多人写反代就是简单写个 proxy_pass,完事儿。但其实这里有不少细节要注意。
location /api/ {
proxy_pass http://backend.example.com;
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 $scheme;
}
上面这段代码,有几个关键点得强调一下:
1. Header 传递:X-Real-IP 和 X-Forwarded-For 必须设置,不然后端日志里全是 Nginx 的 IP,你还想不想排查问题了?X-Forwarded-For 要用 $proxy_add_x_forwarded_for,这样才能保留完整的代理链。
2. 连接超时:生产环境一定要设置超时时间,别用默认的。你永远不知道后端会不会卡死。
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
3. Buffer 机制:Nginx 默认会缓冲后端响应,这对大多数场景是友好的,但如果你做的是实时推送或者大文件下载,得考虑关闭 buffer。
# 关闭 buffer,适合实时流
proxy_buffering off;
chunked_transfer_encoding off;
二、负载均衡:别把所有鸡蛋放一个篮子
单节点反代始终是个单点故障,生产环境肯定得上负载均衡。Nginx 自带的 upstream 模块就能搞定这个,而且配置相当简单。
upstream backend {
least_conn; # 最少连接数算法
server backend1.example.com:8080 weight=3;
server backend2.example.com:8080 weight=2;
server backend3.example.com:8080 backup; # 备用节点
}
server {
location / {
proxy_pass http://backend;
# 健康检查相关
proxy_connect_timeout 3s;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_tries 2;
}
}
这里有几个小技巧:
- 权重分配:根据机器性能合理设置权重,性能强的多分配点请求,很正常的事儿。
- backup 节点:关键时刻能救命,当主要节点都挂了,backup 会自动上场。
- 故障转移:proxy_next_upstream 这个指令非常实用,遇到 500 错误或者超时,自动切换到下一个节点,用户基本无感知。
不过说实话,Nginx 自带的上游健康检测比较基础。如果你的业务对高可用要求极高,可以考虑用 nginx_upstream_check_module 这个第三方模块,或者在 OpenResty 里用 Lua 实现更精细的健康检查逻辑。
三、缓存配置:让响应飞起来
反向代理另外一个重要作用就是缓存。配置好了,能大幅减轻后端压力,用户访问速度也能快不少。
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=api_cache:10m
max_size=1g inactive=60m use_temp_path=off;
server {
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$request_method$host$request_uri";
# 条件化缓存
proxy_cache_bypass $http_cache_bypass;
proxy_cache_use_stale error timeout http_500 http_502 http_503;
add_header X-Cache-Status $upstream_cache_status;
}
}
几点经验之谈:
1. 缓存 key 设计:一定要根据业务特点设计好缓存 key。Query 参数要不要包含?POST 请求的 body 怎么处理?这些都得想清楚。
2. 缓存失效策略:inactive 参数设置的是多长时间没人访问就删除,而 proxy_cache_valid 是针对不同状态码的缓存时间。两者配合使用效果更好。
3. 调试技巧:加上 X-Cache-Status 这个响应头,HIT/MISS/EXPIRED 一目了然,排查问题特别方便。
4. 条件缓存:用 proxy_cache_bypass 可以实现按需绕过缓存,比如登录用户不走缓存,这个在项目中很常见。
四、安全加固:别让人有机可乘
反代作为入口,安全方面可得重视起来。下面这些配置,建议都加上:
server {
# 隐藏 Nginx 版本号
server_tokens off;
# 防止常见攻击
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNet-Version;
# 限流防爬
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
# 禁止敏感目录
if ($request_uri ~* "\.(git|env|conf)$") {
return 403;
}
}
}
}
防止 DDoS
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location / {
limit_conn addr 10;
}
}
这里有个小提醒:限流配置要根据实际业务流量来调,别一上来就限得太死,容易误伤正常用户。建议先用 ngx_http_stub_status_module 监控一段时间,摸清流量规律再调整。
五、OpenResty 高级玩法:Lua 脚本赋能
如果说普通 Nginx 是把瑞士军刀,那 OpenResty 就是加装了各种插件的超级武器库。借助 Lua 脚本,我们可以实现很多原生 Nginx 做不到的功能。
动态路由
-- init_by_lua_block 中加载配置
local route_rules = {
["/api/v1/user"] = "user-service",
["/api/v1/order"] = "order-service",
["/api/v1/pay"] = "pay-service"
}
server {
location ~ ^/api/v1/(\w+) {
set $service_name "";
rewrite_by_lua_block {
local path = ngx.var.uri
local service = route_rules[path]
if service then
ngx.var.service_name = service
else
return ngx.exit(404)
end
}
proxy_pass http://$service_name;
}
}
请求限流与熔断
local function check_rate_limit(key, rate, burst)
local limit = ngx.shared.rate_limit
local current = limit:get(key) or 0
if current > rate then
return false
end
limit:incr(key, 1, 0, 1) -- 1秒后重置
return true
end
access_by_lua_block {
if not check_rate_limit(ngx.var.binary_remote_addr, 100, 50) then
ngx.exit(429) -- Too Many Requests
end
}
请求改写与参数处理
有时候后端接口规范和前端不一样,需要在网关层做转换:
rewrite_by_lua_block {
local args = ngx.req.get_uri_args()
-- 旧版 API 参数兼容
if args.old_param then
args.new_param = args.old_param
args.old_param = nil
ngx.req.set_uri_args(args)
end
}
OpenResty 的玩法真的很多,动态限流、灰度发布、请求日志、熔断降级……只要你敢想,基本都能实现。唯一需要注意的是 Lua 代码的性能,别写个死循环把自己坑了。
总结
好,今天聊了不少,总结一下重点:
1. 基础配置:Header 传递、超时设置、Buffer 调优,这些看似简单,但出问题的时候都是因为没配置好。
2. 负载均衡:合理设置权重,配置好故障转移,关键时刻能救命。
3. 缓存策略:根据业务特点设计缓存 key,调试时加上状态头方便排查。
4. 安全加固:隐藏版本号、限流防爬、敏感文件防护,一个都不能少。
5. OpenResty:用 Lua 脚本可以实现很强大的自定义逻辑,是进阶玩家的必备技能。
反向代理配置看起来简单,但要做到生产级别稳定可靠,里面的门道还是很多的。希望这篇文章能帮到各位,如果有问题,欢迎在评论区交流讨论。咱们下期再见!
Nginx/OpenResty 反代配置最佳实践
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法