Removing location without removing the rest of the path - nginx

According to many old posts here and in other places on the internet, the following nginx configuration should proxy http://nginx-service/foo/bar to http://web.default.svc.cluster.local:8080/bar.
In other words, it should strip the /foo part in the path (the location matched) while appending the rest (/bar) when proxying it on.
That is not what I observe in practice; the full path is removed and / is proxied on.
How could I proxy this to the upstream service while keeping /bar?

You didn't add any config in your question but any of the following should work:
location /foo/ {
proxy_pass http://web.default.svc.cluster.local:8080/;
}
or
location /foo/bar {
proxy_pass http://web.default.svc.cluster.local:8080/bar;
}

Related

Replicate proxy_pass location behavior with variables

So usually when creating a nginx location it would look something like this:
location /foo/ {
proxy_pass http://example.com/;
}
With this setup, requests to /foo/bar are forwarded to http://example.com/bar which is the intended behavior.
However when trying to prevent caching of the domain name example.com or when trying to prevent nginx from crashing if the upstream host is unavailable at startup the only solution seems to be to not use the target directly in the proxy_pass directive, but to instead create a variable containing the target like this:
location /foo/ {
set $targetUri http://example.com/;
proxy_pass $targetUri;
}
But this totally changes the setup. As soon as proxy_pass contains a variable, it no longer appends anything to the target uri, as the nginx docs describe:
When variables are used in proxy_pass [...]. In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.
So requests to /foo/bar are simply forwarded to http://example.com/.
When bringing $request_uri into the mix, more than what we want is appended:
location /foo/ {
set $targetUri http://example.com$request_uri;
proxy_pass $targetUri;
}
Requests to /foo/bar are now forwarded to http://example.com/foo/bar.
The only workaround I have found is to resort to regex patterns for the location:
location ~ ^/foo/(.*)$ {
set $targetUri http://example.com/$1$is_args$args;
proxy_pass $targetUri;
}
Is there any way to replicate the behavior of proxy_pass when using variables without having to regex-match the location? The reason I want to avoid regex is because the location path is based on a user input from which the location block is generated.
Remove the trailing / from your $targetUri variable so that proxy_pass does not have the "optional URI" part in its value. Then use rewrite...break to duplicate the original behaviour.
For example:
location /foo/ {
set $targetUri http://example.com;
rewrite ^/foo(.*)$ $1 break;
proxy_pass $targetUri;
}

Nginx pass_proxy with variables

I'm having trouble making nginx proxy an url with variable to a service within kubernetes.
Url looks like this:
http://localhost/user?username=Dave
I expect this url to take me to a subpage /user, which will read ?username=Dave and then fetch data from a database. However this takes me to the home page of the application(/ instead of /user) and does not read the variable even though url includes /user?username=Dave.
My current nginx config file looks like this:
server {
listen 0.0.0.0:80;
server_name localhost;
location / {
proxy_pass http://${FLASK_APP}:8080/;
}
location /user {
proxy_pass http://${GO_APP}:8000/;
}
}
I have read that location /user will match the url I'm passing. What is wrong with it? Or do I need to add something to proxy_pass http://${GO_APP}:8000/; or location /user?
As noted in the comments, the issue arises because you are using a variable in the proxy_pass target. As also noted in the comments, this question is related. As the answer referencing the docs states:
A special case is using variables in the proxy_pass statement: The
requested URL is not used and you are fully responsible to construct
the target URL yourself.
This means that you either need to use a static proxy_pass target, such as
// note that I added the forward slash
location /user/ {
proxy_pass http://destination:8000/;
}
Or as an alternative, I believe you can do it this way also
location /user/ {
proxy_pass http://${GO_APP}:8000/user$is_args$args;
}

With nginx proxy/rewrite can I keep the original URL in the browser's Location field?

Using nginx.conf features like proxy-pass/rewrite, can I keep the original URL in the browser's Location field?
I have several PlayFramework apps running on different ports (9001, 9002, ...) with proxy forwarding set up via nginx.conf. People browse to them as:
http://domain.name/App1/
http://domain.name/App2/
etc.
My nginx.conf entries look like this:
location /App1/ {
proxy_pass http://localhost:9001/;
rewrite ^/App1/(.*) http://domain.name:9001/$1;
}
If I ask for http://domain.name/App1/, what I see in the browser's Location field is http://domain.name:9001. What I wish I saw was http://domain.name/App1/, that is, I want the name App1 to remain in the URI, and I'd rather not expose the port number.
Let's say App1 has a link /location/ABC. When I click on it I see http://domain.name:9001/location/ABC when I wish I saw http://domain.name/App1/location/ABC.
Can I achieve this with nginx.conf?
P.S. I put http://domain.name explicitly in the rewrite rule because without it I was getting localhost in the browser, and my browser's localhost is not the same as the server's.
Rewrites issue redirects for browser.
If you just want to mount several locations from upstreams - you do not need rewrites, just use:
location /App1/ {
proxy_pass http://localhost:9001/;
}
But apps should use relative links or account for their absolute location.
For more complex url manipulation you can use break-rewrites:
location /App1/ {
rewrite ^/App1/(.*) /$1 break;
proxy_pass http://localhost:9001;
}

