Docket

TROUBLESHOOTING

ERR_TOO_MANY_REDIRECTS after you turned on Cloudflare

Flexible mode fetches your origin over plain HTTP while your server redirects plain HTTP to HTTPS, and the two argue until the browser gives up.

7 MIN READ Last updated 23 August 2026

The board was fine, you turned the orange cloud on, and now every visitor gets ERR_TOO_MANY_REDIRECTS. Nothing in the container logs explains it, because nothing in the container is wrong. Cloudflare is set to Flexible, so it fetches your origin over plain HTTP, your server redirects plain HTTP to HTTPS, and round it goes. Change the encryption mode.

Cloudflare's behaviour below was read from Cloudflare's own troubleshooting documentation on 23 August 2026.

Why does switching the proxy on create a loop?

Because two independent decisions about HTTPS are being made by two systems that do not know about each other. The browser talks to Cloudflare, and Cloudflare talks to your origin, and the encryption mode governs only the second of those. Cloudflare states what Flexible means without hedging:

If your domain's encryption mode is set to Flexible, Cloudflare sends unencrypted requests to your origin server over HTTP.

Cloudflare, ERR_TOO_MANY_REDIRECTS

Now look at your origin. Caddy issues certificates and redirects HTTP to HTTPS on its own, with no configuration at all, and an nginx set up by Certbot gets a server block whose only job is that redirect. Every guide you followed left you with a server that insists on HTTPS, which is correct and which you want.

Put those together and the sequence is: the browser asks Cloudflare over HTTPS, Cloudflare asks your origin over HTTP, your origin answers 301 Moved Permanently to the HTTPS address, Cloudflare passes that redirect back, the browser asks again, and Cloudflare asks your origin over HTTP again. Nobody errors. Every party is behaving exactly as configured. The browser is the only one keeping count, which is why the logs are so unhelpful and why the same symptom on a self-hosted app behind a proxy ran to 24 comments on Coolify's repository before it was closed.

How do you confirm it before changing anything?

Three commands, and you will know which half is redirecting.

1. Watch the loop from outside.

curl -sSI -L --max-redirs 5 https://board.example.com/ \
  | grep -iE '^(HTTP|location)'

The same status line and the same location header repeating is the loop. If you see one redirect and then a 200, this is not your problem.

2. Ask the origin directly, bypassing Cloudflare, substituting your server's real address:

curl -sSI --resolve board.example.com:80:203.0.113.10 \
  http://board.example.com/ | grep -iE '^(HTTP|location)'

A 301 to the HTTPS address here is the origin's half of the loop. That answer is correct. It is only a problem because of what is asking.

3. Check the origin actually serves HTTPS with a valid certificate, because the fix depends on it:

curl -sSI --resolve board.example.com:443:203.0.113.10 \
  https://board.example.com/ | head -1

A clean status line means you have a real certificate at the origin and can move straight to the fix. A certificate error means you need one first.

What is the fix?

1. Set the encryption mode to Full (strict). In the Cloudflare dashboard, under SSL/TLS and then Overview. Cloudflare will connect to your origin over HTTPS and validate the certificate it presents, which is what your origin was expecting all along. The loop ends on the next request.

2. If the origin has no publicly trusted certificate, issue one before you switch. Cloudflare's Origin CA issues a free certificate that is trusted by Cloudflare specifically, which is enough for this hop. Install it at the origin, then set Full (strict).

3. Do not fix it by deleting the origin's HTTPS redirect. Cloudflare's page does offer that as an alternative, and it genuinely stops the loop, but it leaves the hop between Cloudflare and your server unencrypted and means anyone reaching your origin directly is served over plain HTTP. It is a reasonable stopgap while you sort out a certificate, not a destination.

4. Purge the Cloudflare cache and retest in a private window. A 301 is a permanent redirect and browsers cache it hard, so a fixed site can keep looping in the tab you have been testing in.

Cloudflare's own page names three families of cause, and it is worth seeing all of them next to each other, because the fix flips depending on which direction the origin redirects:

