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



我正在尝试将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_bindproxy_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;
    }
}

我的设置

  1. nginx流模块作为SSH和HTTPS的TCP代理
  2. nginx http模块服务我的内容

我的要求:在accept.log中具有真实的客户端IP(而不是流模块中的127.0.0.1),也用于GeoDblocking

我的解决方案

  1. 激活proxy_protocol(在请求中添加其他信息)
  2. 添加" Proxy_procotol"在http侦听指令中(供http服务器接受)
  3. 在流模块和SSH之间添加额外的代理,以删除能够读取
  4. 的proxy_protocol
  5. 替换" $ 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;
    }
}

最新更新