Nginx “Rewrite or Internal Redirection Cycle” Error: Diagnosis and Solutions for Infinite Loop Issues


3 views

The error messages reveal a critical configuration problem where Nginx enters an infinite redirection loop when processing requests for various resources:

rewrite or internal redirection cycle while internally redirecting to "/index.html"

This typically occurs when the server configuration creates circular references in URL processing. The fact that you're seeing requests for unrelated domains suggests either:
1) Your server is catching misconfigured requests
2) The server_name directive isn't properly restricting access

The core issue lies in the try_files directive combined with the catch-all server_name _ configuration:

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

When Nginx can't find a requested file, it keeps falling back to /index.html indefinitely. The wildcard server name makes this server block handle all requests, including those meant for other domains.

Here's an improved configuration that prevents the infinite loop:

server {
    listen 8080;
    listen [::]:8080;
    server_name yourdomain.com www.yourdomain.com;
    
    root /usr/share/nginx/www;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    location = /index.html {
        expires 30d;
        add_header Cache-Control "public";
    }

    # Rest of your configuration...
}

Key improvements:
1) Explicit server_name instead of wildcard
2) Proper fallback to 404 when files don't exist
3) Special handling for index.html

For production environments, consider adding these security measures:

# Block bogus host headers
if ($host !~* ^(yourdomain.com|www.yourdomain.com)$ ) {
    return 444;
}

# Prevent processing of requests with invalid domains
server {
    listen 8080 default_server;
    listen [::]:8080 default_server;
    server_name _;
    return 444;
}

When troubleshooting such issues:

1. Check the request flow with Nginx debugging:

error_log /var/log/nginx/debug.log debug;
rewrite_log on;

2. Verify configuration with:

nginx -t

3. Use curl to test specific scenarios:

curl -v http://localhost:8080/nonexistent-file

The error message you're seeing indicates Nginx has entered an infinite redirection loop when processing requests. This typically occurs when your configuration creates circular patterns in URL rewriting or internal redirects. The key indicators are:

rewrite or internal redirection cycle while internally redirecting to "/index.html"

Your current setup has a critical flaw in the location / block:

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

This configuration creates a loop because:

  1. Nginx first checks if the requested URI exists as a file ($uri)
  2. Then checks if it's a directory ($uri/)
  3. Finally falls back to /index.html

When /index.html is requested, the same rule applies again, creating an endless loop.

Solution 1: Add Exception for Index File

Modify your configuration to exclude the index file from the fallback chain:

location / {
    try_files $uri $uri/ @fallback;
}

location @fallback {
    if (!-e $request_filename) {
        rewrite ^ /index.html break;
    }
}

Solution 2: Use Exact Matching

Alternatively, create a specific location for your index file:

location = /index.html {
    # Directly serve the index file without any redirects
}

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

Solution 3: Debugging the Unexpected Requests

For the strange domains appearing in your logs (qq.com, joesfitness.net), add this security measure:

server {
    listen 8080 default_server;
    server_name _;
    return 444; # This will close the connection for unmatched hostnames
}

Always test your Nginx configuration changes before applying them:

sudo nginx -t

Then reload the configuration:

sudo systemctl reload nginx

Since you're seeing requests from unexpected domains, consider implementing these security measures:

# Block invalid host headers
if ($host !~* ^(yourdomain\.com|www\.yourdomain\.com)$ ) {
    return 444;
}

# Prevent HTTP Host header attacks
server {
    listen 8080;
    server_name "";
    return 444;
}