Knowledge

nginx rewrite or internal redirection cycle

#Nginx

This error means nginx kept redirecting a request back to itself until it gave up. Almost always a try_files directive that loops, producing a 500 error.

Published by Mark van Eijk on June 23, 2026 · 1 minute read

  1. About the error
  2. Why do I see this error
  3. Solution
  4. Use the standard Laravel/PHP try_files
  5. Check the root actually contains index.php

About the error

The page returns a 500 and the nginx error log shows:

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

nginx tried to resolve a request, that resolution pointed at another location, which pointed back, and so on. After 10 internal redirects nginx assumes a loop and aborts with a 500.

Why do I see this error

The classic cause is a try_files that, when nothing matches, falls back to a target that itself triggers the same try_files again. For a PHP app it usually means:

  • The fallback file (index.php) doesn't exist at the expected path, so the fallback re-enters the same block.
  • The root is wrong, so nginx never finds the real file and keeps redirecting.
  • A try_files pointing at a named location or URI that loops back.

Solution

Use the standard Laravel/PHP try_files

A correct front-controller setup looks like this. Note the $uri and $uri/ are tried first, and the final fallback passes the path as a query string rather than re-requesting a file:

server {
    root /var/www/html/public;
    index index.php;

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

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }
}

Check the root actually contains index.php

The most common real cause is a wrong root. If /var/www/html/public/index.php doesn't exist, the fallback can never resolve and loops:

ls -l /var/www/html/public/index.php

Point root at the directory that genuinely contains the front controller (for Laravel that's public, not the project root).

Validate and reload after fixing:

nginx -t && systemctl reload nginx

For a deeper look at how try_files resolves requests, see the nginx try_files article. A redirect loop that happens in the browser rather than inside nginx shows up as ERR_TOO_MANY_REDIRECTS instead.

Subscribe to our newsletter

Do you want to receive regular updates with fresh and exclusive content to learn more about web development, hosting, security and performance? Subscribe now!