我正在尝试将nginx用作我的TCP守护程序的代理,以使nginx为ssl/tls frontend,以及负载控制。
我的后端应用需要真实的客户端IP,这是一个问题。
stream {
server {
listen 3333;
proxy_pass 127.0.0.1:2222;
}
}
我在文档中找到了一个解决方案:
proxy_bind $remote_addr transparent;
但是太复杂了:
"为了使此参数工作,有必要运行nginx 具有超级用户特权并配置内核的工作过程 路由表可从代理服务器拦截网络流量。"
还有其他方法可以通过$ remote_addr来后端吗?
我尝试使用sub_filter,发送HTTP标头等修改客户端消息主体,但是所有这些都只能与HTTP上下文一起使用,而不是不幸的是。
据我所知,只有两个解决方案: proxy_bind
和 proxy_protocol
。
proxy_bind
正如您在文档中引用的那样,工作过程将需要 superuser 特权。明显地。这不是最好的做法。此外,它可能会导致连接问题回到远程客户端。
假设nginx作为nginx
用户运行,请运行此命令以授予其权限。
usermod -aG sudo nginx
proxy_protocol
此解决方案需要上层目标(例如后端应用程序)接受代理协议。
stream {
server {
listen 3333;
proxy_pass 127.0.0.1:2222;
proxy_protocol on;
}
}
上面的解决方案假设Nginx服务器是网络的入口点。如果有边缘设备(例如负载平衡器),则很可能正在更改源IP。在这种情况下,您需要在边缘设备上启用代理协议,并在server
块中启用proxy_protocol
侦听器。我没有测试过,但是类似的东西应该起作用。
stream {
server {
listen 3333 proxy_protocol;
proxy_pass 127.0.0.1:2222;
proxy_protocol on;
set_real_ip_from $proxy_protocol_addr;
}
}
我的设置:
- nginx流模块作为SSH和HTTPS的TCP代理
- nginx http模块服务我的内容
我的要求:在accept.log中具有真实的客户端IP(而不是流模块中的127.0.0.1),也用于GeoDblocking
我的解决方案:
- 激活proxy_protocol(在请求中添加其他信息)
- 添加" Proxy_procotol"在http侦听指令中(供http服务器接受)
- 在流模块和SSH之间添加额外的代理,以删除能够读取 的proxy_protocol
- 替换" $ remote_addr"使用" $ proxy_protocol_addr"在Access.log
对于构造,您还必须使用proxy_protocol_addr,但我将在此处省略以保持简短。
nginx.conf:
...
stream {
upstream ssh {
server 127.0.0.1:2222;
}
upstream https {
server 127.0.0.1:444;
}
map $ssl_preread_protocol $upstream {
default ssh;
"TLSv1.2" https;
"TLSv1.3" https;
"TLSv1.1" https;
"TLSv1.0" https;
}
server {
listen 443;
proxy_pass $upstream;
proxy_protocol on;
ssl_preread on;
}
server {
listen 2222 proxy_protocol;
proxy_pass 192.168.2.76:22;
}
}
http {
log_format main '$proxy_protocol_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
...
server {
listen 444 ssl proxy_protocol;
...
}
}
" set_real_ip_from"指令应为边缘设备的地址/cidr
stream {
server {
listen 3333 proxy_protocol;
proxy_pass 127.0.0.1:2222;
proxy_protocol on;
set_real_ip_from 10.0.0.0/8;
}
}