16

Original URL: /api/url%2Fencoded%2F/?with=queryParams

nginx:

location /api {
    client_max_body_size 2G;
    proxy_pass https://oursite;
}

With this configuration, I was able to preserve the URL encoding when passing through the proxy. If I add a "/" after "oursite", it will decode the URL.

Problem:

Now the URL after being proxied still contains "/api/". I need to remove "/api/" only while still preserving the URL encoded parts.

5
  • if I use a rewrite with a break it decodes it again Commented Mar 11, 2015 at 19:46
  • 2
    Not a long time ago there was identical question without an answer. In my opinion, you should rething api to not have such weird URLs. Another way is to have api on subdomain. Commented Mar 11, 2015 at 22:58
  • 1
    stackoverflow.com/q/28684300/1016033 Commented Mar 11, 2015 at 23:01
  • 1
    @AlexeyTen, i've got an answer! any chance it can get some votes? :-) Commented Jun 23, 2016 at 16:39
  • 1
    @SeanBollin, ping! I've worked really hard on the answer here, any chance you can take some time to decide whether it answers your question? Commented Jun 23, 2016 at 16:40

2 Answers 2

29

Not a long time ago there was identical question without an answer. In my opinion, you should rething api to not have such weird URLs. Another way is to have api on subdomain. – Alexey Ten Mar 11 '15 at 22:58

stackoverflow.com/q/28684300/1016033 – Alexey Ten Mar 11 '15 at 23:01

Year-old challenge accepted!

    location /api/ {
        rewrite ^ $request_uri;
        rewrite ^/api/(.*) $1 break;
        return 400;
        proxy_pass http://127.0.0.1:82/$uri;
    }

That's it, folks!

More details at Nginx pass_proxy subdirectory without url decoding, but it does work even with the query string, too:

%  curl "localhost:81/api/url%2Fencoded%2F/?with=queryParams"
/url%2Fencoded%2F/?with=queryParams
%
Sign up to request clarification or add additional context in comments.

12 Comments

For anyone working without nested paths, location / { proxy_pass http://127.0.0.1$request_uri; } works fine
@diachedelic, look at the last control group in the more details answer — the $request_uri in your example is redundant.
by gum you're right, my mistake was adding a slash like proxy_pass http://127.0.0.1/; which caused nginx to normalize the path (mentioned in docs here: nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass)
Same problem here on CentOS 6.4 and nginx 1.10.2. This answer fixed it. Now I'm wondering if latest version of nginx (1.13.9) still have this behaviour. This seems like a workaround not an Nginx classic configuration...
@MaX, look at the linked trac issue from the linked full "More details…" answer; the option you suggest would be a security risk, hence, it's nginx classic configuration to not provide it. There's very limited use case for this, and when it does strike, then the above workaround is 100% doable and is the best choice, really. (Thanks for upvote.) BTW, also, if you don't modify $uri, then no decoding is done. And you can't possibly have both without it being a total mess.
|
0

Disclaimer: I am sure this looks like an hack - and maybe it is. It is using the auth-subrequest feature for something else than auth, but it works!

If you want to keep any url-encoded part after /api/ from the original $request_uri I use NJS to set a variable and use it afterwards in the proxy_pass

js_import /etc/nginx/conf.d/http.js; # Import your njs file here
js_set $encodedUrlPart 'empty'; # Define a variable

  location ~* api\/(.*)$ {
    auth_request /urlencode; #This will get executed before proxy_pass
    proxy_pass http://127.0.0.1:82/$encodedUrlPart;
}

and the http.js can look like this

function urlencode(r){
    let regex = "(?<=\/api\/)(.*$)";
    let url = r.variables.request_uri # this holds the original, non touched url
    let lastPart = url.match(regex);
    r.variables.encodedUrlPart = lastPart; 
    r.log("The encoded url part: " + r.variables.encodedUrlPart);
    r.return(200); // need to return 200 so the 'auth' doesn't fail
  }
  export default {urlencode};

Is this considered unsafe? We could do some checking in the njs part though!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.