【问题标题】:Use NGINX to limit multiple IPs generated by proxy chain to just client IP?使用 NGINX 将代理链生成的多个 IP 限制为仅客户端 IP?
【发布时间】:2021-11-11 01:39:36
【问题描述】:

我正在运行 NGINX(版本 1.17.3)作为系统设置的最后一步,如下所示:

客户端 -> HAProxy(SSL 终止)-> Varnish -> NGINX

它运行良好,但如果我查看 NGINX 日志,我会看到 both 客户端 IP 和 127.0.0.1,以逗号分隔。排在第二位的 127.0.0.1 是 Varnish。

有没有办法告诉 NGINX 忽略第二个地址,这样:

1.2.3.4, 127.0.0.1

变成了

1.2.3.4

?

我的问题不是第二个 IP 出现在日志中——我本身并不关心这个——而是它将它传递给在 NGINX 后面运行的某些软件,如果他们期望的话,会弄乱它们单个 IP。

谢谢!

【问题讨论】:

    标签: nginx ip reverse-proxy haproxy varnish


    【解决方案1】:

    解决此问题的最佳方法是使用 PROXY protocol 连接 HAProxy 和 Varnish。

    此协议将客户端连接信息存储在 TCP 包中,并沿各个跃点传输此信息。

    要求您的代理服务器支持此协议。幸运的是 Varnish 和 HAProxy 可以。

    对于 HAProxy,只需将 send-proxy-v2 作为额外属性添加到后端定义。

    对于 Varnish,您需要确保打开支持 PROXY 的侦听端口。

    HAProxy 示例配置

    这是一个支持 send-proxy-v 的过于简化的 HAProxy 示例配置:

    defaults
        mode    http
    
    frontend http-in-proxy
        bind *:80
        default_backend servers-proxy
    
    backend servers-proxy
        server server1-proxy varnish.example.com:8443 send-proxy-v2
    
    

    为了简单起见,我没有终止 TLS,但我只是通过 PROXY 协议向 Varnish 发送纯 HTTP。

    清漆代理示例

    下面是一个使用 PROXY 支持打开的额外侦听端口的示例:

    varnishd -a :80 -a :8443,PROXY -f /etc/varnish/default.vcl -s malloc,2g
    

    如您所见,常规 HTTP 端口是 80,而 PROXY 端口是 8443。 HAProxy 配置也引用了该端口。

    那个 X-Forwarded-For 标头呢?

    成功设置 PROXY 协议后,您现在可以受益于准确的 X-Forwarded-For 标头。

    Varnish 将使用它从 PROXY 协议获得的值,不再需要链接 X-Forwarded-For 值。

    如果连接HAProxy的客户端IP地址为1.2.3.4,则Nginx中的X-Forwarded-For标头为X-Forwarded-For: 1.2.3.4

    额外奖励:TLS 信息。

    PROXY 协议不仅存储原始客户端 IP 地址,还存储有关请求协议的信息。

    以下是proxy VMOD 的示例,用于确定原始连接是通过 HTTP 还是 HTTPS:

    vcl 4.1;
    
    import proxy;
    
    sub vcl_recv {
        if (proxy.is_ssl()) {
            set req.http.X-Forwarded-Proto = "https";
        } else {
            set req.http.X-Forwarded-Proto = "http";
        }
    }
    
    sub vcl_hash {
        hash_data(req.http.X-Forwarded-Proto);
    }
    

    注意:此示例还将通过将 X-Forwarded-Proto 标头的值添加到缓存对象的哈希值来创建基于协议的缓存变体。

    这是另一个使用 PROXY 协议提取更多 TLS 信息的示例:

    vcl 4.1;
    import proxy;
    
    sub vcl_deliver {
        set resp.http.alpn = proxy.alpn();
        set resp.http.authority = proxy.authority();
        set resp.http.ssl = proxy.is_ssl();
        set resp.http.ssl-version = proxy.ssl_version();
        set resp.http.ssl-cipher = proxy.ssl_cipher();
        set resp.http.client-has-cert-sess = proxy.client_has_cert_sess();
        set resp.http.client-has-cert-conn = proxy.client_has_cert_conn();   
    }
    

    后备计划

    我希望我让您相信 PROXY 协议非常强大。但是,如果您不打算使用 PROXY 协议,您仍然可以在 VCL 代码中提取 X-Forwarded-For 标头的第一个值。

    您可以在 VCL 中执行此操作:

    sub vcl_recv {
        set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For,"^([^,]+)(,[^,]+)*","\1");
    }
    

    然后,此值将以现成的格式呈现给您的 Nginx 服务器。

    【讨论】:

    • 感谢您的回复,非常感谢。我尝试了第一个选项,但它仍然给了我两个 IP。不过,这一次,不是一个是正确的 IP,另一个是 127.0.0.1,而是两个都是正确的 IP,用逗号分隔。知道为什么吗?备份计划第一次奏效。
    • @Charles 也许是因为您在 HAProxy 配置中的某处有一个 option forwarfor。尝试删除它并再次测试。
    • 谢谢。就是这样。我删除了它,它起作用了。然而,这又提出了另一个问题。我在 HAProxy 中将 Varnish 作为 primary 服务器,但作为 backup,HAProxy 会将访问者直接发送到 NGINX 服务器。通过删除option forwardfor,当 HAProxy 将流量发送到备份(即直接发送到 NGINX)时,我现在不会获得任何通过的 IP 地址。有什么方法可以让 HAProxy 做它对 option forwardfor 变量所做的事情,但仅限于服务器级别?
    • @Charles 也许在非 Varnish 后端设置 X-Forwarded-For 标头,而不是全局设置。
    猜你喜欢
    • 1970-01-01
    • 2021-09-01
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    相关资源
    最近更新 更多