How can query string parameters be forwarded through a proxy_pass with nginx?
Asked Answered
C

7

185
upstream apache {
   server 127.0.0.1:8080;
}
server{
   location ~* ^/service/(.*)$ {
      proxy_pass http://apache/$1;
      proxy_redirect off;
   }
 }

The above snippet will redirect requests where the url includes the string "service" to another server, but it does not include query parameters.

Cleric answered 15/11, 2011 at 2:13 Comment(0)
S
275

From the proxy_pass documentation:

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.

Since you're using $1 in the target, nginx relies on you to tell it exactly what to pass. You can fix this in two ways. First, stripping the beginning of the uri with a proxy_pass is trivial:

location /service/ {
  # Note the trailing slash on the proxy_pass.
  # It tells nginx to replace /service/ with / when passing the request.
  proxy_pass http://apache/;
}

Or if you want to use the regex location, just include the args:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}
Stereotomy answered 15/11, 2011 at 2:44 Comment(6)
I don't believe you can do the latter. I tried and nginx complained to me.Stumer
Complained how? I just tested it on nginx 1.3.4 and it worked fine for me.Stereotomy
Humm.. I can't recall now :( But I feel like it might have been related to the "~*". However, I just checked, and I have nginx 1.2.3 (through homebrew). Maybe that's it?Stumer
"proxy_redirect default" may not be used with "proxy_pass" directive with variablesTorietorii
have to use rewrite location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }Rybinsk
ChatGPT, including GPT-4, could not get this right. Thank you so much. I already miss the human aspect of StackOverflow.Headachy
G
45

I use a slightly modified version of kolbyjack's second approach with ~ instead of ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Gelatinize answered 25/7, 2013 at 13:48 Comment(0)
R
19

you have to use rewrite to pass params using proxy_pass here is example I did for angularjs app deployment to s3

S3 Static Website Hosting Route All Paths to Index.html

adopted to your needs would be something like

location /service/ {
    rewrite ^\/service\/(.*) /$1 break;
    proxy_pass http://apache;
}

if you want to end up in http://127.0.0.1:8080/query/params/

if you want to end up in http://127.0.0.1:8080/service/query/params/ you'll need something like

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}
Rybinsk answered 24/5, 2016 at 7:30 Comment(2)
This looks like it handles path params (/path/params) well but not query params (?query=params)?Glamour
Ah no, my mistake, query parameters should be added automatically (they are in my testing).Glamour
B
14

I modified @kolbyjack code to make it work for

http://website1/service
http://website1/service/

with parameters

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}
Bain answered 24/9, 2015 at 21:9 Comment(3)
Keep in mind this will make the server return a 301 response to the client before redirecting. The proxy_pass directive above does the redirection on the server side.Credenza
This will break if your query parameters contain URL(%) encoded characters. Use Andrew's answer instead.Zygophyte
This answer has nothing to do with a reverse proxy. If for example service_url is not reachable from the internet directly (which is highly likely in a reverse proxy scenario) it will fail completely. Furthermore it tells the client that it should use the redirect URL directly next time (301 permanently moved) which is probably not desired in this case, too.Ultramundane
E
8

worked with adding $request_uri:
proxy_pass http://apache/$request_uri;

Estragon answered 29/5, 2020 at 11:17 Comment(0)
D
3

To redirect Without Query String add below lines in Server block under listen port line:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/;
}

With Query String:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Diamagnet answered 6/6, 2017 at 8:24 Comment(3)
The nginx documentation is explicit in avoid to use if when possible. In this case, the solution could be right using location as shown in another answers.Epirogeny
anyway one more solution even if it has drawbacks is betterJames
How can we pass query string parameters with JS_CONTENT module ?Frederickafredericks
K
3

github gist https://gist.github.com/anjia0532/da4a17f848468de5a374c860b17607e7

#set $token "?"; # deprecated

set $token ""; # declar token is ""(empty str) for original request without args,because $is_args concat any var will be `?`

if ($is_args) { # if the request has args update token to "&"
    set $token "&";
}

location /test {
    set $args "${args}${token}k1=v1&k2=v2"; # update original append custom params with $token
    # if no args $is_args is empty str,else it's "?"
    # http is scheme
    # service is upstream server
    #proxy_pass http://service/$uri$is_args$args; # deprecated remove `/`
    proxy_pass http://service$uri$is_args$args; # proxy pass
}

#http://localhost/test?foo=bar ==> http://service/test?foo=bar&k1=v1&k2=v2

#http://localhost/test/ ==> http://service/test?k1=v1&k2=v2
Kailey answered 16/10, 2017 at 8:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.