Okay, here is a blog post draft covering the problem and solution you experienced with Cloudflare Flexible SSL, Nginx, and WordPress.
Navigating the Redirect Loop: Fixing Cloudflare Flexible SSL with WordPress and Nginx
Running WordPress behind a reverse proxy like Nginx, especially when using Cloudflare for performance and security, is a common and powerful setup. One popular configuration is using Cloudflare’s “Flexible” SSL mode, which encrypts traffic between the visitor and Cloudflare, but sends unencrypted HTTP traffic from Cloudflare to your origin server (your VPS with Nginx).
While seemingly straightforward, this setup often leads to a frustrating issue: the dreaded “too many redirects” error or persistent mixed content warnings in WordPress. If you’ve just set this up and suddenly can’t access your WP Admin dashboard or your site looks broken, you’re in the right place.
Let’s break down why this happens and how to fix it.
The Problem: WordPress is Confused About HTTPS
Here’s the typical flow of a request in your setup:
- A visitor requests
https://yourdomain.com
in their browser. - Cloudflare intercepts the request, handles the SSL handshake, and serves content from its cache if available.
- If the request needs to go to your server (the origin), Cloudflare makes a request to your VPS using HTTP. So, it connects to
http://[your_vps_ip]:80
. - Your Nginx server, listening on port 80, receives this HTTP request.
- Nginx acts as a reverse proxy, forwarding the request internally (via HTTP) to your Dockerized WordPress instance, typically on a port like 8090 (
http://localhost:8090
orhttp://0.0.0.0:8090
). - Your WordPress instance receives an HTTP request from Nginx.
Okay, here is a blog post draft covering the problem and solution you experienced with Cloudflare Flexible SSL, Nginx, and WordPress.
Navigating the Redirect Loop: Fixing Cloudflare Flexible SSL with WordPress and Nginx
Running WordPress behind a reverse proxy like Nginx, especially when using Cloudflare for performance and security, is a common and powerful setup. One popular configuration is using Cloudflare’s “Flexible” SSL mode, which encrypts traffic between the visitor and Cloudflare, but sends unencrypted HTTP traffic from Cloudflare to your origin server (your VPS with Nginx).
While seemingly straightforward, this setup often leads to a frustrating issue: the dreaded “too many redirects” error or persistent mixed content warnings in WordPress. If you’ve just set this up and suddenly can’t access your WP Admin dashboard or your site looks broken, you’re in the right place.
Let’s break down why this happens and how to fix it.
The Problem: WordPress is Confused About HTTPS
Here’s the typical flow of a request in your setup:
- A visitor requests
https://yourdomain.com
in their browser. - Cloudflare intercepts the request, handles the SSL handshake, and serves content from its cache if available.
- If the request needs to go to your server (the origin), Cloudflare makes a request to your VPS using HTTP. So, it connects to
http://[your_vps_ip]:80
. - Your Nginx server, listening on port 80, receives this HTTP request.
- Nginx acts as a reverse proxy, forwarding the request internally (via HTTP) to your Dockerized WordPress instance, typically on a port like 8090 (
http://localhost:8090
orhttp://0.0.0.0:8090
). - Your WordPress instance receives an HTTP request from Nginx.
The core issue is that WordPress, by default, looks at the immediate incoming connection protocol. When running behind Cloudflare Flexible and Nginx proxying HTTP, WordPress sees http
.
However, your WordPress Site Address and Home URL settings (which you likely updated to https://yourdomain.com
) tell WordPress the site should be served over HTTPS.
This creates a conflict:
- WordPress receives HTTP.
- It checks its settings and sees it should be HTTPS.
- It tries to redirect the visitor’s browser to the HTTPS version.
- Cloudflare gets the redirect, makes another HTTP request to your origin… and the loop continues endlessly.
Mixed content happens because while the page might load via HTTPS (thanks to Cloudflare), WordPress generates internal links, script/CSS URLs, and image paths using http://
because it thinks it’s running on HTTP.
The Analysis: Passing the Original Protocol Information
Nginx configurations for reverse proxies often include headers like X-Forwarded-Proto $scheme;
. The $scheme
variable in Nginx reflects the protocol Nginx received. In the case of Cloudflare Flexible, Nginx receives HTTP, so $scheme
is http
. Passing X-Forwarded-Proto: http
to WordPress doesn’t help WordPress realize the original request from the visitor was HTTPS.
Cloudflare provides this crucial information in other headers, specifically the CF-Visitor
header (sent as HTTP_CF_VISITOR
in PHP’s $_SERVER
array). This header contains a JSON object, like {"scheme":"https"}
, indicating the protocol the visitor used to connect to Cloudflare.
The solution lies in telling WordPress to look at this header to determine the original scheme, rather than just relying on the immediate connection protocol or a misleading X-Forwarded-Proto
from Nginx in this specific Cloudflare Flexible scenario.
The Solution: Configuring WordPress to Trust Cloudflare’s Headers
We need to modify your WordPress configuration file (wp-config.php
) to read and interpret the HTTP_CF_VISITOR
header.
Assuming your Nginx is already configured to listen on port 80 and proxy to your WordPress container (your provided config is suitable for this part):
Nginx:
server {
listen 80; # Correctly listens for HTTP from Cloudflare Flexible
server_name devslinger.fyi; # Your domain
location / {
proxy_pass http://0.0.0.0:8090; # Proxies to your WordPress backend (adjust address if needed)
# Standard headers - essential for correct proxying
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
# While set here, X-Forwarded-Proto $scheme; will be 'http' in this setup.
# WordPress needs to look at Cloudflare's specific headers instead.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off; # Recommended for proxies
}
# Add other locations for specific needs (e.g., /nginx_status)
}
Now, let’s apply the fix in wp-config.php
:
Step 1: Edit wp-config.php
Locate the wp-config.php
file in the root of your WordPress installation. This might be within your Docker volume or image. Open it for editing.
Step 2: Add the Cloudflare Detection Code
Insert the following code snippet before the line that says /* That's all, stop editing! Happy publishing. */
. Placing it near the top, after the initial <?php
tag, is a good practice.
<?php
/**
* The base configuration for WordPress
*
* (Rest of default comments...)
*/
// --- BEGIN Cloudflare Flexible SSL Fix ---
// Detect original protocol from Cloudflare's header
if (isset($_SERVER['HTTP_CF_VISITOR'])) {
$visitor_data = json_decode($_SERVER['HTTP_CF_VISITOR']);
if (isset($visitor_data->scheme) && $visitor_data->scheme === 'https') {
$_SERVER['HTTPS'] = 'on';
}
}
// Fix REMOTE_ADDR to show the correct visitor IP behind proxies like Cloudflare/Nginx
if (isset($_SERVER['HTTP_X_REAL_IP'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Fallback check if X-Real-IP isn't present (less common with Nginx config above)
$_SERVER['REMOTE_ADDR'] = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
}
// --- END Cloudflare Flexible SSL Fix ---
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php'; // This line must be AFTER the fix
/* That's all, stop editing! Happy publishing. */
Explanation of the Code:
- It checks if the
HTTP_CF_VISITOR
header exists (Cloudflare adds this). - It decodes the JSON value to access the visitor data.
- It checks if the
scheme
within that data ishttps
. - If it is, it sets
$_SERVER['HTTPS']
to'on'
. This is the critical step that tells WordPress the connection is secure, even though the immediate connection from Nginx is HTTP. - The
$_SERVER['REMOTE_ADDR']
fix ensures WordPress sees the actual visitor’s IP address, not the IP of the Nginx proxy or Cloudflare server.
Step 3: Update WordPress Site URLs in Settings
If you haven’t already, go to your WordPress Admin dashboard Settings > General.
- Set WordPress Address (URL) to
https://yourdomain.com
- Set Site Address (URL) to
https://yourdomain.com
Save the changes.
What if You’re Locked Out by the Redirect Loop?
If you applied Step 3 before Step 2 (or Step 2 didn’t work initially) and you’re stuck in a redirect loop preventing dashboard access, you’ll need to revert the URLs in the database:
- Access your WordPress database using a tool like phpMyAdmin, Adminer, or the command line.
- Find the
wp_options
table (the table prefix might be different, e.g.,xyz_options
). - Locate the rows with
option_name
equal tositeurl
andhome
. - Change their
option_value
back tohttp://yourdomain.com
. - Save the changes. You should now be able to access your dashboard again (likely via HTTP, possibly with mixed content).
- Now, perform Step 1 (add the correct
wp-config.php
code) and then re-perform Step 3 (update URLs to HTTPS in settings).
Step 4: Clear Caches
After applying the fix and updating settings:
- Clear your browser’s cache.
- Purge the cache for your site within your Cloudflare dashboard.
Troubleshooting:
- Check
wp-config.php
syntax: A missing semicolon or misplaced character inwp-config.php
will cause a critical error. Check your server logs if the site goes down entirely. - Code Placement: Ensure the code is strictly before the
require_once ABSPATH . 'wp-settings.php';
line. - Plugin Conflicts: Rarely, a plugin (especially security or other SSL-related plugins) might interfere. If the issue persists, try temporarily deactivating plugins (you might need to do this via the database or file system if locked out).
- Cloudflare Page Rules: Double-check that you don’t have any conflicting Cloudflare Page Rules (like a custom redirect that interferes with the admin path).
A Note on Security
While Flexible SSL is easy to set up, remember that the traffic between Cloudflare and your VPS is not encrypted. For better security, consider upgrading to Cloudflare’s “Full” or “Full (Strict)” SSL modes. These require you to install an SSL certificate on your origin server (your VPS), but ensure the entire connection path is encrypted. The wp-config.php
fix discussed here is specifically for the Flexible SSL mode.
Conclusion
The “too many redirects” error with Cloudflare Flexible SSL and WordPress behind Nginx is a classic problem stemming from WordPress’s inability to see the original HTTPS connection. By adding a simple snippet to wp-config.php
that instructs WordPress to look at Cloudflare’s specific HTTP_CF_VISITOR
header, you can correctly inform WordPress about the secure connection, resolve redirect loops, and eliminate mixed content issues.
Happy developing!