How to handle upstreams returning redirects in nginx
In a project that I use with nginx, I have an proxied upstream that returns a redirect to another url.
The new destination is not available to the end user, and anyway I want this to be transparent to the end user.
How can I configure nginx
in order to handle this ?
There are many resources online that offer help on this, but I had mixed results. What worked for me was a configuration as follows.
Let’s say that I want to serve url of the type https://example.com/item/:id
, where :id
can be any number.
Any request to such an url should be forwarded to https://upstream.com/someservice?item=:id
. My issue is
that for a number of reason such service will respond with a redirect to https://upstream.com/someservice/item/:id?token=sometoken
,
which cannot be reached by the end users, so I need nginx to handle it for me.
I finally found a solution that works for me, and it is something as follows:
server_name example.com;
# ...
location ~ ^/item/(.*)$ {
proxy_pass https://upstream.com/someservice?item=$1;
proxy_intercept_errors on;
recursive_error_pages on;
error_page 301 302 303 307 308 = @handle_redirect;
}
location @handle_redirect {
# For some reasons, directly using the variable doesn't work
set $saved_redirect_location '$upstream_http_location';
proxy_intercept_errors on;
recursive_error_pages on;
error_page 301 302 303 307 308 = @handle_redirect;
}
In other words, you tell nginx to handle redirects result with a virtual location that handles the redirect properly.
What I couldn’t find online is that if there are multiple redirects involved (like it was my case), you need to explicitly
handle them in the virtual location too (hence the proxy_intercept_errors
, recursive_error_pages
and error_page
directives
in the virtual location too).