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!
Varnish is a powerful caching HTTP reverse proxy server. It can sit in front of Apache or Nginx and can cache the requests that are configured to be cached. Varnish offers a lot of flexibility on what to cache and what not to cache. However, it doesn’t offer any simple redirection by default. When it stands in front of a general purpose web server, it sends the requests to the backend (in our case, Nginx), and then sends the backend response to the browser. While this is the natural process, there are a couple of ways to reduce this round-trip and save a bit of time. After all, every millisecond counts!
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.
This doesn’t work. I get the following error in Chrome:
Error 310 (net::ERR_TOO_MANY_REDIRECTS): There were too many redirects.
How does the `curl -L` output look like?
What does the number 750 in line no. 4 “error 750” mean ? I don’t think it is a HTTP error code.
The double ampersand (&) symbol has been encoded to & on line two.
Correct.
750 is a temporary and imaginary status code used by Varnish to pass the request to vcl_error that would put the correct status code afterwards.
Thanks for the note on ampersand. Can’t figure out how to let it display correctly. :(
Are you using “SyntaxHighlighter Evolved” plugin ? I also faced the same issue with it and this is how I fixed it.
1. Go to “Your Profile” and disable the visual editor.
2. Open Settings > Writing and uncheck “correct invalidly nested ……” and the “convert ….” option below it.
3. Now open this article, CUT (don’t copy) and paste this piece of code to your notepad, edit the ampersand, add [code][/code] tags in the notepad itself.
4. Copy this code and paste it in this article and UPDATE it do NOT preview it.
This is how I got it working.
Awesome. It worked. Thank you.
Yes.
You’re welcome Pothi.
What plugin are you using for these comment forms ? Each time someone replies to my comments I get a notification from WordPress.com !!!
But I find that you’re using self hosted wordpress.
Hi Jesin,
I use Jetpack subscriptions. I find it easier to let visitors to subscribe (comments or posts) by email, rather than using other similar solutions. I know Jetpack is bloated. However, I use it only for subscription and for contact form (I understand there are better solutions for contact forms). If there is a better way to manage the subscriptions, I’m all ears.
Pothi,
I think Solution #1 code changed to:
sub vcl_fetch {
if (beresp.status == 301 || beresp.status == 302) {
set beresp.ttl = 52w;
}
}