Disabling URL decoding in nginx proxy
Solution 1:
Quoting Valentin V. Bartenev (who should get the full credit for this answer):
A quote from documentation:
If proxy_pass is specified with URI, when passing a request to the server, part of a normalized request URI matching the location is replaced by a URI specified in the directive
If
proxy_pass
is specified without URI, a request URI is passed to the server in the same form as sent by a client when processing an original requestThe correct configuration in your case would be:
location /foo { proxy_pass http://localhost:8080; }
Solution 2:
Note that URL decoding, commonly known as $uri
"normalisation" within the documentation of nginx, happens before the backend IFF:
either any URI is specified within
proxy_pass
itself, even if just the trailing slash all by itself,or, URI is changed during the processing, e.g., through
rewrite
.
Both conditions are explicitly documented at http://nginx.org/r/proxy_pass (emphasis mine):
If the
proxy_pass
directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directiveIf
proxy_pass
is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI
The solution is to either omit the URI as in OPs case, or, indeed, use a clever rewrite
rule:
# map `/foo` to `/foo`:
location /foo {
proxy_pass http://localhost:8080; # no URI -- not even just a slash
}
# map `/foo` to `/bar`:
location /foo {
rewrite ^ $request_uri; # get original URI
rewrite ^/foo(/.*) /bar$1 break; # drop /foo, put /bar
return 400; # if the second rewrite won't match
proxy_pass http://localhost:8080$uri;
}
You can see it live in a related Stack Overflow answer, including control group.