DEV Community

How to Fix WordPress "Too Many Redirects" in Docker behind Reverse Proxy

📖 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 or off.
  • WordPress sees that its configured site URL is HTTPS, thinks the visitor accessed via insecure HTTP, and responds with an HTTP 301 Moved Permanently directing back to https://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 is 80.
  • 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.

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.