Note (as of August 30, 2017): The original post was published for Varnish 3. A lot changed since then. Currently, we have a nicer way to achieve 301 redirects. Thanks!
Solution 1
We could increase the TTL to 52 weeks, like the following example…
sub vcl_fetch {
if (beresp.status == 301) {
beresp.ttl = 52w;
}
}
In this method, only the first request goes to the backend. The consecutive requests to the same URL would probably never reach the backend (at least for the next 52 weeks), as the backend response has been cached by Varnish. You may change the TTL value to suit your particular scenario.
Solution 2
This uses a dirty trick! Here is how it’s done here in this site…
sub vcl_recv {
if ( req.http.host ~ "^(?i)(www.)?tinywp.in" &&
req.http.X-Forwarded-Proto !~ "(?i)https") {
error 750 "Moved Permanently";
}
}
sub vcl_error {
if (obj.status == 750) {
set obj.http.Location = "https://www.tinywp.in" + req.url;
set obj.status = 301;
return (deliver);
}
}
In this method, Varnish offers 301 redirection using vcl_error logic. It still saves some milliseconds, rather than going to the backend and then to serve its response on each client request. Here, the error code 750 is just a temporary and imaginary status code (here’s the list of all valid HTTP status codes) used by Varnish, as mentioned in the comments below (thanks to Jesin for the question).
My preference is with the solution #1. You may use solution #2, depending on the use-case (ex: if you wish to save a bit of memory). If you have any other solution, please feel free to share it in the comments!
If you don’t use Varnish on port 80, then you may benefit from the new way of doing 301 redirects at the server level using Apache or Nginx.