前言
由于要开始用nginx的tcp代理,发现最终http打印出来的IP都是最后一个代理的内网IP,这就不方便去查问题了。那就依样画葫芦吧。但是发现个问题,TCP层面哪里有header头啊。还好nginx提供了stream_realip这个模块。
1
|
./configure --with-http_geoip_module --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_v2_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-file-aio --with-stream --with-stream_ssl_module --with-stream_realip_module --with-stream_geoip_module --with-stream_ssl_preread_module --with-pcre --prefix=/opt/nginx
|
我实际的网络结构如下:
1
|
user1 ---> SLB ---> nginx tcp proxy1 ---> nginx tcp proxy2 ---> nginx http server
|
先说这个处理的思路吧。大家都知道tcp是没有header这些东西的,那就只能从data部分来着手了。TCP proxy_protocol的定义其实就是在数据报文最前面加上对应的IP信息。然后最后一个server解开这个data前面的IP信息。
但是一开始没有这个思路,就看了官方文档大干快上。
http://nginx.org/en/docs/stream/ngx_stream_realip_module.html
排查
把nginx tcp proxy1和proxy2的配置改成如下:
1 2 3 4 5
|
server { set_real_ip_from 172.16.0.0/16; listen 21000 so_keepalive=on; proxy_pass goapi; }
|
其中172.16.0.0/16是当中传输的网段,然后看了下nginx http server的日志,发现没有生效啊。这文档骗人啊。
然后放狗搜了下,这个哥们一样的问题
https://stackoverflow.com/questions/40873393/nginx-real-client-ip-to-tcp-stream-backend
于是上面的配置又改成了如下:
1 2 3 4 5 6
|
server { set_real_ip_from 172.16.0.0/16; listen 21000 proxy_protocol so_keepalive=on; proxy_protocol on; proxy_pass goapi; }
|
结果这样改了,连服务都不通了,curl一下直接返回400了,看了下http server的日志
1 2
|
~ » curl -I http://api.timoq.com curl: (52) Empty reply from server
|
1
|
172.16.106.16 api.timoq.com - [2019-12-25T19:43:50+08:00] "PROXY TCP4 172.16.0.6 172.16.0.16 21000 80" 400 631 "-" "-" "-" 0.000|-|-|-|-||-|-$
|
nginx http server收到的请求变成了”PROXY TCP4 172.16.0.6 172.16.0.16 40173 80”, 而不是实际的URL。
现象就跟下面这个的一样
https://stackoverflow.com/questions/46948866/verify-if-nginx-is-working-correctly-with-proxy-protocol-locally
这看着还是配置文件不对导致的。看来各种教程有问题啊。于是又仔细看了看了下官方文档
https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
这篇还是说的比较清楚的,也就是我前面总结的那个。那我们重新梳理一下
1
|
user1 ---> SLB(透明代理) ---> nginx tcp proxy1(在data头部增加realip) ---> nginx tcp proxy2(默认tcp传输,不改变数据包) ---> nginx http server(解开nginx tcp proxy1里在data里增加的realip)
|
去nginx http server抓包看了下,确实如此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
>E@@I0j ueWbQ/OH fhPROXY TCP4 222.73.97.11 192.168.0.6 53136 21000 HEAD /aaaaa HTTP/1.1 Host: api.timoq.com User-Agent: curl/7.54.0 Accept: */*
>E@@I0j ueWbQ/OH fhPROXY TCP4 222.73.97.11 192.168.0.6 53136 21080 HEAD /aaaaa HTTP/1.1 Host: api.timoq.com User-Agent: curl/7.54.0 Accept: */*
|
终结
因此最终的配置就是如下了:
nginx tcp proxy1
1 2 3 4 5 6
|
server { set_real_ip_from 172.16.0.0/16; listen 21000 so_keepalive=on; proxy_protocol on; proxy_pass goapi; }
|
nginx tcp proxy2
1 2 3 4 5
|
server { set_real_ip_from 172.16.0.0/16; listen 21000 so_keepalive=on; proxy_pass goapi; }
|
nginx http server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
http{ log_format proxy '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';
server { listen 80 proxy_protocol;
set_real_ip_from 172.16.0.0/16; proxy_http_version 1.1; proxy_set_header Connection ""; access_log /opt/logs/nginx/proxy_api.timoq.com proxy; server_name api.timoq.com; real_ip_header proxy_protocol; proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_set_header X-Forwarded-For $proxy_protocol_addr;
include conf.d/include/api.conf; } }
|