Nginx is running on port 80, and I'm using it to reverse proxy URLs with path /foo to port 3200 this way:

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

This works fine, but I have an application on port 3200, for which I don't want the initial /foo to be sent to. That is - when I access http://localhost/foo/bar, I want only /bar to be the path as received by the app. So I tried adding this line to the location block above:

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

This causes 302 redirect (change in URL), but I want 301. What should I do?

share|improve this question
up vote 93 down vote accepted

Any redirect to localhost doesn't make sense from a remote system (e.g. client's Web browser). So the rewrite flags permanent (301) or redirect (302) are not usable in your case.

Please try following setup using a transparent rewrite rule:

location  /foo {
  rewrite /foo(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}
share|improve this answer
1  
The URL path still begins with /foo in my app when I do that... – jeffreyveon Apr 16 '12 at 1:48
    
There must be a different problem. I reproduced this scenario successfully, just minutes ago. Original URL: http://development/foo/testme/1234 - REQUEST_URI of a PHP script running on a Apache connected as proxy back-end: '/testme/1234' – Jens Bradler Apr 17 '12 at 8:32
6  
The regex should probably be /foo(.*), otherwise example.com/foo wont be matched. (which is probably what jeffreyveon experienced) – Benno Jan 30 '14 at 2:11
    
This kind of works, but my body i'm setting with proxy_set_body is being removed. – Justin Thomas Mar 23 '17 at 17:00
    
rewrite /(.*) /socket.io/ break; SAVE MY DAY FOR SOCKET.IO – user956584 Jul 25 '17 at 18:52

Simple location prefix matching works for this without using a rewrite rule as long as you specify a URI in the proxy_pass directive:

location /foo {
  proxy_pass http://localhost:3200/;
}

Notice the additional / at the end of the proxy_pass directive. NGINX will strip the matched prefix /foo and pass the remainder to the backend server at the URI /. Therefore, http://myserver:80/foo/bar will post to the backend at http://localhost:3200/bar.

From the NGINX docs on proxy_pass:

If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

share|improve this answer
6  
Works for me than I've added / to location /foo/ { – Andrei N Nov 26 '15 at 10:41
    
This was precisely what I was looking for! – anbiniyar May 8 '16 at 19:53
4  
This is a very clean solution, I would prefer this to be the canonical answer to the question. – Alex Sep 29 '16 at 22:12
    
While this works, the other answer is more self-documenting. This feels like magic. – Eric Dec 6 '16 at 19:21
1  
Took too long to realize the importance of keeping or removing trailing slash. – Parvez Aug 2 '17 at 9:25

The absolute most correct way and best practice is usually as follows:

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • Note the dire importance of the trailing slash in proxy_pass, which automatically alters the $uri variable to have the /foo/ on the front-end correspond with / on the backend. No need for an explicit rewrite directive.

  • Additionally, note that the the trailing / in the location is quite important as well — without it, you risk having weird-looking URLs on your site at one point (e.g., a working /fooen in addition to /foo/en).

    Additionally, the trailing / in the location with proxy_pass also ensures some special handling, as per the documentation of the location directive, to effectively cause an implicit location = /foo {return 301 /foo/;} as well.

    So, by defining a location with the trailing slash as above, you not only ensure that slash-less suffix URLs like /fooen won't be valid, but also that a /foo without a trailing slash will continue to work as well.


Reference documentation:

share|improve this answer
1  
This is the best answer here! – Mo Friedrich Oct 18 '17 at 12:37
    
It looks like $args are lost: http://frontend/foo?bar=baz will be proxied to http://backend/. Notice that args are not the part of url – Vanuan Nov 1 '17 at 17:47
    
@Vanuan, are you sure about that? I'm pretty certain $args should still be handled appropriately if you use the code above, as they're separate from $uri, and should get assembled back in, unless you're using explicit variables in your proxy_pass. – cnst Nov 3 '17 at 6:53
    
@cnst Oh, I see. I'm using the host variable. That's counter intuitive. – Vanuan Nov 4 '17 at 18:08
    
@cnst What would you recommend if I need a mapping of upstream servers with proxy_pass directive? Like here serverfault.com/questions/562332/… – Vanuan Nov 4 '17 at 18:10

try

location /foo {
    proxy_pass http://localhost:3200/;
    ....

or

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....
share|improve this answer
9  
This answer would be good if you give some explanation why it must be configured like above. – masegaloeh Jan 21 '15 at 22:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.