背景
部门因之前做web聊天应用,7层接入大量使用了haproxy。后来做第三方接入,针对https的应用场景,开始引入nginx。使用过程中发现nginx的插件非常丰富、特别是支持lua、而且方便进行模块开发定制。慢慢的开始替换haproxy,成为主要的7层接入组件。运营过程中也遇到不少问题,这里简单case by case做个总结记录:
总结
1. proxy_set_header
这个是后台鉴权server需要调用方提供一个QC_REAL_IP的http头做校验,我在nginx里配置如下:
-
proxy_set_header QC_REAL_IP $http_host;
-
location ^~/authorize/ {
-
proxy_set_header Host $http_host;
-
proxy_pass http://authorize_server;
-
proxy_redirect off;
-
}
但是,却发现鉴权不成功,一直是返回503。掏出tcpdump抓包:
-
tcpdump -i eth1 -nn -Als0p 'tcp and host author_server_ip and port author_server_port'
分析nginx发出的包头里没有QC_REAL_IP字段,遂翻阅nginx wiki,找到这行
proxy_set_header directives issued at higher levels are only inherited when no proxy_set_header directives have been issued at a given level.
原来proxy_set_header不完全是继承关系!把QC_REAL_IP的配置copy一份到location里,终于生效了。
2. nginx https proxy
平时拿nginx做proxy我有个习惯,一般会把upstream、proxy_pass名字一致,但稍微区分于server_name.例如:
-
upstream xxoo_com {
-
server 10.8.8.8:8080;
-
}
-
-
server {
-
listen 443;
-
server_name xxoo.com
-
... ...
-
location / {
-
proxy_pass http://xxoo_com;
-
proxy_redirect off;
-
}
-
}
重启nginx后,访问测试第一个https访问是正常的,由后端server返回的302跳转全部变成了http请求。自己找资料,不断调试,tcpdump抓包分析,继续调。最后意外发现,把upstream, proxy_pass名改成和server_name一致就可以了。
抓包发现nginx的proxy模块请求backend的http header中Host字段指就是proxy_pass 指令的值。nginx根据该Host是否和server_name匹配绝对是否对前端返回https。
3. 透传客户端ip
一般情况我们在nginx接入侧配置这条足以:
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_add_x_forwarded_for的值为: 客户端穿过来的x_forwarded_for值+ remote_addr。如果客户端传来的x-forwarded-for值本事是非法、错误的。那么后端应用如果截取左起第一个字段获取到的ip值也是错误。
这个一般有2个办法,首先,可以在nginx接入对很明显非法的ip摘掉,强制把remote_addr值添到X-Forwarded-For字段:
-
set $my_proxy_add_x_forwarded_for $proxy_add_x_forwarded_for;
-
if ($proxy_add_x_forwarded_for ~* "127.0.0.1"){
-
set $my_proxy_add_x_forwarded_for $remote_addr;
-
}
-
proxy_set_header X-Forwarded-For $my_proxy_add_x_forwarded_for;
另外,如果是做ip频率限制、校验的话,还不如直接取X-Forwarded-For值的最后一段。因为伪造x-forword-for值的成本太低了。
4. 记录自动化测试用例请求
为定位问题时提供数据参考,如: 记录cookies中uin在某范围的请求延迟、返回码等。
这里用到lua:
-
if ngx.var.cookie_uin ~= nil then
-
local uin = tonumber(string.sub(ngx.var.cookie_uin,2,-1))
-
-
-
if uin ~= nil and uin >=1011000140 and uin<=1011000149 then
-
--ngx.log(ngx.CRIT, "[ATT] att_client:"..ngx.var.remote_addr..",rsp_time:"..ngx.var.request_time..",upstream_rsp_time:" .. ngx.var.upstream_response_time .. ",upstream_addr:" .. ngx.var.upstream_addr..",upstream_status:"..tostring(ngx.var.upstream_status..","));
-
ngx.log(ngx.CRIT, "[ATT] att_uin:".. uin..",rsp_time:"..ngx.var.request_time..",upstream_rsp_time:" .. ngx.var.upstream_response_time .. ",upstream_status:"..ngx.var.upstream_status..",");
-
end
阅读(2241) | 评论(0) | 转发(0) |