Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic proxy_pass with map and regexp

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?

like image 895
Thijs Koerselman Avatar asked Aug 26 '13 20:08

Thijs Koerselman


1 Answers

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
like image 100
Thijs Koerselman Avatar answered Sep 19 '22 12:09

Thijs Koerselman