Dynamic proxy_pass with map and regexp

12,272

Solution 1

I eventually went back to the first approach, because it's not convenient to add a query parameter to a url for this. It makes the client logic unnecessary complex.

I found the solution to my first approach. The regex in the location statement was wrong. You need to capture the regex in variable names by using ? like this:

location ~ ^/fwd/(?<fwd_alias>\w+)/(?<fwd_path>.*)$

Then $fwd_alias will contain the alias like foo or bar. $fwd_path with contain the whole path after that.

To pass on the full path including optional query parameters you specify the proxy_pass as:

proxy_pass http://$repo_url$fwd_path$is_args$args;

That's it!

So now, including the mapping in the first example, and adding the resolver, it comes down to:

location ~ ^/fwd/(?<fwd_alias>\w+)/(?<fwd_path>.*)$ {
  resolver 8.8.8.8;
  add_header Access-Control-Allow-Origin "*";
  proxy_pass http://$repo_url$fwd_path$is_args$args;
  proxy_redirect off;
  access_log on;
}

And a request with the following path:

http://localhost:8080/fwd/foo/something/else?with=query 

maps to:

http://foo.domain.nl/something/else?with=query

Solution 2

I was on the right track.

If you want to use proxy_pass with a variable argument you need to do two things:

  1. Add a resolver statement to resolve the hostnames. As I understand it, on startup nginx looks up all domain names in the config and maps them to IPs. Since we're using a variable hostname nginx can't look it up when loading the config and we need to specify the DNS resolver.

  2. When using a variable in proxy_pass you need to add http:// to it. Not sure why that is.

So this results in:

location /fwd/ {
  resolver 8.8.8.8;
  add_header X-FwdHost $repo_forward;
  add_header Access-Control-Allow-Origin "*";
  proxy_pass http://$repo_forward;
  proxy_redirect off;
  access_log on;
}

And it works! :)

Share:
12,272

Related videos on Youtube

Thijs Koerselman
Author by

Thijs Koerselman

Updated on September 19, 2022

Comments

  • Thijs Koerselman
    Thijs Koerselman over 1 year

    I'm trying to get the following pattern to work. I need to specify a dynamic path in my client side code to be able to switch to a few predefined hosts. I map these hosts by appending their alias to a /fwd/ url. The alias is mapped to the real server in nginx like this:

    map $uri $repoUrl {
        default             invalid;
        ~^/fwd/foo/.*        http://foo.domain.nl/;
        ~^/fwd/bar/.*        http://bar.domain.nl/;
      }
    

    Then in the server config part I catch any url starting with fwd and apply the mapped alias value. The remaining part of the url, after the alias should be appended to the url as well.

    location /fwd/(\w+)/(.*)$ {
      add_header X-FwdHost "$repoUrl$2";
      add_header Access-Control-Allow-Origin "*";
      proxy_pass         "$repoUrl$2";
      proxy_redirect off;
      access_log on;
    }
    

    If I test this with:

    curl -i http://localhost:8080/fwd/foo/something/else
    

    I get:

    X-FwdHost: http://foo.domain.nl/
    

    But when test the results from the regexp I get:

     $1: foo
     $2: something/else
    

    So overall it seems to be working. The regex appears to be ok, but I can't get it to concatenate into one string? Any ideas or is there an easier/better way to accomplish the same?

    [EDIT]

    I found a possibly much easier way to do this, by using a query parameter named forward. First map the query parameter to a the right host:

    map $arg_forward $repo_forward {
    default           http://invalid_repo_forward/;
    
    foo              http://foo.domain.nl/;
    bar              http://bar.domain.nl/;
    

    }

    Then use the parameter in the path to be forwarded:

    location /fwd/ {
      add_header X-FwdHost $repo_forward;
      add_header Access-Control-Allow-Origin "*";
      proxy_pass         $repo_forward;
      proxy_redirect off;
      access_log on;
    }
    

    I would expect and url like:

    http://localhost:8080/fwd/?forward=foo
    

    To result in:

    http://foo.domain.nl/
    

    ...but still this doesn't work. I get a 404 returned. What am I missing?

  • Guy
    Guy over 8 years
    Any chance you can post a "full" copy of the solution please. I'm following this (as far as I can) but still getting 404's. Alstublieft.