我在负载均衡器后面有一个 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;
这是虚拟主机:
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;
}
}
但我从容器中得到的是:
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"
}
值得注意的是,X-Real-IP、X-Fowarded-For 似乎未设置,remote_addr 也未设置。直接从 nginx 提供的文件已正确设置 x-forwarded-for,因此 LB 正在发送正确的标头。
我是否遗漏了某步?
答案1
我认为问题出在你的真实 IP 配置上。
set_real_ip_from {{LB IP}};
real_ip_header X-Real-IP;
real_ip_recursive on;
当 real_ip_header 应该(在您的情况下)设置为 X-Forwarded-For 时。我假设您的 LB 的 X-Forwarded-For 标头如下所示:
X-Forwarded-For: {{Original client ip}}, {{LB ip}}
因此,当您将 real_ip_header(用于替换客户端 ip 的标头)设置为 X-Forwarded-For 时,它将与原始客户端 ip 匹配。原始客户端现在应该位于变量 $realip_remote_addr 下,您可以将其寻址到 proxy_set_header X-Forwarded-For :
proxy_set_header X-Forwarded-For $realip_remote_addr
如果我有帮到您的话请告诉我!
答案2
这是覆盖 X-Forwarded-For 标头的语句:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
假设您想要保留该标头中的原始客户端 IP,则应该写入:
proxy_set_header X-Forwarded-For $remote_addr;
答案3
从您的描述来看,您的问题与 nginx 没有直接关系,而是与 apache 有关。
根据您的配置,您的流量可能看起来像这样:
outside -> nginx -> apache -> php (running as fpm)
或者
outside -> nginx -> apache + php module
您应该查看 apache 配置,以确保 apache在将请求传递给 PHP 时不会丢弃x-forwarded-for
和标头。x-real-ip
如果您的流量与第一个例子一致,那么您会让 apache 将请求代理到 php,如果 nginx 和 apache 不是“同步”,这可能会导致更多问题。
如果您单独使用 nginx 处理 php 代理,则只需将以下内容添加到您的 phplocation
配置中:
location ~ \.php$ {
#...other rules
fastcgi_param REMOTE_ADDR $http_x_real_ip;
#...other rules
}
这样,PHPREMOTE_ADDR
就会被正确设置。
关于您的 nginx 配置,如果您的 nginx{{LB IP}}
是静态的,您可以直接在配置中设置它。
/etc/nginx/conf.d/real_ip.conf
set_real_ip_from {{LB IP}};
real_ip_recursive on;
你不需要real_ip_header X-Real-IP;
在配置文件中添加。这将覆盖该set_real_ip_from
指令。
请记住,您需要在 nginx 中启用 real_ip 模块才能使其正常工作。
答案4
我最终以一种可行的方式解决了这个问题,但实际上并没有解决根本问题。据我所知,上游 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;
conf.d 中的内容如下:
/etc/nginx/conf.d/real_ip.conf
set_real_ip_from {{ LB_IP }};
real_ip_header proxy_protocol;
改编自:
https://www.x33u.org/docs/kubernetes-stuff/hetzner-loadbalancer-setup/
现在一切正常。