首页 > 解决方案 > 使用 NGINX 将代理链生成的多个 IP 限制为仅客户端 IP?

问题描述

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

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

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

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

1.2.3.4, 127.0.0.1

变得公正

1.2.3.4

?

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

谢谢!

标签: nginxipreverse-proxyhaproxyvarnish

解决方案


解决此问题的最佳方法是使用PROXY 协议在 HAProxy 和 Varnish 之间进行连接。

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

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

对于 HAProxy,send-proxy-v2只需在后端定义中添加一个额外属性即可。

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

HAProxy 示例配置

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

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地址是, Nginx中1.2.3.4的header就是。X-Forwarded-ForX-Forwarded-For: 1.2.3.4

额外奖励:TLS 信息。

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

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

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 协议,您仍然可以提取X-Forwarded-ForVCL 代码中标头的第一个值。

这是在 VCL 中执行此操作的方法:

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

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


推荐阅读