Dynamic proxy_pass with map and regexp
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:
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.
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! :)
Related videos on Youtube
Thijs Koerselman
Updated on September 19, 2022Comments
-
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 over 8 yearsAny 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.