如何让 nginx 在代理时不覆盖 x-forwarded-for?

Aqu*_*ion 6 nginx reverse-proxy nginx-reverse-proxy

我在负载均衡器后面有一个 nginx 服务器,nginx 服务器将请求传递到各种服务,但在本例中是一个运行 apache 的 docker 容器。负载均衡器正确设置了 X-Forwarded-For,但当它到达 docker 容器时,X-Forwarded-For 已设置为 LB IP。

我在 nginx 配置中有这个:

/etc/nginx/conf.d/real_ip.conf
set_real_ip_from {{LB IP}};
real_ip_header X-Real-IP;
real_ip_recursive on;
Run Code Online (Sandbox Code Playgroud)

这是虚拟主机:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name *.domain domain;
    include /etc/nginx/snippets/domain_ssl.conf;

  add_header X-Nginx-Debug "hi";

  proxy_pass_request_headers on;

  location    / {
    proxy_pass_request_headers on;
    proxy_pass  http://container-php;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Remote-Addr $remote_addr;
    proxy_set_header X-Real-IP $http_x_real_ip;
    proxy_set_header X-Header-Test "Hello World - $http_x_forwarded_for";
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}
Run Code Online (Sandbox Code Playgroud)

但我从容器中得到的是:

array(19) {
  ["Connection"]=>
  string(7) "upgrade"
  ["Host"]=>
  string(19) "domain"
  ["X-Forwarded-For"]=>
  string(12) "{{LB IP}}"
  ["X-Header-Test"]=>
  string(13) "Hello World -"
  ["X-Forwarded-Proto"]=>
  string(5) "https"
  ["cache-control"]=>
  string(9) "max-age=0"
  ["sec-ch-ua"]=>
  string(64) "" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97""
  ["sec-ch-ua-mobile"]=>
  string(2) "?0"
  ["sec-ch-ua-platform"]=>
  string(9) ""Windows""
  ["upgrade-insecure-requests"]=>
  string(1) "1"
  ["user-agent"]=>
  string(114) "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"
  ["accept"]=>
  string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
  ["sec-fetch-site"]=>
  string(4) "none"
  ["sec-fetch-mode"]=>
  string(8) "navigate"
  ["sec-fetch-user"]=>
  string(2) "?1"
  ["sec-fetch-dest"]=>
  string(8) "document"
  ["accept-encoding"]=>
  string(17) "gzip, deflate, br"
  ["accept-language"]=>
  string(26) "en-GB,en-US;q=0.9,en;q=0.8"
}
Run Code Online (Sandbox Code Playgroud)

值得注意的是 X-Real-IP、X-Fowarded-For 似乎没有设置,remote_addr 也没有设置。直接从 nginx 提供的文件已正确设置 x-forwarded-for,因此 LB 正在发送正确的标头。

我是不是漏掉了一步?

Aqu*_*ion 0

我最终以一种可行的方式解决了这个问题,但实际上并没有解决根本问题。据我所知,上游 LB 将“X-Forwarded-For”设置为远程地址,而 nginx 神奇地尝试为反向代理正确设置该设置总是出错,并将其设置为 LB 地址或空地址细绳。

相反,我将 LB->Server 位从 HTTP 切换到 PROXY 协议,在 /etc/nginx/proxy_params 中设置以下内容:

proxy_set_header X-Real-IP       $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
Run Code Online (Sandbox Code Playgroud)

在conf.d中:

 /etc/nginx/conf.d/real_ip.conf
set_real_ip_from {{ LB_IP }};
real_ip_header proxy_protocol;
Run Code Online (Sandbox Code Playgroud)

改编自此:

https://www.x33u.org/docs/kubernetes-stuff/hetzner-loadbalancer-setup/

现在一切正常了。