302 redirect loop with nginx and WordPress

algui91 asked:

I’ve been searching a couple of hours in Serverfault trying to solve this problem but I can not find a solution. What happens is:

I am having a 302 redirect loop using wget in my site, but not using the browser. In my nginx configuration I only have two 301 redirects, not 302. I’ve tried to disable all the plugins from wordpress with no luck.

What could be causing the problem? Below is my nginx config. Some examples with wget:

wget elbauldelprogramador.com
    --2014-10-30 13:10:24--  http://elbauldelprogramador.com/
    Resolving elbauldelprogramador.com (elbauldelprogramador.com)... 
    Connecting to elbauldelprogramador.com (elbauldelprogramador.com)||:80... connected.
    HTTP request sent, awaiting response... 302 Moved Temporarily
    Location: 404 [following]
    --2014-10-30 13:10:25--  http://elbauldelprogramador.com/404
    Reusing existing connection to elbauldelprogramador.com:80.
    HTTP request sent, awaiting response... 302 Moved Temporarily
    Location: 404 [following]
    --2014-10-30 13:10:25--  http://elbauldelprogramador.com/404
    Reusing existing connection to elbauldelprogramador.com:80.
    [...]
    HTTP request sent, awaiting response... 302 Moved Temporarily
    Location: 404 [following]
    20 redirections exceeded.

And the logs in the server:

S.IP - - [30/Oct/2014:13:11:22 +0100] "GET /404 HTTP/1.1" 302 154 "-" "Wget/1.15 (linux-gnu)"
S.IP - - [30/Oct/2014:13:11:22 +0100] "GET /404 HTTP/1.1" 302 154 "-" "Wget/1.15 (linux-gnu)"
S.IP - - [30/Oct/2014:13:11:22 +0100] "GET /404 HTTP/1.1" 302 154 "-" "Wget/1.15 (linux-gnu)"

Nginx config

server {
    #listen 127.0.0.1:81;
    listen 80;
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
#    listen 127.0.0.1:81;
    listen 80;
    server_name example.com 

    port_in_redirect off;
    server_tokens off;
    autoindex off;

    root /path;

    ## Page Speed Module ##
    include global/pagespeed.conf;

    ## Fastcgi cache start ##
    set $no_cache 0;

    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
        set $no_cache 1;
    }
    if ($query_string != "") {
        set $no_cache 1;
    }

    # Don't cache uris containing the following segments
    if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
        set $no_cache 1;
    }

    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $no_cache 1;
    }

    # Deliver 404 instead of 403 "Forbidden"
    error_page 403 = 404;

    include global/restrictions.conf;
    include global/caching.conf;


    # Additional rules go here.
    access_log log/access.log;
    error_log log/error.log warn;

    rewrite ^/sitemap_index.xml$ /index.php?sitemap=1 last;
    rewrite ^/([^/]+?)-sitemap([0-9]+)?.xml$ /index.php?sitemap=$1&sitemap_n=$2 last;

    location = /p/guia-de-desarrollo-android.html {
        rewrite  /p/guia-de-desarrollo-android.html http://example.com/curso-programacion-android/ permanent;
    }

    location = /p/bases-de-datos.html {
        rewrite  /p/bases-de-datos.html http://example.com/bases-de-datos/ permanent;
    }

    location = /feeds/posts/default {
        rewrite /feeds/posts/default http://example.com/feed permanent;
    }

    location = /p/guias-gratuitas.html {
        rewrite /p/guias-gratuitas.html http://example.com/manuales-gratuitos/ permanent;
    }

    # Only include one of the files below.
    include global/wordpress.conf;
    include global/security.conf;

}

include global/wordpress.conf;

#WordPress single blog rules.
# Designed to be included in any server {} block.

#A little something from the Search Overload blog entry
location = /search { 
    limit_req zone=wpsearch burst=3 nodelay;
    try_files $uri /index.php; 
}

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

# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    access_log off; log_not_found off; expires max;
}

# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ .php$ {

    # Zero-day exploit defense.
    # http://forum.nginx.org/read.php?2,88845,page=3
    # Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
    # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine.  And then cross your fingers that you won't get hacked.
    try_files $uri =404;

    fastcgi_split_path_info ^(.+.php)(/.+)$;
    #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

    include fastcgi_params;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass php;

    ##
    # Fastcgi cache
    ##
    fastcgi_cache_bypass $no_cache;
    fastcgi_no_cache $no_cache;
    fastcgi_cache microcache;
    fastcgi_cache_valid 60m;
}

Thanks in advance.

My answer:


You have a mistake in your nginx configuration:

    error_page 403 = 404;

This causes nginx to try to redirect to a document named “404”, which is exactly what is happening.

This should have been written as:

    error_page 403 =404;

Or better yet, it should not be present at all. Sending a blatantly wrong error code is a good way to confuse people (like yourself).


View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.