Avoid nginx decoding query parameters on proxy_pass (equivalent to AllowEncodedSlashes NoDecode)

I use nginx as a load balencer in front of several tomcats. In my incoming requests, I have encoded query parameters. But when the request arrives to tomcat, parameters are decoded :
incoming request to nginx:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http%3A%2F%2Fwww.google.com%2F"
incoming request to tomcat:
curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http:/www.google.com/"
I don't want my request parameters to be transformed, because in that case my tomcat throws a 405 error.
My nginx configuration is the following :
upstream tracking {
server front-01.server.com:8080;
server front-02.server.com:8080;
server front-03.server.com:8080;
server front-04.server.com:8080;
}
server {
listen 80;
server_name tracking.server.com;
access_log /var/log/nginx/tracking-access.log;
error_log /var/log/nginx/tracking-error.log;
location / {
proxy_pass http://tracking/webapp;
}
}
In my current apache load balancer configuration, I have the AllowEncodedSlashes directive that preserves my encoded parameters:
AllowEncodedSlashes NoDecode
I need to move from apache to nginx.
My question is quite the opposite from this question : Avoid nginx escaping query parameters on proxy_pass
I finally found the solution: I need to pass $request_uri parameter :
location / {
proxy_pass http://tracking/webapp$request_uri;
}
That way, characters that were encoded in the original request will not be decoded, i.e. will be passed as-is to the proxied server.
Jean's answer is good, but it does not work with sublocations. In that case, the more generic answer is:
location /path/ {
if ($request_uri ~* "/path/(.*)") {
proxy_pass http://tracking/webapp/$1;
}
}
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 directive
If 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 depends on whether or not you need to change the URL between the front-end and the backend.
If no URI change is required:
# map `/foo` to `/foo`:
location /foo {
proxy_pass http://localhost:8080; # no URI -- not even just a slash
}
Otherwise, if you do need to swap or map /api of the front-end with /app on the backend, then you can get the original URI from the $request_uri variable, and the use the rewrite directives over the $uri variable similar to a DFA (BTW, if you want more rewrite DFA action, take a look at mdoc.su). Note that the return 400 part is needed in case someone tries to get around your second rewrite rule, as it wouldn't match something like //api/.
# map `/api` to `/app`:
location /foo {
rewrite ^ $request_uri; # get original URI
rewrite ^/api(/.*) /app$1 break; # drop /api, put /app
return 400; # if the second rewrite won't match
proxy_pass http://localhost:8080$uri;
}
If you simply want to add a prefix for the backend, then you can just use the $request_uri variable right away:
# add `/webapp` to the backend:
location / {
proxy_pass http://localhost:8080/webapp$request_uri;
}
You might also want to take a look at a related answer, which shows some test-runs of the code similar to the above.
There is one documented option for Nginx proxy_pass directive
If it is necessary to transmit URI in the unprocessed form then directive proxy_pass should be used without URI part:
location /some/path/ {
proxy_pass http://127.0.0.1;
}
so in your case it could be like this. Do not worry about request URI it will be passed over to upstream servers
location / {
proxy_pass http://tracking;
}
Hope it helps.
In some cases, the problem is not on the nginx side - you must set the uri encoding on Tomcat connector to UTF-8.

Correct proxy path in nginx.conf

we have two servers, A and B. Server A is accessed worldwide. He has nginx installed. That's what I have in conf:
location /test {
proxy_pass http://localserver.com;
}
What it should do, is translate the addreess http://globalserver.com/test (that is server A) to internal server address http://localserver.com. However, it does append the location path, that is, itries to look for http://localserver.com/test, which is not available at all. How can I make the proxy pass to the correct address, throwing out the last part in the location?
That should work. Nginx should strip the '/test' path on the upstream local server. So what I can say is that is not the cause. To make it a bit better, try this:
location /test/ {
proxy_pass http://localserver.com/;
}
The 2 slashes I added at the first 2 lines will avoid mistakenly match '/testABC' and send the wrong request to the upstream local server, for example.
Do you have a
proxy_redirect
line in the same location block? If your upstream local server has redirects, then a mistake on that line will cause an issue like you described.
[UPDATE] Found the root cause why the original config didn't work and mine works: nginx does NOT replace URI path part if the proxy_pass directive does not have a URI path itself. So my fix of adding a slash (slash is treated as a URI path) at the end triggers the URI path replacement.
Reference: http://wiki.nginx.org/HttpProxyModule#proxy_pass
If it is necessary to transmit URI in the unprocessed form then directive proxy_pass should be used without URI part
location /some/path/ {
proxy_pass http://127.0.0.1;
}
try to add as specified here http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass:
proxy_pass http://localserver.com/;
try rewrite
location /test {
rewrite ^ $scheme://$host/;
proxy_pass http://localserver.com;
}
some helpful links...
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
http://wiki.nginx.org/Pitfalls

Resources