Support » How-To and Troubleshooting » [Resolved] Nginx php-fpm multisite "too many redirects"

[Resolved] Nginx php-fpm multisite "too many redirects"

  • OK. I’m almost ready to throw the towel in on this one, so I’m hoping some of you clever folks out there can help me.

    I’ve got a wordPress multisite setup running on Nginx… or I should say ‘HAD’ a WordPress multisite setup running on Nginx. At some stage last weekend, I suddenly found myself unable to login to the default domain –let’s call it mydomain.com. I get the dreaded “The webpage at mydomain.com has resulted in too many redirects” error [insert equivalent wording for your browser of choice]. I am still able to login to both the other sites I have running on the setup; site1.mydomain.com and site2.mydomain.com, however that’s not much good to me as obviously all the network settings, controls, etc. are under the default mydomain.com login.

    I’m not sure exactly when the problem arose. I’ve been working on theming one of the subdomains and hadn’t logged into the default domain for a few days, but everything was working fine up until a week or so ago. Since then, I’ve updated WordPress to the current version [3,5,2] and also updated a couple of plugins, as and when they required it. I’ve also ‘slimmed down a few config files, after reading various articles but this mostly involved removing old commented out code, extracting certain sections into external files and swapping php-cgi for php-fpm, as my PHP backend. Chances are that somewhere in that morass of small insignificant changes, I’ve done *something* which has broken multisite, but I’m sure I’ve tried practically every suggestion I’ve found online, when duckduckgoing this problem, but nothing seems to work. Diagnosis isn’t helped by the fact that neither Nginx, php-fpm or WordPress [with debug set to ‘true’] are logging anything untoward. As far as they’re concerned everything is hunky-dory, yet still I can’t load my default domain, thanks to these ‘redirect loop’ errors.

    anyway, enough waffling. Here are the relevant config file excerpts:

    First off, my wp-congfig.php file:

    define('DB_NAME', 'blah blah');
    /* MySQL database username */
    define('DB_USER', 'wordpress');
    /* MySQL database password */
    define('DB_PASSWORD', 'blah blah');
    /* MySQL hostname */
    define('DB_HOST', 'localhost:/var/run/mysqld/mysqld.sock');
    define('DB_CHARSET', 'utf8');
    /* Authentication Unique Keys and Salts. */
    * WordPress Database Table prefix.
    $table_prefix  = 'WP_';
    /* WordPress Localized Language, defaults to English. */
    define('WPLANG', 'en_IE');
    /*For developers: WordPress debugging mode */
    define('WP_DEBUG', true);
    define('WP_DEBUG_DISPLAY', false);
    define('WP_DEBUG_LOG', true);
    define( 'NOBLOGREDIRECT', 'http://mydomain.com' );
    /* multisite */
    define('WP_ALLOW_MULTISITE', true);
    define('MULTISITE', true);
    define('SUBDOMAIN_INSTALL', true);
    define('DOMAIN_CURRENT_SITE', 'mydomain.com');
    define('PATH_CURRENT_SITE', '/');
    define('SITE_ID_CURRENT_SITE', 1);
    define('BLOG_ID_CURRENT_SITE', 1);
    /** Cookies –commented out on orders of WPMU domain mapping plugin below **/
    /* define('COOKIE_DOMAIN', 'mydomain.com'); */
    /** WordPress MU Domain Mapping plugin **/
    define( 'SUNRISE', 'on' );
    /* That's all, stop editing! Happy blogging. */
    /* Absolute path to the WordPress directory. */
    if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');
    /* Sets up WordPress vars and included files. */
    require_once(ABSPATH . 'wp-settings.php');

    Next, the Nginx config file for the default domain:

    map $http_host $blogid
            default 1;
            mydomain.com 1;
    #       normalski
            listen   80 default_server;
            server_name  www.mydomain.com;
            rewrite ^/(.*) http://mydomain.com/$1 permanent;
            rewrite ^ http://mydomain.com$request_uri? permanent;
            listen 80;
            server_name mydomain.com;
            root /var/www/wordpress;
            access_log /var/log/mydomain.com-access.log;
            error_log /var/log/nginx/mydomain.com-error.log;
            include /etc/nginx/conf.d/W3TC.conf;
            include /etc/nginx/conf.d/restrictions.conf;
            include /etc/nginx/conf.d/wordpress-multisite.conf;
            include /etc/nginx/conf.d/php-fpm.conf;
    #       SSL
            listen 443 ssl;
            server_name mydomain.com;
            ssl_certificate /etc/ssl/certs/mydomain.com.crt;
            ssl_certificate_key /etc/ssl/private/mydomain.com.key;
            root /var/www/wordpress;
            access_log /var/log/nginx/mydomain.com-access.log;
            error_log /var/log/nginx/mydomain.com-error.log;
            include /etc/nginx/conf.d/W3TC.conf;
            include /etc/nginx/conf.d/restrictions.conf;
            include /etc/nginx/conf.d/wordpress-multisite.conf;
            include /etc/nginx/conf.d/php-fpm.conf;

    As you can see, the stripped down Nginx config file ‘includes’ several external config files. Here is the content of those, in the order they’re included:


    #2013-07-07 Taken from: https://codex.wordpress.org/Nginx
    location ~ \.(ttf|otf|eot|woff)$ {
       add_header Access-Control-Allow-Origin "*";
    # END W3TC CDN
    set $cache_uri $request_uri;
    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
            set $cache_uri 'null cache';
    if ($query_string != "") {
            set $cache_uri 'null cache';
    # 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 $cache_uri 'null cache';
    # 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 $cache_uri 'null cache';


    # Global restrictions configuration file.
    # Designed to be included in any server {} block.</p>
    location = /favicon.ico
            log_not_found off;
            access_log off;
    location = /robots.txt
            allow all;
            log_not_found off;
            access_log off;
    # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~ /\.
     deny all;
    # Deny access to any files with a .php extension in the uploads directory
    # Works in sub-directory installs and also in multisite network
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~* /(?:uploads|files)/.*\.php$
     deny all;


    2013-070-07 Taken from: https://codex.wordpress.org/Nginx
    #WordPress multisite subdirectory rules.
    # Designed to be included in any server {} block.
    # This order might seem weird - this is attempted to match last if rules below fail.
    # http://wiki.nginx.org/HttpCoreModule
    location / {
            index index.php;
    #       try_files $uri $uri/ /index.php?$args;
    #       changed to this, coz of W3TC
            try_files /wp-content/w3tc-$host/pgcache/$cache_uri/_index.html $uri $uri/ /index.php?$args;
    # Directives to send expires headers and turn off 404 error logging.
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
            expires 24h;
            log_not_found off;
    location ~ ^/[_0-9a-zA-Z-]+/files/(.*)$ {
            try_files /wp-content/blogs.dir/$blogid/files/$2 /wp-includes/ms-files.php?file=$2 ;
            access_log off; log_not_found off; expires max;
    #avoid php readfile()
    location ^~ /blogs.dir {
            alias /var/www/example.com/htdocs/wp-content/blogs.dir ;
            access_log off; log_not_found off;      expires max;
    # Uncomment one of the lines below for the appropriate caching plugin (if used).
    #include global/wordpress-ms-subdir-wp-super-cache.conf;
    include /etc/nginx/conf.d/W3TC.conf;
    # Rewrite multisite '.../wp-.*' and '.../*.php'.
    if (!-e $request_filename) {
            rewrite /wp-admin$ $scheme://$host$uri/ permanent;
            rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
            rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;


    #2013-07-16: Common php5-fpm PHP-handling config.
    # php-fpm config file is at: /etc/php5/fpm/pool.d/www.conf
    location ~ \.php
            # for security reasons the next line is highly encouraged
            try_files $uri =404;
            fastcgi_param  QUERY_STRING       $query_string;
            fastcgi_param  REQUEST_METHOD     $request_method;
            fastcgi_param  CONTENT_TYPE       $content_type;
            fastcgi_param  CONTENT_LENGTH     $content_length;
            fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
            fastcgi_param  SCRIPT_FILENAME    $request_filename;
            fastcgi_param  REQUEST_URI        $request_uri;
            fastcgi_param  DOCUMENT_URI       $document_uri;
            fastcgi_param  DOCUMENT_ROOT      $document_root;
            fastcgi_param  SERVER_PROTOCOL    $server_protocol;
            fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
            fastcgi_param  SERVER_SOFTWARE    nginx;
            fastcgi_param  REMOTE_ADDR        $remote_addr;
            fastcgi_param  REMOTE_PORT        $remote_port;
            fastcgi_param  SERVER_ADDR        $server_addr;
            fastcgi_param  SERVER_PORT        $server_port;
            fastcgi_param  SERVER_NAME        $server_name;
            # If using a unix socket...
            # OSX version:
            #fastcgi_pass unix:/tmp/php-fpm.sock;
            # Debian version
            fastcgi_pass unix:/var/run/php5-fpm.sock;

    So, there you have it. I’m sure i’m overlooking something so obvious it’ll make me want to bequeath my brain to medical research for investigations into idiocy, but I’ve been staring at these damned config files for so long my head is swimming. Can someone put me out of my misery?

    Thanks in advance!

Viewing 5 replies - 1 through 5 (of 5 total)
  • You may change the error_log level in Nginx to debug and see where the redirect happens (whether it’s happening at the server level or at the application level). You may dig further from there.

    Ah thanks! –good thinking. It never occurred to me that Nginx would have a default logging level.

    However unfortunately, after changing the logging level to “debug” I’m not sure I’m any the wiser. Here’s what I’m seeing in my log files, these three entries repeated over and over. I’ve blanked out some of the personal data with’xxxx’ to protect the innocent:

    2013/07/20 20:53:03 [info] 21697#0: *83 client xx.xxx.143.36 closed keepalive connection
    2013/07/20 20:53:03 [notice] 21697#0: *85 "(/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)" does not match "/", client:xx.xxx.143.36, server: mydomain.com, request: "GET / HTTP/1.1", host: "mydomain.com"
    2013/07/20 20:53:03 [notice] 21697#0: *85 "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in" matches "__utma=1xxxxxxx1.8xxxxxx8.1xxxxxx2.xxxxxx2.1xxxxxx2.1; __utmz=1xxxxxx1.1xxxxxx2.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); wp-settings-1=libraryContent%3Dbrowse%26uploader%3D1%26wplink%3D0%26hidetb%3D0; wp-settings-time-1=1370778996; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_22fxxxxxxxxxxxxxxxxx74f=myname%7Cxxxxxxxxxxxxxxxxxxx81b", client: xx.xxx.143.36, server: mydomain.com, request: "GET / HTTP/1.1", host: "mydomain.com"

    There are only two things I can see that look suspicious here:

    1: The ……does not match “/” part looks like something’s not where nginx thinks it should be, and
    2: The __utma, __utmz and __utmcsr references which seem to be related to Google Analytics, which I haven’t got installed on the site.

    Is there anything else in these logs I’m missing?

    One thing I’ve noticed from the nginx error log is that, even if I try and visit https://mydomain.com, the browser tries to load http://mydomain.com and the log records the request as request: "GET / HTTP/1.1"

    should the request not show in the logs as request: "GET / HTTP/1.1", or is HTTP a generic reference to the protocol and includes HTTPS requests?… and why is the server [apparently] trying to serve up the HTTP version of the page when I request the HTTPS version?

    [As you can probably tell, the intricacies of HTTP server requests are not my strong point!]

    >> Is there anything else in these logs I’m missing?

    Your log doesn’t show any redirect happening at the server level (actually, it doesn’t show any redirect at all). So, the redirects may be happening at the application level or you may have missed the log entry that actually shows the multiple redirects.

    >> is HTTP a generic reference to the protocol and includes HTTPS requests?

    Yes, it is the correct generic reference. Both HTTP and HTTPS requests transfer via different ports in a server. Basically, they are implemented on top of HTTP/1.x . If you’d want to learn more about HTTP, I highly recommend Http: The Definitive Guide .

    Thanks for the help.

    In the end I bit the bullet and: deleted the extra network tables from my database, reconfigured multisite and imported the DB dump again —and everything is [so far!] up and running again.

    Sometimes you realise that starting from scratch is actually a quicker route than trying to effect running repairs!

Viewing 5 replies - 1 through 5 (of 5 total)
  • The topic ‘[Resolved] Nginx php-fpm multisite "too many redirects"’ is closed to new replies.
Skip to toolbar