Varnish ERR_TOO_MANY_REDIRECTS

varnish

I use Nginx > Varnish > Apache, php-fpm in Centos WebPanel.
ERR_TOO_MANY_REDIRECTS appears for the WordPress homepage only and it goes away and then comes back on my site. This periodical behavior gave the clue that it is a cache-related problem.

Status 301 Moved Permanently
Server nginx/1.16.1
Date Mon, 24 Feb 2020 15:46:29 GMT
Content-Type text/html; charset=iso-8859-1
Content-Length 230
Connection keep-alive
Keep-Alive timeout=60
Location https://thinkbalm.com/
X-Varnish 98379 131369
Age 13
Via 1.1 varnish (Varnish/5.2)
X-Cache HIT from Backend

Setting the domain's configuration to Nginx > Apache, thereby taking out Varnish solves the problem, but then I lose Varnish cache. Therefore I did a lot of searching and the problem seems to be the following:

Varnish and SSL – WordPress Behind an HTTPS Terminating Proxy

Unfortunately, Varnish does not support SSL. So we need to terminate the SSL connection and speak plain HTTP with Varnish and your WordPress site.

Not only does Varnish not support SSL, it is also unaware of the SSL termination and just uses the hostname and the URL of the request as an identifier.

We trigger a problem: forcing HTTPS redirects on an application that is not aware what the initial request protocol, can cause ERR_TOO_MANY_REDIRECTS errors in your browser.

This happens when the HTTP version of a page is stored in cache. The output is nothing more than a 301 redirect to the HTTPS version. But because Varnish and WordPress are unaware of SSL termination, you’ll end up in a redirection loop until the browser throws this error.

How can we solve this?

I tried adding this to the wp-config file:

 if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'){
   $_SERVER['HTTPS'] = 'on';
   $_SERVER['SERVER_PORT'] = 443;
 }

I also tried to add this to .htaccess:

SetEnvIf X-Forwarded-Proto "https" HTTPS=on
Header append Vary: X-Forwarded-Proto

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

None of these resolved the situation.

Any ideas?

Best Answer

The entire solution, which I wrote a blog post about, depends on the presence of the X-Forwarded-Proto header.

  • Without it, the HTTPS environment variable cannot be set in Apache.
  • Without it, Varnish cannot perform the cache variation

My initial assumption is that this header is not properly set. But there's an easy way to find out:

Please send me the output of the following Varnish command:

varnishlog -g request -q "ReqUrl eq '/'"`

I'm assuming this happens on the homepage, so the command filters for requests on the homepage.

Please also confirm if you have a custom sub vcl_hash configuration that influences the way cache variations are done.