I wrote a blog post about the subject a couple of years ago. Please have a look: https://feryn.eu/blog/mixed-content-and-err-too-many-redirects-in-wordpress/
Of course I'm going to put the relevant configuration out here as well.
Nginx config
Nginx is acting as your TLS termination point, but it sends plain HTTP requests to Varnish.
You need to send an X-Forwarded-Proto
header through Varnish and Apache, to make both of them aware of the protocol that was used.
You can add the following line to your proxy logic within your Nginx config:
proxy_set_header X-Forwarded-Proto $scheme;
Apache config
Apache will process this X-Forwarded-Proto
and perform redirection if the value is not HTTPS
.
The snippet below can be dropped in an .htaccess
file if you want:
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>
A quick rundown of what this does:
- Check the value of the
X-Forwarded-Proto
- Set the environment variable
HTTPS
to ON
if X-Forwarded-Proto
equals HTTPS
- Set a custom
Vary: X-Forwarded-Proto header
(required for Varnish)
- Do on HTTPS redirect if
HTTPS
is not On
and X-Forwarded-Proto
is not HTTPS
What about Varnish?
By default, Varnish has no protocol awareness. You can write some VCL to make that happen, but luckily the HTTP protocol has the required semantics to make this happen using HTTP headers.
In the previous section about Apache configuration, I referred to Vary: X-Forwarded-Proto
. This is what Varnish needs to make a distinction between HTTP & HTTPS content.
If it weren't for this Vary
header, Varnish would cache whatever is called first, which could lead to mixed content being cached.
A Vary
tells Varnish to create a cache variation for each value of X-Forwarded-Proto
. This will separate HTTP content from HTTPS content and will result in the right URL scheme to be used on the cached pages.