Troubleshooting an endless redirect loop for a site behind Cloudflare
What can you do when you don't know (or have forgotten) that a setting exists?
I spent a few very frustrating hours trying to figure out why HTTPS requests to for a particular domain (behind Cloudflare) kept providing redirects to the same URI. I checked and re-checked my web server configuration, deleting lines, re-adding lines, and refreshing my browser. It turned out that I needed to change the encryption mode in Cloudflare!
The web server configuration #
I configured the web server to:
- Listen on port 80 and redirect to port 443
- Redirect the bare domain and every subdomain (except www.) to www.
- Serve a site on www.
server {
server_name example.com *.example.com;
listen 80;
listen [::]:80;
if ($host ~ (^[^.]+\.example\.com$|^example.com$)) {
return 301 https://$host$request_uri;
}
# Should never get here!
return 404;
}
server {
server_name example.com *.example.com;
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
autoindex off;
return 307 https://www.example.com;
}
server {
server_name www.example.com;
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
}
Troubleshooting the problem #
I expected the following:
Request | Behaviour |
---|---|
http://example.com/ | Redirect to https://example.com/ |
http://www.example.com/ | Redirect to https://www.example.com/ |
https://example.com/ | Redirect to https://www.example.com/ |
https://www.example.com/ | Serve site content |
HTTP requests redirected to HTTPS, as expected.
However, HTTPS requests resulted in an endless loop to the same URI!
I spent entirely too much time testing and re-testing the web server configuration before I decided to try making requests directly to the web server itself, as requests to the domain itself are handled by a Cloudflare proxy.
I learned that I could inspect an HTTPS response to the web server's IP address
via curl
using three arguemnts:
-i
to makecurl
include the response headers in the output [1]-k
to makecurl
skip certificate verification [2]—since the request is to the IP address but the certificate is for the domain, certificate verification would fail--header 'Host: www.example.com'
to tell the web server which site I want [3]
So I reviewed the response I got in my browser from Cloudflare and compared it
to the response I got making a curl
request to the web server's IP address:
curl -ik --header 'Host: example.com' https://12.34.56.78
The server presented the behaviour I expected to curl
, but Cloudflare
presented the behaviour for an HTTP request to my browser!
Fixing the Cloudflare setting #
From there, I quickly found out (or maybe more accurately re-discovered) that Cloudflare's encryption mode for a site controls how Cloudflare connects to the origin server [4]. The encryption mode was set to Flexible, which meant that Cloudflare accessed the site via HTTP and presented the response to the requester via HTTPS. I changed the encryption mode to Full (strict) to have Cloudflare only use HTTPS.
If I'd only searched for the right terms, I might have seen Cloudflare's
troubleshooting page on ERR_TOO_MANY_REDIRECTS [5], which addresses this
exact scenario. Well, at least now I know how to make requests for a particular
host and skip certificate validation using curl
.
Footnotes #
[1] Telling curl to include HTTP response headers in the output (curl.se) ^
[2] Telling curl to skip certificate verification (curl.se) ^
[3] Manually setting the Host header for a curl request (stackoverflow.com) ^
[4] Cloudflare Docs: Encryption modes (developers.cloudflare.com) ^
[5] Cloudflare Docs: ERR_TOO_MANY_REDIRECTS (developers.cloudflare.com) ^