What is setThe loop it createsWhat to change
Flexible encryption modeCloudflare fetches over HTTP, the origin redirects to HTTPSFull (strict), with a certificate at the origin
Full or Full (strict), origin redirecting HTTPS back to HTTPCloudflare fetches over HTTPS, the origin sends it back downRemove the HTTP redirect at the origin
Always Use HTTPS, origin redirecting HTTPS to HTTPThe same loop driven from the edge insteadFix the origin, or turn Always Use HTTPS off
A redirect rule whose destination matches its sourceApex to www while DNS sends www straight backRewrite the rule so the two differ

How do you tell it worked?

Run the first command again. One redirect, or none, followed by a 200, is the answer you want:

curl -sSI https://board.example.com/ | grep -iE '^(HTTP|cf-ray)'

The cf-ray header confirms the request really went through Cloudflare rather than round it. Then load the board in a fresh private window, sign in, and cast a vote, because a session cookie marked Secure is the thing most likely to still be unhappy after a scheme change. If the page loads signed out and loops signed in, the remaining fault is in the headers your proxy sends the application, which is the mixed content problem rather than this one.

Your own support centre, in your own repository

One payment, no subscription, unlimited products.

Same error, different cause

What you seeWhat it usually is
It loops through a Cloudflare Tunnel with no orange cloud involvedThe tunnel's ingress points at http://localhost while the local server forces HTTPS, or at https://localhost with a certificate the tunnel will not accept. Same argument, different transport
It still loops after switching to Full (strict)HSTS. The browser was told to always use HTTPS and is honouring it against an origin that redirects the other way. Test in a fresh profile, and check the origin is not sending its own downgrade
Only the apex or only the www hostname loopsA redirect rule pointing one at the other while DNS or the origin sends it back. Follow the chain with curl -L and read every location line
Only some paths loopAn application-level canonical redirect, for example forcing a trailing slash or a lower-case path, disagreeing with a rule at the edge
Turning the orange cloud off fixes it instantlyConfirms the diagnosis rather than solving it. That is a valid rollback while you install a certificate, and grey-clouding the record is also what several hosted vendors ask for during domain verification
It works for you and loops for a colleagueA cached redirect on their side, or an HSTS entry. Ask them to test in a private window before you change anything

Does this one apply to a static support centre?

Yes, and unlike most of what goes wrong in front of a self-hosted tool, this one is not about the application at all. The fault lives between the browser and your host, so a static site hits it exactly as hard as a container does: if your host forces HTTPS, and any sensible static host does, and the mode is Flexible, you get the same loop with no application involved. Docket has no special protection here. The related setup steps, including the grey cloud during domain verification, are in custom domains for a support site and Cloudflare Tunnel for a support site.

Frequently asked questions

What is the difference between Flexible, Full and Full (strict)?

They describe the Cloudflare to origin hop only. Flexible connects over plain HTTP. Full connects over HTTPS but accepts any certificate, including a self-signed one. Full (strict) connects over HTTPS and validates the certificate properly. Full (strict) is the one to aim for, and Cloudflare's own Origin CA gives you a free certificate that satisfies it.

Why did it work before I switched the proxy on?

Because with the orange cloud off, Cloudflare only answers DNS and the browser connects straight to your server over HTTPS. There is no second hop and therefore no second opinion about the scheme. Proxying introduces that hop, and the encryption mode is where you tell Cloudflare what to do with it.

Is Flexible mode ever the right choice?

Rarely, and never for anything with a login. It leaves the connection between Cloudflare and your server unencrypted, so traffic that visitors see as secure is not secure for its whole journey. If the only thing standing between you and Full (strict) is a certificate, an Origin CA certificate takes minutes to issue and install.

Why do the container logs show nothing wrong?

Because nothing is wrong in the container. It receives a plain HTTP request and answers with a redirect, correctly, every time. There is no error to log. The loop only exists when you look at the whole chain, which is why the diagnosis has to be made with curl from outside rather than from inside the box.

Could this be my proxy rather than Cloudflare?

It can be, and the second command above tells you which. Ask the origin directly with --resolve. If the origin returns a single redirect to HTTPS and then serves a page, it is behaving; the loop is being created by the settings in front of it. If the origin loops against itself, fix that first and leave Cloudflare alone until it does not.