Intercepting backend 301/302 redirects (proxy_pass) and rewriting to another location block possible?
Asked Answered
A

4

28

We have a couple of backends sitting behind our nginx front ends.

Is it possible to intercept 301 / 302 redirects sent by these backends and have nginx handle them?

We were thinging something alone the lines of:

error_page 302 = @target;

But I doubt 301/302 redirects can be handled the same as 404's etc etc... I mean, error_page probably doesnt apply to 200, etc error codes?

So to summarize:

Our backends send back 301/302s once in a while. We would like to have nginx intercept these, and rewrite them to another location block, where we could do any number of other things with them.

Possible?

Thanks!

Airplane answered 27/11, 2013 at 22:39 Comment(0)
S
28

You could use proxy_redirect directive (documentation).

Nginx will still return 301/302 to the client but proxy_redirect will modify Location header and the client should make a new request to the URL given in the Location header.

Something like this should make the subsequent request back to nginx:

proxy_redirect    http://upstream:port/    http://$http_host/;
Shipowner answered 24/9, 2014 at 20:10 Comment(0)
S
16

I succeeded in solving a more generic case when a redirect location can be any external URL.

server {
    ...

    location / {
        proxy_pass http://backend;
        # You may need to uncomment the following line if your redirects are relative, e.g. /foo/bar
        #proxy_redirect / /;
        proxy_intercept_errors on;
        error_page 301 302 307 = @handle_redirects;
    }

    location @handle_redirects {
        set $saved_redirect_location '$upstream_http_location';
        proxy_pass $saved_redirect_location;
    }
}

Alternative approach, which is closer to what you describe, is covered in ServerFault answer to this question: https://serverfault.com/questions/641070/nginx-302-redirect-resolve-internally

Semantic answered 26/7, 2016 at 14:3 Comment(0)
C
12

If you need to follow multiple redirects, modify Vlad's solution as follows:

  1. Add

    recursive_error_pages on;
    

    to location /.

  2. Add

       proxy_intercept_errors on;
       error_page 301 302 307 = @handle_redirects;
    

    to the location @handle_redirects section.

Crosslink answered 10/9, 2017 at 14:1 Comment(0)
P
8

More on proxy_redirect, for relative locations

Case

location /api/ {
  proxy_pass http://${API_HOST}:${API_PORT}/;
}
  • the backend redirects to a relative location, which misses the /api/ prefix
  • the browser follows the redirection and hits a wall of incomprehension

Solution

location /api/ {
  proxy_pass http://${API_HOST}:${API_PORT}/;
  proxy_redirect ~^/(.*) http://$http_host/api/$1;
}
Piloting answered 13/11, 2018 at 17:57 Comment(1)
Use $scheme:// instead of http:// in the proxy redirect to get it to work on https.Hornstein

© 2022 - 2024 — McMap. All rights reserved.