Hi!

I found out that when we use nginx before apache, and when we go to the main page (example.com), nginx go to apache at index.php (example.com/index.php) page, and then globalredirect start an infinite redirection loop in lines 92-107 of globalredirect.module:

  // Do a check if this is a front page
  if (drupal_is_front_page()) {
    // Redirect if the current request does not refer to the front page in the
    // configured fashion (with or without a prefix)
    if ($request_path != $prefix) {
      drupal_goto('', $options, 301);
    }
    elseif ($settings['nonclean_to_clean'] &&
            ((bool)variable_get('clean_url', 0)) &&
            (strpos(request_uri(), '?q=') || strpos(request_uri(), 'index.php'))) {
      drupal_goto('', $options, 301);
    }
    // If we've got to this point then we're on a front page with a VALID
    // request path (such as a language-prefix front page such as '/de')
    return;
  }

Redirect starts in line 97: drupal_goto('', $options, 301);

Here, the condition if ($request_path != $prefix) becomes true, because $request_path='index.php', and $prefix is empty line. Options array is (in my case):

fragment (String, 0 characters )
query (NULL)
absolute (Boolean) FALSE
alias (Boolean) FALSE
prefix (String, 0 characters )
external (Boolean) FALSE

May be there is a good way to solve that problem?

Comments

wizonesolutions’s picture

Status: Active » Postponed (maintainer needs more info)

This is almost definitely due to your nginx configuration. Troubleshooting that is beyond the scope of this issue queue. However, google proxy_redirect and go to #nginx on Freenode and someone can probably help you.

Using curl -v http://example.com is a great way to see exactly what's happening.

Make sure you try the latest -dev version before reporting bugs as well.

andyceo’s picture

Title: Redirect loop if use nginx before apache (proxy) » Redirect loop on frontpage if use nginx before apache (proxy)
Version: 7.x-1.4 » 7.x-1.x-dev
Status: Postponed (maintainer needs more info) » Closed (works as designed)

And finally, the problem is clear enough for me and solved.

I also reproduce at 7.x-1.5 version of this module:

if (isset($_REQUEST['q']) && $_REQUEST['q'] != $prefix) {
  drupal_goto('', $query_string, NULL, 301);
}
elseif ($settings['nonclean_to_clean'] &&
        ((bool)variable_get('clean_url', 0)) &&
        (strpos(request_uri(), '?q=') || strpos(request_uri(), 'index.php'))) {
  drupal_goto('', $query_string, NULL, 301);
}

strpos(request_uri(), 'index.php') always become TRUE.

The reason is that nginx does an internal redirect to "/index.php" file, when recieve query to site root "/".

nginx has directive "index", that works similar to Apache "DirectoryIndex" directive.

When nginx recieve "/" request, it construct '/index.php' accordingly with "index" directive and send it to backend. See http://nginx.org/en/docs/http/ngx_http_index_module.html#index for more information about "index" directive.

At backend, GlobalRedirect find that user requests "/index.php" and make real redirection through user's browser back to "/". Here is the loop.

As for Apache, it pass to PHP the uri before rewrite rule. In other words, if Apache recieve "/" query, and there is "RewriteCondition" or "DirectoryIndex" directives to "/index.php", it execute directive, but PHP's variable $_SERVER['REQUEST_URI'] will hold actual URI "/".

My Apache settings is classic, and Apache use Drupal .htaccess file.

And the strangest thing is that on Ubuntu 10.04 everything was fine, but when I upgraded to 12.04, this problem appear. Seems like old nginx versions didn't make internal redirects.

nginx has the following settings:

nginx.conf:

user www-data;
worker_processes  2;
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    access_log	/var/log/nginx/access.log;
    sendfile        on;
    keepalive_timeout  65;
    tcp_nodelay        on;
    gzip  on;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";
    index index.html index.php;
    upstream backend {
      server 127.0.0.1:8080;
    }
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

proxy.conf:

proxy_redirect          off;
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    50m;
client_body_buffer_size 128k;
proxy_connect_timeout   10;
proxy_send_timeout      10;
proxy_read_timeout      300;
proxy_buffers           32 4k;

sites-available/drupal6:

In this file changes was made to solve the problem.

server {
listen   80;
server_name drupal6.local www.drupal6.local;

  // !!! This location I was have to create to solve the problem with
  // !!! GlobalRedirect module
  location = / {
       proxy_pass	http://backend/; // !!! look carefully - there is trailing slash
       include	/etc/nginx/proxy.conf;
  }

  location ~ \.php$ {
      proxy_pass  http://backend;
      include     /etc/nginx/proxy.conf;
  }

  location @apache {
      proxy_pass  http://backend;
      include     /etc/nginx/proxy.conf;
  }

  log_not_found off;
  error_page 404 403 = @apache;

  location ~ /\.ht {
      deny  all;
  }
}