📖 Original Reference: Originally published with full architecture diagrams and server configuration templates at alexmaina.dev/wordpress-docker-redirect-loop.
Running WordPress inside Docker behind a reverse proxy (like Nginx Proxy Manager, Traefik, Caddy, or Cloudflare) often leads to the dreaded browser error:
ERR_TOO_MANY_REDIRECTS
The browser gets trapped in an infinite HTTP 301 loop. Here is why this happens and how to permanently fix it in under 60 seconds.
âš¡ The 30-Second Solution
Open your WordPress volume mount and edit wp-config.php. Paste this snippet BEFORE the line /* That's all, stop editing! Happy publishing. */:
// Trust HTTPS termination from your Reverse Proxy
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
$_SERVER['HTTPS'] = 'on';
}
define('WP_HOME', 'https://yourdomain.com');
define('WP_SITEURL', 'https://yourdomain.com');
define('FORCE_SSL_ADMIN', true);
1. Anatomy of the Loop: Why Does it Happen?
In a modern containerized stack:
- The user requests
https://yourdomain.com(encrypted on port 443). - The Reverse Proxy terminates the SSL session (decrypts the traffic) and forwards the request internally to the WordPress container via HTTP on port 80.
- Inside the container, PHP checks
$_SERVER['HTTPS']. Because internal Docker network communication is unencrypted,$_SERVER['HTTPS']is empty oroff. - WordPress sees that its configured site URL is HTTPS, thinks the visitor accessed via insecure HTTP, and responds with an
HTTP 301 Moved Permanentlydirecting back tohttps://yourdomain.com. - The browser follows the redirect, the proxy intercepts it again on port 443, forwards it via port 80, and the cycle repeats infinitely until the browser throws
ERR_TOO_MANY_REDIRECTS.
2. Nginx Reverse Proxy Headers
Ensure your upstream Nginx proxy passes the correct forwarded protocol headers:
server {
listen 443 ssl http2;
server_name yourdomain.com;
location / {
proxy_pass http://wordpress_container:80;
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-Proto $scheme;
}
}
If using Nginx Proxy Manager (NPM):
- Under Details: Scheme is
http, Forward Host is the container name, Port is80. - Under SSL: Enable Force SSL and HTTP/2 Support.
3. The Cloudflare Trap: Flexible vs Full (Strict)
If your DNS is proxied through Cloudflare (orange cloud active):
- Never use Flexible SSL: Flexible instructs Cloudflare to contact your origin server strictly on port 80 (HTTP). If WordPress enforces HTTPS, Cloudflare and your origin will bounce redirects back and forth indefinitely.
- Fix: Change your Cloudflare SSL/TLS encryption mode to Full or Full (Strict).
4. Verification with cURL
Run this terminal command to test the raw HTTP status without browser cache pollution:
curl -ILs -o /dev/null -w "%{http_code} -> %{url_effective}\n" https://yourdomain.com
Expected output:
200 -> https://yourdomain.com/
If you see 20 consecutive 301 -> ... lines, the PHP block was either placed too late in wp-config.php or the reverse proxy is stripping the X-Forwarded-Proto header.
Author: Alessandro Mainardi — Software Developer & Computer Engineering Student @ UniBo. Explore more self-hosting & Docker guides at alexmaina.dev.
Top comments (0)