Search code examples
nginxherokugeo

Use `geo` directive in NGINX on Heroku


Duplicated from the GitHub issue:

Please see the relevant areas of nginx.conf.erb below. I've tested something like this locally on my machine with nginx and 127.0.0.1 so I believe I'm using the directives properly. However when I add a CIDR group that contains my IP address and put this on my Heroku dyno I can still get through to my site.

Any ideas why this isn't being picked up properly or something I'm missing? Does this feature not work on Heroku?

http {
  geo $test_group {
    default 0;
    1.2.3.4/22 1; # this includes my local IP address
  }
  server {
    location / {
      if ($test_group) {
        return 418 "short AND stout";
      }
    }
  }
}

My best guess is that theres a decent amount of IP forwarding going on behind the scenes that is screwing around with NGINX. For example if I do curl -i -H "X-Forwarded-For: 1.2.3.4" "https://my-cool-app.herokuapp.com" I still see my real IP and it does not get picked up by the NGINX rule.


Solution

  • tl;dr

    It is related to IP forwarding so the proxy directive must be used. Simply add

    proxy 10.0.0.0/8;
    

    inside geo and you're good to go.

    Whaaa!? How and Why

    Heroku forwards all internal requests on private IP addresses in the 10.x.x.x range. This is probably obvious and immediately makes sense to folks more familiar with networking and/or NGINX. I was able to figure it out by returning $remote_addr as a header and noticed that it was not my public IP address. While the docs leave a lot to be desired for the novice, the proxy description clued me in that if I proxied the CIDR range for private IPs (10.0.0.0/8), the X-Forwarded-For address would be used instead.