Fix Cloudflare ERR_TOO_MANY_REDIRECTS After Forcing HTTPS in Laravel or WordPress
You switch your site to HTTPS behind Cloudflare, refresh the page, and suddenly the browser shows: This page isn’t working ERR_TOO_MANY_REDIRECTS This means your browser is being bounced back and forth between HTTP and HTTPS (or between two domains) until it gives up. With Cloudflare in front and Laravel or WordPress on the origin, it’s easy to create a redirect loop by accident.
Let’s walk through the real reasons this happens and how to fix it safely.
1. Understand the basic problem: double HTTPS redirects
A redirect loop usually happens because:
- Cloudflare is redirecting HTTP → HTTPS
- Your server (Laravel / WordPress / web server config) is also redirecting HTTP → HTTPS, but the two disagree on whether the request is already secure.
Typical flow:
- Browser requests
http://example.com - Cloudflare changes it to
https://example.com - Cloudflare talks to your origin over HTTP
- Origin sees
HTTP(because the connection from Cloudflare is not HTTPS) and redirects to HTTPS again - Cloudflare receives the redirect to HTTPS and does the same thing again… loop.
So the real fix is always:
- Choose the correct Cloudflare SSL mode
- Make Laravel/WordPress trust the Cloudflare HTTPS headers
- Avoid duplicate redirect rules.
2. Step one: Set the correct Cloudflare SSL/TLS mode
In Cloudflare Dashboard → SSL/TLS → Overview, you’ll see four modes:
- Off
- Flexible
- Full
- Full (strict)
Short version:
- Flexible: Browser ↔ Cloudflare uses HTTPS, Cloudflare ↔ Origin uses HTTP
- Full / Full strict: Both legs use HTTPS (Cloudflare expects SSL on your server)
Flexible is the number one cause of redirect loops once you start redirecting to HTTPS at the origin.
Recommended setting
If your server has an SSL certificate (Let’s Encrypt, cPanel AutoSSL, self-signed, etc.):
- Use Full (strict) if the cert is valid and matches the domain
- Use Full if it’s self-signed or not perfectly trusted
Avoid Flexible unless you absolutely cannot install any certificate on the origin.
After changing SSL mode, wait a minute and reload the site in a new incognito window.
3. Clean up Cloudflare HTTPS redirects and page rules
Cloudflare gives you multiple ways to force HTTPS:
- “Always Use HTTPS” (SSL/TLS → Edge Certificates)
- Page Rules or Redirect Rules that forward
httptraffic tohttps - Transform Rules / origin rules in newer setups
You only need one simple HTTPS redirect, not several stacked together.
Suggested setup
- Turn ON “Always Use HTTPS”
- Remove any extra Page Rules that also redirect
http://*example.com/*tohttps://example.com/$1 - Remove unnecessary forwarding rules in Redirect Rules if they duplicate HTTPS redirects
Keeping HTTPS forcing in one place at the edge is cleaner and avoids loops when the origin also checks HTTPS correctly.
4. Fix Laravel behind Cloudflare (trust HTTPS correctly)
Laravel decides whether a request is HTTPS using $request->isSecure() and the server’s HTTPS variable. Behind Cloudflare, the connection from Cloudflare to your server might be plain HTTP, even though the visitor sees HTTPS.
You must tell Laravel to trust the X-Forwarded-Proto / CF-Visitor headers.
4.1 Enable the TrustProxies middleware correctly
Laravel already has App\Http\Middleware\TrustProxies. Make sure it’s active in app/Http/Kernel.php (it is by default in the web group).
Then in app/Http/Middleware/TrustProxies.php, use:
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware; // Laravel < 7
// or use Illuminate\Http\Middleware\TrustProxies as Middleware; in newer versions
class TrustProxies extends Middleware
{
protected $proxies = '*';
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
$proxies = '*' tells Laravel to trust all proxies (including Cloudflare), and HEADER_X_FORWARDED_ALL makes it respect the forwarded protocol.
4.2 Remove or adjust manual HTTPS redirects in Laravel
Many apps have something like this in AppServiceProvider or middleware:
if (app()->environment('production')) {
URL::forceScheme('https');
}
This is fine if TrustProxies is configured correctly. Laravel then sees the real client scheme and does not create loops.
But if TrustProxies is wrong or SSL mode is Flexible, Laravel may think every request is HTTP and keep redirecting.
If you suspect this, temporarily comment out URL::forceScheme('https') and test. If the loop disappears, fix TrustProxies and your SSL mode, then re-enable the force https line.
4.3 Check .htaccess or Nginx redirects
On Apache (Laravel under public/):
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Behind Cloudflare, HTTPS might be off even though the visitor sees HTTPS. A safer rule is:
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
On Nginx, inside the server block:
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
This way, your origin only redirects when the original client is not already on HTTPS.
5. Fix WordPress behind Cloudflare
WordPress also needs to know when a request is truly HTTPS.
5.1 Force SSL the right way in wp-config.php
Add this near the top of wp-config.php (just above /* That's all, stop editing! */):
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
define('FORCE_SSL_ADMIN', true);
This tells WordPress “treat it as HTTPS when Cloudflare says so”. That prevents loops when admin or login URLs are forced to HTTPS.
Avoid hardcoding the site URLs with http and then using plugins to force https at the same time.
5.2 Update WordPress and Site Address URLs
In Settings → General (or directly in the DB):
- WordPress Address (URL)
- Site Address (URL)
Set both to https://your-domain.com.
If you cannot reach the admin, you can set them in wp-config.php as a temporary fix:
define('WP_HOME', 'https://your-domain.com');
define('WP_SITEURL', 'https://your-domain.com');
Once you log in and save them in the UI, you can remove these defines if you like.
5.3 Remove duplicate HTTPS plugins or redirects
If you use plugins like Really Simple SSL or other redirect/SEO plugins:
- Check they are not creating extra redirects on top of Cloudflare’s “Always Use HTTPS”.
- Ideally, let Cloudflare handle HTTP→HTTPS and let WordPress just know the site is HTTPS (through the config above).
You generally do not need three different layers all forcing HTTPS.
6. Clear all caches and cookies
Old redirects can be cached by:
- Cloudflare (edge cache)
- WordPress/Laravel caching plugins
- Browser cookies and cache
Do this after you adjust settings:
- Purge Cloudflare cache (“Purge Everything”)
- Clear any WordPress/Laravel plugin cache (Redis, page cache, etc.)
- Open the site in an incognito/private tab or clear cookies for that domain
If the loop is gone in private mode but still appears in normal mode, cookies were part of the problem.
7. Quick Laravel example config behind Cloudflare
Here’s a minimal, safe combo for a Laravel app running HTTPS through Cloudflare:
.env:
APP_URL=https://example.com
app/Http/Middleware/TrustProxies.php:
protected $proxies = '*';
protected $headers = Request::HEADER_X_FORWARDED_ALL;
AppServiceProvider:
public function boot()
{
if (app()->environment('production')) {
\Illuminate\Support\Facades\URL::forceScheme('https');
}
}
Server config: no extra weird redirect loops, optionally a simple HTTP→HTTPS redirect that checks X-Forwarded-Proto as shown earlier.
Cloudflare: SSL mode set to Full (strict), “Always Use HTTPS” enabled, no duplicate HTTPS page rules.
8. Quick WordPress example config behind Cloudflare
For a typical WordPress site:
wp-config.php:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
define('FORCE_SSL_ADMIN', true);
define('WP_HOME', 'https://example.com');
define('WP_SITEURL', 'https://example.com');
Cloudflare: Full/Full Strict SSL, “Always Use HTTPS” on, minimal extra redirect rules.
Plugins: avoid multiple HTTPS/redirect plugins all trying to be clever at once.
9. Quick checklist
When you hit ERR_TOO_MANY_REDIRECTS after forcing HTTPS with Cloudflare on Laravel or WordPress:
- Set Cloudflare SSL mode to Full or Full (strict), not Flexible if possible
- Use only one HTTPS redirect (prefer Cloudflare’s “Always Use HTTPS”)
- For Laravel, configure
TrustProxiesand avoid naive HTTPS redirects that ignoreX-Forwarded-Proto - For WordPress, set
WP_HOME/WP_SITEURLtohttps://and mapHTTP_X_FORWARDED_PROTOtoHTTPSinwp-config.php - Remove duplicate HTTPS redirects in
.htaccess, Nginx, plugins, and page rules - Purge Cloudflare and app caches, then test in an incognito window
Once both Cloudflare and your origin agree on when a request is already secure, the redirect loop stops and your HTTPS site loads normally.