190
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.

7 Answers 7

285

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;
}
Sign up to request clarification or add additional context in comments.

6 Comments

I don't believe you can do the latter. I tried and nginx complained to me.
Complained how? I just tested it on nginx 1.3.4 and it worked fine for me.
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?
have to use rewrite location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
ChatGPT, including GPT-4, could not get this right. Thank you so much. I already miss the human aspect of StackOverflow.
|
48

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

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}

Comments

18

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;
}

2 Comments

This looks like it handles path params (/path/params) well but not query params (?query=params)?
Ah no, my mistake, query parameters should be added automatically (they are in my testing).
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;
}

3 Comments

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.
This will break if your query parameters contain URL(%) encoded characters. Use Andrew's answer instead.
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.
11

worked with adding $request_uri:

proxy_pass http://apache/$request_uri;

Comments

4

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;
}

3 Comments

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.
anyway one more solution even if it has drawbacks is better
How can we pass query string parameters with JS_CONTENT module ?
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

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.