3

I'm having an issue where I need to make the proxy_pass a variable, but when I make it a variable, it fails to resolve correctly on the backend server

nginx -v
nginx version: nginx/1.6.2

This is the working one:

  server {
    listen 443 ssl;
    ssl on;
    server_name api.hostname.com;

    include ssl_params;

    location = /v1 {
      return 302 /v1/;
    }

    location /v1/ {
      proxy_pass        http://internal-api.hostname.com.us-east-1.elb.amazonaws.com/;
      proxy_set_header  Host            $host;
      proxy_set_header        X-Real-IP       $remote_addr;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    }

  }

This is a broken one

  server {
    listen 443 ssl;
    ssl on;
    server_name api.hostname.com;

    include ssl_params;

    location = /v1 {
      return 302 /v1/;
    }

    location /v1/ {
      resolver 10.0.0.2;
      set $backend "http://internal-api.hostname.com.us-east-1.elb.amazonaws.com/";
      proxy_pass        $backend;
      proxy_set_header  Host            $host;
      proxy_set_header        X-Real-IP       $remote_addr;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    }

  }

The backend results for https://api.hostname.com/v1/profile on the working one is:

<-- GET /profile
--> GET /profile 200 16ms 349b

But on the broken one

<-- GET /
--> GET / 401 1ms 12b

I've tried with:

set $backend "internal-api.hostname.com.us-east-1.elb.amazonaws.com";
proxy_pass http://$backend/

set $backend "internal-api.hostname.com.us-east-1.elb.amazonaws.com/";
proxy_pass http://$backend/

Any time I'm using variables in the proxy_pass, it forwards everything to / (root) on the backend, definitely not what I was intending.

Clown Man
  • 385
  • 1
  • 3
  • 12
  • *I need to make the proxy_pass a variable* ... I am looking into this but I'm also curious why it needs to be a variable. Is that so you don't get in a situation where the back-end's IP address changes but nginx has already cached the backend lookup, and doesn't try to resolve it again as needed? – Michael - sqlbot Aug 15 '15 at 01:51
  • I suspect using a variable breaks the otherwise automatic preservation of the uri, so perhaps inside the location block, `rewrite ^/v1(/.*)$ $1;` and then `proxy_pass $backend$uri;` might be closer to what you need (with no trailing slash stored in `$backend`). – Michael - sqlbot Aug 15 '15 at 02:11
  • The reason for using a variable is so that when the ip changes on the aws backend, I won't have an outage lasting a few hours realizing that a restart of the Web server was needed. I'm trying to remove the need of using regex on every call. But that may be the way to go. I'll try that upstream one first, then I'll try your suggestion. – Clown Man Aug 16 '15 at 07:40
  • @ClownMan did you manage to figure this out? I'm having the same problem where I need the resolver and want to strip a subpath from the url. – Niels Krijger Mar 01 '18 at 15:23
  • @NielsKrijger I haven't figured it out, I have since just had to put in checks if my backend has changed IPs, and to "restart" nginx, because a reload will not refresh the backend's resolved IP. – Clown Man Mar 02 '18 at 18:54
  • This didn't resolve my issue, because there was always a risk of backend going down, so I ended up just using the direct backend IPs of my nodejs servers, not at all highly available, or dynamic. But the business requirements worked out. – Clown Man Mar 02 '18 at 19:03

2 Answers2

3

I have exactly the same problem (need variable because on AWS the internal IP change). After two days of test/investigation, I think have found a working configuration (with no / in variable or proxy_pass but with a "rewrite break" for remove the unwanted path on backend request):

resolver 10.0.0.2;
set $backend "http://internal-api.hostname.com.us-east-1.elb.amazonaws.com";
location /v1/ {
      proxy_pass        $backend;
      proxy_set_header  Host            $host;
      proxy_set_header        X-Real-IP       $remote_addr;
      proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
      rewrite ^/v1/(.*) /$1 break;
}
PiR
  • 175
  • 9
0

Use the upstream module to set the variable:

http {

    ...

    upstream backend {
        server internal-api.hostname.com.us-east-1.elb.amazonaws.com;
    }

    ...

    server {

        ...

        location /v1/ {
            proxy_pass http://backend;

            ...

        }
    }
}

The upstream module is a standard module and would have had to have been specifically disabled for it not to be in your installation of Nginx.

Dayo
  • 12,413
  • 5
  • 52
  • 67
  • I'll give this a shot when I wake up, I never thought of using the upstream module, since I I previously used it when I didn't have access to the elb, it's been a while. – Clown Man Aug 16 '15 at 07:41
  • 2
    Did you mean for me to use the resolver with the upstream module? Because your answer wont work per documentation: I will need to test this hopefully sometime this week: – Clown Man Aug 17 '15 at 23:03