Search code examples
ruby-on-railslinuxcentosvarnishvarnish-vcl

varnish cache http 301 302 header location redirects


I'm trying to set up an in-the-middle varnish server to allow a Rails app on xyz.com to work on several other domain names.

What happens is that from time to time the Rails app outputs some 301/302 redirects and apparently varnish does not change these headers, so visitors get redirected to the original site (which is behind the public-facing varnish server), so... error.

Is there a way to configure this rewrite on the varnish side of things?

under vcl_fetch I tried the following:

if ( (beresp.status == 301) || (beresp.status == 302) ) {
    set req.url = regsub(req.url,".*",regsuball(regsub(beresp.http.Location,"^http://[^/]+(.*)","\1"),"[+]","%2520"));
    return(restart);

But maybe I don't understand how this works exactly? Any help will be much appreciated


Solution

  • After fighting with your regex an thinking of the use case... I think you would probably can do a much straightforward thing, such as rewrite the location and cache the object corrected (and leave redirection to client browser).

    On vcl_fetch:

    # ...
    if ( beresp.status == 301
      || beresp.status == 302
    ) {
      # Check if we're redirecting to a different site
      if ( ! beresp.http.Location ~ req.http.host ) {
        # Rewrite HTTP Location header to cache it and pass redirection to client
        set beresp.http.Location = regsub(
                                     beresp.http.Location,
                                     "^http://[^/]+/",
                                     "http://" + req.http.host + "/"
                                   );
      }
    }
    # ...
    

    If you still prefer to restart the request on a different url inside Varnish, I'll try (again on vcl_fetch):

    # ...
    if ( beresp.status == 301
      || beresp.status == 302
    ) {
      # Add a header so you can debug cleanly on varnishlog
      set req.http.X-Redirected-Orig = beresp.http.Location;
      # Rewrite request host
      set req.http.host = regsub(
                            regsub(
                              beresp.http.Location,
                              "^http://",
                              "",
                            ),
                            "^([^/]+)/.*$",
                            "\1"
                          );
      # Rewrite request url
      set req.url = regsub(
                      beresp.http.Location,
                      "^http://[^/]+/(.*)$",
                      "/\1",
                    );
      # Add a header so you can debug cleanly on varnishlog
      set req.http.X-Redirected-To = "http://" + req.http.host + req.url;
      return (restart);
    }
    # ...
    

    PS: Excuse me for the regsub indentations, but I think it's much more readable with it.