Nginx for proxying to AWS Load Balancer Dynamic IP Resolver + URL Parameters

August 10, 2022 Dev Ops

The story goes that we have a web-app running on AWS Elastic Container Service in a Docker container and is served with nginx. It is exposed to the internet via a public-facing load balancer.

We also have an API service in another container that the web-app will have to access to perform some tasks. It is resolved in an internal/private load balancer. Now if we were to call the API directly with the internal load balancer API URI, we will get a CORS issue as it’s trying to access something on a different domain.

Creating a proxy_pass

To fix this, we create a rule in the nginx.conf of the web-app to proxy a path of the nginx server of the web-app to point to the internal load balancer API URI which will be used by the app to access the API.

location /some-service-api/ {
  proxy_pass http://internal-load-balancer-url/some-service-api/;
}

Stale IP

This looks fine and dandy, however an issue will arise when the container has been running for a certain period of time. The IP address that is resolved when we pass the URI to proxy_pass will become stale as the IP address of the load balancer is dynamic in AWS. Therefore the location will be pointing to a stale IP that is no longer in use.

Resolving dynamic IP address of load balancer URI

To fix the above issue, we add a resolver IP address which will be the IP in your internal network VPC. Then we create a variable and set it to the URI and pass that variable into proxy_pass. This will make the IP address be dynamically resolved so that the location will always be pointing to the correct IP address of your internal load balancer.

location /some-service-api/ {
  resolver 10.1.0.2;
  
  set $some_service_uri_var http://internal-load-balancer-url/some-service-api/;

  proxy_pass $some_service_uri_var;
}

Great, that works, but now if your API has endpoint paths, you may start getting 404s.

The final fix (I promise) – getting path parameters

To fix, we need to grab the path parameters by first using a nginx global variable: $request_uri which contains the path of the request (e.g. /some-service-api/users?id=2). We then grab everything after the first trailing slash and put it in a $path_remainder variable. Then when we set the internal load balancer API URI variable, we append the $path_remainder then pass the final variable into proxy_pass.

    location /some-service-api/ {
      resolver 10.1.0.2;

      if ($request_uri ~* "/some-service-api/(.*$)") {
          set  $path_remainder  $1;
      }

      set $some_service_uri_var http://internal-load-balancer-url/some-service-api/$path_remainder;

      proxy_pass $some_service_uri_var;
    }

Okay, we’re done. Hope you find this useful and that Google will point more people like you here who are having this issue as I had to look deep and hard and go through many sources to combine the knowledge to put this solution together. Also, forgive my lack of in-depth knowledge in nginx as I’m still a bit of a n00b ;). Cheers.

Leave a Reply

Your email address will not be published.