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

aharris88
  • 3,560
  • 3
  • 27
  • 45
Alex Luya
  • 9,412
  • 15
  • 59
  • 91

7 Answers7

265

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;
}
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
kolbyjack
  • 17,660
  • 5
  • 48
  • 35
44

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

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Sebastian vom Meer
  • 5,005
  • 2
  • 28
  • 36
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;
}
Community
  • 1
  • 1
Andrew Arnautov
  • 345
  • 3
  • 5
  • 4
    This looks like it handles path params (`/path/params`) well but not query params (`?query=params`)? – Will Jun 12 '17 at 14:23
  • Ah no, my mistake, query parameters should be added automatically (they are in my testing). – Will Jun 12 '17 at 16:41
12

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;
}
SeinopSys
  • 8,787
  • 10
  • 62
  • 110
Pranav Garg
  • 583
  • 1
  • 9
  • 17
  • 1
    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. – Luke Peterson Dec 20 '16 at 04:52
  • 2
    This will break if your query parameters contain URL(%) encoded characters. Use Andrew's answer instead. – David Weber Dec 01 '17 at 06:53
  • This answer has nothing to do with a reverse proxy. If for example https://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. – Fencer Feb 03 '21 at 16:18
9

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

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Tobias Sgoff
  • 99
  • 1
  • 1
2

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;
}
Marcs
  • 3,768
  • 5
  • 33
  • 42
Abhishek
  • 1,558
  • 16
  • 28
2

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
AnJia
  • 129
  • 7