Nginx真实客户端IP到TCP流后端

J_z*_*J_z 6 nginx

我正在尝试使用Nginx作为TCP守护进程的代理,以使Nginx成为SSL / TLS前端以及负载控制。

我的后端应用程序需要真实的客户端IP,这是一个问题。

stream {
    server {
        listen     3333;
        proxy_pass 127.0.0.1:2222;
    }
}
Run Code Online (Sandbox Code Playgroud)

我在文档中找到了一种解决方案:

proxy_bind $remote_addr transparent;
Run Code Online (Sandbox Code Playgroud)

但这太复杂了:

“为了使该参数起作用,必须以超级用户特权运行nginx worker进程,并配置内核路由表以拦截来自代理服务器的网络流量。”

还有其他方法可以将$ remote_addr传递到后端吗?

我尝试使用sub_filter修改客户端消息正文,发送HTTP标头等。但是,所有这些都只能在http上下文中使用,不幸的是,不能在流中使用。

Sgt*_*tOJ 7

据我所知,只有两种解决方案:proxy_bindproxy_protocol

代理绑定

正如您从文档中引用的那样,工作流程将需要超级用户权限。明显地。这不是最佳实践。此外,它可能会导致远程客户端出现连接问题。

假设 Nginx 以nginx用户身份运行,运行此命令为其授予权限。

usermod -aG sudo nginx
Run Code Online (Sandbox Code Playgroud)

代理协议

该解决方案要求上游目的地(例如后端应用程序)接受PROXY协议。

stream {
    server {
        listen         3333;
        proxy_pass     127.0.0.1:2222;
        proxy_protocol on;
    }
}
Run Code Online (Sandbox Code Playgroud)

上述解决方案假设 Nginx 服务器是网络的入口点。如果有边缘设备(例如负载均衡器),则很可能正在更改源 IP。在这种情况下,您需要在边缘设备上启用代理协议proxy_protocol并在server块中启用侦听器。我还没有测试过,但类似的东西应该有效。

stream {
    server {
        listen            3333 proxy_protocol;
        proxy_pass        127.0.0.1:2222;
        proxy_protocol    on;
        set_real_ip_from  $proxy_protocol_addr;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你好,我尝试过这个,但这是不允许的。我收到错误: nginx: [emerg] "set_real_ip_from" 指令在 /etc/nginx/nginx.conf 中不允许 (2认同)

f4t*_*0ny 6

我的设置

  1. Nginx 流模块作为 ssh 和 https 的 Tcp 代理
  2. Nginx http 模块来提供我的内容

我的要求:在 access.log 中拥有真实的客户端 IP(而不是来自流模块的 127.0.0.1)并且也用于地理封锁

我的解决方案

  1. 激活 proxy_protocol (在请求中添加附加信息)
  2. 在http监听指令中添加“proxy_procotol”(供http服务器接受)
  3. 在流模块和 ssh 之间添加额外的代理以删除 proxy_protocol 以便 ssh 能够读取
  4. 在 access.log 中将“$remote_addr”替换为“$proxy_protocol_addr”

对于地理封锁,您还必须使用 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;
    ... 
    }
}
Run Code Online (Sandbox Code Playgroud)