Nginx pass_proxy subdirectory without url decoding

后端 未结 2 531
太阳男子
太阳男子 2020-11-29 03:27

I need to write an nginx location directive to proxy requests to subdirectory to another server preserving urlencoding and removing subdirectory pre

相关标签:
2条回答
  • 2020-11-29 04:00

    What you have to do is fairly easy as long as we are talking prefix matching with ^~ or no modifier

    location /api/ {
      # if you don't want to pass /api/ add a trailing slash to the proxy_pass
      proxy_pass http://localhost:8080/;
    
      ...
    }
    

    And everything will be passed along without decoding, you don't have to pass $uri

    Also while you use proxy pass you should also set these headers

    # pass headers and body along
    proxy_pass_request_headers on;
    proxy_pass_request_body on;
    
    # set some headers to make sure the reverse proxy is passing along everything necessary
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    
    0 讨论(0)
  • 2020-11-29 04:12

    But there is no easy way to fix this nginx behaviour. There are some bugs in nginx trac, you could add yours. trac.nginx.org/nginx/…. So, I think that the simplest way is to have subdomain. – Alexey Ten Feb 24 '15 at 14:49

    https://trac.nginx.org/nginx/ticket/727

    If you want nginx to do something custom, you can do so using ​proxy_pass with variables (and the $request_uri variable, which contains original unescaped request URI as sent by a client). In this case it will be your responsibility to do correct URI transformations. Note though that this can easily cause security issues and should be done with care.

    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!


    Here's for the full proof.

    The config file for nginx/1.2.1:

    server {
        listen 81;
        #first, the solution
        location /api/ {
            rewrite ^ $request_uri;
            rewrite ^/api/(.*) $1 break;
            return 400; #if the second rewrite won't match
            proxy_pass http://127.0.0.1:82/$uri;
        }
        #next, a few control groups
        location /dec/ {
            proxy_pass http://127.0.0.1:82/;
        }
        location /mec/ {
            rewrite ^/mec(/.*) $1 break;
            proxy_pass http://127.0.0.1:82;
        }
        location /nod/ {
            proxy_pass http://127.0.0.1:82;
        }
    }
    
    server {
        listen 82;
        return 200 $request_uri\n;
    }
    

    Here are the results of running the queries for each location:

    % echo localhost:81/{api,dec,mec,nod}/save/http%3A%2F%2Fexample.com | xargs -n1 curl
    /save/http%3A%2F%2Fexample.com
    /save/http:/example.com
    /save/http:/example.com
    /nod/save/http%3A%2F%2Fexample.com
    %
    

    Note that having that extra return 400; is quite important — otherwise, you risk having a security issue (file access through //api etc), as Maxim has briefly mentioned in your trac ticket.


    P.S. If you think using the rewrite engine as a finite-state automaton is super cool, you might also want check out my http://mdoc.su/ project, or fork it github.

    0 讨论(0)
提交回复
热议问题