how to issue a relative url redirect from nginx?

15,017

Solution 1

nginx header filter always inserts <scheme>://<host> if return uri starts with /.
(see ngx_http_script_return_code() and ngx_http_header_filter() function in nginx source for reference)


So, if client (e.g. google chrome) can accept Location: /qwerty, you can use the following configure:

location = /b {
    return 301 " /qwerty";    # insert space char before "/qwerty"
}

Another solution can generate Location: /qwerty exactly, via lua-nginx-module and add_header directive:

location = /b {
    add_header Location "/qwerty";
    content_by_lua 'ngx.exit(301)';
}

How does this weird configure work?

  • use ngx.exit to exit with status code with 301, it does not create "Location" header (return directive always create "Location" header, even empty header value)
  • use add_header to add Location: /qwerty header, it does not insert <scheme>://<host>

Solution 2

There is an nginx directive absolute_redirect available from nginx version 1.11.8, which is enabled by default. If disabled, redirects issued by nginx will be relative. This issue is a bit older, but maybe useful for all of you hitting it from google.

 absolute_redirect off;
Share:
15,017

Related videos on Youtube

dan moore
Author by

dan moore

Updated on September 19, 2022

Comments

  • dan moore
    dan moore over 1 year

    How can a redirect be configured in nginx to respond to a certain url with a relative redirect to a specific path?

    The nginx documentation suggests that this is the default mode for nginx, but in reality if the location being redirected to starts with a / nginx is responding with an absolute url in the Location field.

    For local server configuration containing locations:

    location = /a {
      return 301 some/path;
    }
    location = /b {
      return 301 /qwerty;
    }
    

    the response Location to a request to /a is:

    Location: some/path
    

    and for /b it is:

    Location: http://127.0.0.1/qwerty
    

    however, we would like /b to respond with:

    Location: /qwerty
    

    The reason we would like to use relative redirects is that we would like to access nginx from different domains and proxies, e.g. in clear in dev or via ssl-terminating load-balancer, and would rather keep things simple by relieving nginx of needing to understand that context.

    FYI these examples were tested against nginx versions 1.4.6 and 1.9.6, using curl e.g.:

    curl --head http://127.0.0.1/b
    
  • Rafał Krypa
    Rafał Krypa about 7 years
    Nice trick with a space in "return" directive. Is this behavior of nginx documented anywhere?
  • Trevor Freeman
    Trevor Freeman over 6 years
    That space trick is hilarious and awesome, how did you discover it?
  • xiaochen
    xiaochen over 6 years
    hi @TrevorFreeman , RFC 2616 allows "space trick" actually. In chapter "4.2 Message Headers", the header value is defined as field-value = *( field-content | LWS ). *LWS means zero or many linear white space.
  • chrkv
    chrkv over 6 years
    @xiaochen RFC 2616 is obsolete for 3 years. RFC 7231 now allows relative redirects tools.ietf.org/html/rfc7231
  • Santhosh
    Santhosh about 4 years
    This is simplest and perfect solution, but I had to check it in a private browser window to confirm that Location header is relative. Regular browser window still shows the absolute Location header due to caching behaviour.
  • JJ Roman
    JJ Roman over 3 years
    add_header solution is significantly slower