'Nginx proxy_pass with $remote_addr

I'm trying to include $remote_addr or $http_remote_addr on my proxy_pass without success.

The rewrite rule works

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

The proxy_pass without the $remote_addr works, but freegeoip does not read the 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;
}

Then, I'm adding the ip to the end of the request, like this:

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

but nginx report this error: no resolver defined to resolve freegeoip.net



Solution 1:[1]

If the proxy_pass statement has no variables in it, then it will use the "gethostbyaddr" system call during start-up or reload and will cache that value permanently.

if there are any variables, such as using either of the following:

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

Then nginx will use a built-in resolver, and the "resolver" directive must be present. "resolver" is probably a misnomer; think of it as "what DNS server will the built-in resolver use". Since nginx 1.1.9 the built-in resolver will honour DNS TTL values. Before then it used a fixed value of 5 minutes.

Solution 2:[2]

It seems a bit strange that nginx is failing to resolve the domain name at runtime rather than at configuration time (since the domain name is hard coded). Adding a resolver declaration to the location block usually fixes dns issues experienced at runtime. So your location block might look like:

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

This solution is based on an article I read a while back - Proxy pass and resolver. Would be worth a read.

Solution 3:[3]

If anyone is stll experiencing trouble, for me it helped to move the proxy_pass host to a seperate upstream, so I come up with something like this

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/;
  }
}

Solution 4:[4]

You could also mention your nginx server port in the proxy_pass uri. This solved the issue for me.

Solution 5:[5]

Another way is that you can provide your host ip address and port number instead of host URL in proxy_pass like below:

Your Code: proxy_pass http://freegeoip.net/json/;

Updated Code proxy_pass http://10.45.45.10:2290/json/;

Solution 6:[6]

Try to use dig / nslookup to make sure this is still nginx issue. In my case the issue was that one of dns server between my nginx and root dns was not respecting TTL values that are as small as 1 second.

Nginx does not re-resolve DNS names in Docker

Solution 7:[7]

So you want this to work:

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

but as pointed out by Chris Cogdon, it fails because at run-time, nginx does not have the domain name resolved, and so proxy_pass requires a resolver (see also, proxy_pass docs).

Something that seems to work (though may be a hack!) is to do something that triggers nginx to resolve the domain name at start-up and cache this.

So, change the config to include a location (for the same host) without any variables (as well as your location with variables):

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;
}

The host will now be resolved at start-up (and its cached value will be used in the second location at run-time). You can verify this start-up resolution behavior by changing hostname (freegeoip.net) to something that doesn't exist, and when you run nginx -t or nginx -s reload you'll have an emergency error ([emerg] host not found in upstream). And of course you can verify that the cached value is used at run-time by leaving out any resovler, hitting your location block, and observing no errors in the logs.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nbari
Solution 2 Rob Squires
Solution 3 AmazingTurtle
Solution 4 RijulB
Solution 5 Rohit Gaikwad
Solution 6 Piotr
Solution 7 Peter W