WordPress redirect loop on nginx + apache reverse proxy

The question:

I am trying to setup a fresh WordPress installation on an nginx + apache reverse proxy configuration. My installation process was as follows:

  1. Installed nginx and apache servers
  2. Configured nginx (conf below) to proxy apache server (listening on port 8080)
  3. Generated let’s encrypt SSL certificate using certbot with nginx plugin
  4. Extracted fresh wordpress installation to apache /var/www/mysite.com, setup file ownership/permissions
  5. Ran wordpress install, generated config and added HTTPS details (conf below)

I intend to only allow access over HTTPS to this site, so I have setup the nginx conf to redirect all traffic to port 443.

/etc/nginx/mysite.com:

server {

    root /var/www/mysite.com;
    index index.php index.html index.htm;

    server_name mysite.com;

    location / {
    try_files $uri $uri/ /index.php;
    }

    location ~ .php$ {

    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme; # scheme: https
    proxy_set_header Host $host;
    proxy_pass http://127.0.0.1:8080;

     }

     location ~ /.ht {
            deny all;
    }

listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
if ($host = mysite.com) {
    return 301 https://$host$request_uri;
} # managed by Certbot


    listen   80;

    server_name mysite.com;
return 404; # managed by Certbot


}

wp-config.php:

<?php

define( 'DB_NAME', 'x' );
...
define( 'NONCE_SALT',       'x' );

$table_prefix = 'wp_';

define( 'WP_DEBUG', false );

if ( $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
{
    $_SERVER['HTTPS']       = 'on';
    $_SERVER['SERVER_PORT'] = '443';
    define('FORCE_SSL_ADMIN', true);
}

if ( isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}

if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', dirname( __FILE__ ) . '/' );
}

require_once( ABSPATH . 'wp-settings.php' );

Using this installation, I can access /wp-admin/ without any issues, however when I try to access the main site I run into a redirect loop. Chrome network console shows this:
Wordpress front page produces endless redirect loop

Anyone have any solutions to this issue? I have tried many solutions I’ve seen across various websites, including some plugins, which claim to manage the SSL page settings for you, to no avail. If you need any more details, please don’t hesitate to ask!

EDIT:
Raw response from each redirect:

HTTP/1.1 301 Moved Permanently
Server: nginx/1.14.0 (Ubuntu)
Date: Sun, 10 Mar 2019 16:35:06 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 0
Connection: keep-alive
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
X-Redirect-By: WordPress
Location: https://example.com/

When I try to request / I get a 301 Moved Permanently response telling me the resource has moved to /, causing the redirect loop.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Issue was caused by nginx serving example.com/index.php while WordPress was redirecting to example.com/, thus causing a redirect loop.

This is the working config I used to fixed the redirect loop:

server {
server_name example.com;
root /var/www/example.com;

index index.php;

listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
        try_files $uri @apache;
}

location ~[^?]*/$ { # proxy directories
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
}

location ~ .php$ { # serve php files
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
}

location @apache { # used by location /
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
}

location ~ /.ht { # Deny access to .htaccess, .htpassword 
        deny all;
}
}
server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

Another thread with more details.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment