如何将 NGINX proxy_pass 与 $remote_addr 一起使用?

问题描述 投票:0回答:8

我试图将

$remote_addr
$http_remote_addr
包含在我的
proxy_pass
上,但没有成功。重写规则有效:

location ^~ /freegeoip/ {  
  rewrite ^ http://freegeoip.net/json/$remote_addr last;
}

没有

$remote_addr
的 proxy_pass 可以工作,但是
freegeoip
不会读取
x-Real-IP
:

location ^~ /freegeoip/ {
  proxy_pass http://freegeoip.net/json/;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $host;
}

然后,我将

ip
添加到请求末尾:

location ^~ /freegeoip/ {
  proxy_pass http://freegeoip.net/json/$remote_addr;
}

但是

nginx
报告此错误:

no resolver defined to resolve freegeoip.net
nginx proxypass
8个回答
204
投票

如果

proxy_pass
语句中没有变量,那么它将在启动或重新加载期间使用“gethostbyaddr”系统调用,并永久缓存该值。

如果有任何变量,例如使用以下任一:

set $originaddr http://origin.example.com;
proxy_pass $originaddr;
# or even
proxy_pass http://origin.example.com$request_uri;

然后 nginx 将使用内置解析器,并且“解析器”指令必须存在。 “解析器”可能是用词不当;将其视为“内置解析器将使用哪个 DNS 服务器”。从 nginx 1.1.9 开始,内置解析器将遵循 DNS TTL 值。在此之前它使用的是 5 分钟的固定值。


95
投票

nginx 在运行时而不是在配置时解析域名失败(因为域名是硬编码的),这似乎有点奇怪。向位置块添加

resolver
声明通常可以修复运行时遇到的 dns 问题。所以你的位置块可能看起来像:

location ^~ /freegeoip/ {
  #use google as dns
  resolver 8.8.8.8;
  proxy_pass http://freegeoip.net/json/$remote_addr;
}

这个解决方案基于我不久前读过的一篇文章 - 代理传递和解析器。值得一读。


17
投票

如果有人仍然遇到麻烦,对我来说,将 proxy_pass 主机移动到单独的上游有帮助,所以我想出了这样的方法

upstream backend-server { server backend.service.consul; } server { listen 80; server_name frontend.test.me; location ~/api(.*)$ { proxy_pass http://backend-server$1; } location / { # this works mystically! backend doesn't... proxy_pass http://frontend.service.consul/; } }
    

2
投票
另一种方法是您可以提供您的主机

ip

 地址和 
port
 号码,而不是 
URL
 中的主机 
proxy_pass
,如下所示:

您的代码: proxy_pass http://freegeoip.net/json/;


更新代码 proxy_pass http://10.45.45.10:2290/json/;


    


1
投票
所以你希望这个工作:

location ^~ /freegeoip/ { proxy_pass http://freegeoip.net/json/$remote_addr; }
但正如 Chris Cogdon 

指出,它会失败,因为在运行时,nginx 没有解析域名,因此 proxy_pass

 需要解析器(另请参阅
proxy_pass 文档)。

似乎有效的方法(尽管可能是黑客!)是触发 nginx 在启动时解析域名并缓存它。

因此,更改配置以包含不带任何变量的位置(针对同一主机)(以及您的位置

变量):

location = /freegeoip/this-location-is-just-a-hack { # A dummy location. Use any path, but keep the hostname. proxy_pass http://freegeoip.net/this-path-need-not-exist; } location ^~ /freegeoip/ { proxy_pass http://freegeoip.net/json/$remote_addr; }
主机现在将在启动时解析(其缓存值将在运行时在第二个位置使用)。您可以通过将主机名 (

freegeoip.net

) 更改为不存在的名称来验证此启动解析行为,并且当您运行 
nginx -t
nginx -s reload
 时,您将遇到紧急错误 (
[emerg] host not found in upstream
)。当然,您可以通过省略任何 
resolver
、点击 
location
 块并观察日志中没有错误来验证缓存的值是否在运行时使用。


0
投票
您还可以在

server port

 中提及您的 nginx 
proxy_pass uri
。这为我解决了这个问题。


0
投票
尝试使用 dig / nslookup 来确保这仍然是 nginx 问题。 就我而言,问题是我的 nginx 和根 dns 之间的其中一台 dns 服务器不遵守小至 1 秒的 TTL 值。

Nginx 不会在 Docker 中重新解析 DNS 名称


0
投票
对于处理此问题的任何人,重要的是在 proxy_pass 之后设置代理标头,然后这应该可以解决问题:

proxy_pass http://backend-server; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Host $host;
    
© www.soinside.com 2019 - 2024. All rights reserved.