# Nginx Try_Files Not Working

The try_files directive should gracefully handle missing files and fallback to alternative content, but instead you get 404 errors, infinite redirect loops, or all requests going to the fallback. Understanding how try_files evaluates its arguments and interacts with other directives is critical for proper fallback behavior.

Understanding Try_Files Behavior

  1. 1.try_files checks each path in order:
  2. 2.Checks if file exists (using $uri as path)
  3. 3.Checks if directory exists (using $uri/ as path)
  4. 4.Falls back to the last argument (URI or named location)

Basic example: ``nginx location / { root /var/www/html; try_files $uri $uri/ /index.html; }

  1. 1.Request /about:
  2. 2.Check /var/www/html/about - file? No
  3. 3.Check /var/www/html/about/ - directory? No
  4. 4.Internal redirect to /index.html

Common Cause 1: Order of Arguments Matters

Arguments are checked in sequence; wrong order breaks logic.

Problematic config: ``nginx location / { try_files /index.html $uri $uri/; # Wrong order }

Every request immediately falls back to /index.html. $uri never checked.

Solution: Check specific first, fallback last: ``nginx location / { try_files $uri $uri/ /index.html; }

Common Cause 2: Named Location vs URI Fallback

The last argument behavior differs.

URI fallback (starts internal redirect): ``nginx try_files $uri $uri/ /index.html; # Falls back to /index.html, processed by location matching

Named location fallback: ```nginx try_files $uri $uri/ @fallback;

location @fallback { proxy_pass http://backend; } ```

Named location bypasses normal location matching, goes directly to the named block.

Problematic config: ```nginx location / { try_files $uri $uri/ @backend; }

location @backend { # Named location doesn't inherit settings from parent proxy_pass http://localhost:3000; # Missing proxy_set_header Host $host; } ```

Solution: Configure named location fully: ``nginx location @backend { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }

Common Cause 3: Infinite Redirect Loop

Fallback URI triggers same location block recursively.

Problematic config: ``nginx location / { root /var/www/html; try_files $uri $uri/ $uri.html =404; }

  1. 1.If /about doesn't exist and /about/ doesn't exist:
  2. 2.Check /about.html - doesn't exist
  3. 3.Return 404

This works. But problematic:

nginx
location / {
    try_files $uri $uri/ /;  # / redirects back to this location
}
  1. 1.Request /missing:
  2. 2.Check /missing - no
  3. 3.Check /missing/ - no
  4. 4.Internal redirect to /
  5. 5./ matches same location
  6. 6.Check / - directory exists
  7. 7.Serve index

Worse - actual loop: ```nginx location / { try_files $uri $uri.html /index.html; }

location = /index.html { try_files $uri $uri/ /; # / triggers location / # Loop! } ```

Solution: Ensure fallback doesn't trigger same logic: ``nginx location / { try_files $uri $uri/ =404; # End with 404, not redirect }

Or use named location: ```nginx location / { try_files $uri $uri/ @fallback; }

location @fallback { proxy_pass http://backend; } ```

Common Cause 4: Try_Files with Alias

try_files uses $uri which doesn't account for alias mapping.

Problematic config: ``nginx location /assets/ { alias /var/www/files/; try_files $uri $uri/ =404; }

Request /assets/logo.png: - try_files checks /assets/logo.png using $uri - But file is at /var/www/files/logo.png (alias maps this) - $uri path doesn't match alias path

**Solution: Use $request_filename or adjust logic:** ``nginx location /assets/ { alias /var/www/files/; try_files $request_filename =404; }

$request_filename reflects the actual file path after alias mapping.

Or simpler - alias handles files directly: ``nginx location /assets/ { alias /var/www/files/; # Don't need try_files - alias handles file resolution }

Common Cause 5: Try_Files Ignoring Index Files

Directory fallback doesn't serve index files automatically.

Problematic config: ``nginx location / { root /var/www/html; try_files $uri $uri/ =404; }

  1. 1.Request /docs/ (directory exists):
  2. 2.$uri = /docs/
  3. 3.Check /docs/ - is directory? Yes
  4. 4.Nginx needs to serve directory index
  5. 5.But no index directive set!

Solution: Add index directive: ``nginx location / { root /var/www/html; index index.html index.htm; try_files $uri $uri/ =404; }

Now /docs/ serves /docs/index.html.

Common Cause 6: SPA Routing with API Conflicts

Single-page apps need all routes to hit index.html, but API routes need to bypass.

Problematic config: ```nginx location / { try_files $uri $uri/ /index.html; }

location /api/ { proxy_pass http://backend; } ```

This works, but /api/users hits /api location first.

Problem: ```nginx location / { try_files $uri $uri/ /index.html; }

# API location missing - all /api requests go to index.html ```

Solution: Define API location with priority: ```nginx location ^~ /api/ { proxy_pass http://backend; }

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

^~ ensures /api prefix stops further location searching.

Common Cause 7: Try_Files with Rewrite

Rewrite changes $uri before try_files evaluates.

Problematic config: ``nginx location / { rewrite ^/old/(.*)$ /new/$1 break; try_files $uri $uri/ =404; }

  1. 1.Request /old/page:
  2. 2.Rewrite changes $uri to /new/page
  3. 3.try_files checks /new/page
  4. 4.Works correctly

But with last: ``nginx location / { rewrite ^/old/(.*)$ /new/$1 last; # restarts location matching try_files $uri $uri/ =404; }

Rewrite with last restarts location matching - try_files may not be reached.

Common Cause 8: Try_Files Not Serving Actual File

File exists but 404 returned anyway.

Diagnosis: ```bash # Check if file exists ls -la /var/www/html/about

# Check Nginx error log tail -f /var/log/nginx/error.log ```

Common cause: Permission denied: ``nginx location / { root /var/www/html; try_files $uri $uri/ =404; }

File /var/www/html/about exists, but www-data can't read it.

bash
# Check permissions
ls -la /var/www/html/about
sudo -u www-data cat /var/www/html/about

Solution: Fix permissions: ``bash chmod 644 /var/www/html/about chown www-data:www-data /var/www/html/about

Common Cause 9: Static Files Going to Backend

All requests, including static files, hit the fallback.

Problematic config: ```nginx location / { try_files $uri @backend; # Missing $uri/ for directories }

location @backend { proxy_pass http://backend; } ```

Directories (like /css/) don't exist as files, go directly to backend.

Solution: Include directory check: ```nginx location / { root /var/www/html; try_files $uri $uri/ @backend; }

location @backend { proxy_pass http://backend; } ```

Verification Steps

  1. 1.Test file resolution:
  2. 2.```bash
  3. 3.curl -I http://localhost/about
  4. 4.curl -I http://localhost/about/
  5. 5.curl -I http://localhost/missing
  6. 6.`
  7. 7.Add diagnostic headers:
  8. 8.```nginx
  9. 9.location / {
  10. 10.root /var/www/html;
  11. 11.try_files $uri $uri/ @fallback;

add_header X-Checked-Path $request_filename always; }

location @fallback { add_header X-Fallback "triggered" always; return 200 "fallback"; } ```

  1. 1.Check file existence:
  2. 2.```bash
  3. 3.ls -la /var/www/html/$uri
  4. 4.`
  5. 5.Monitor error log:
  6. 6.```bash
  7. 7.tail -f /var/log/nginx/error.log | grep "open()"
  8. 8.`
  9. 9.Debug internal redirects:
  10. 10.```nginx
  11. 11.error_log /var/log/nginx/debug.log debug;
  12. 12.`

Complete Working Configurations

Static site with fallback: ``nginx location / { root /var/www/html; index index.html; try_files $uri $uri/ $uri.html =404; }

Single-page application: ```nginx # API routes first location ^~ /api/ { proxy_pass http://backend; }

# Static assets location ^~ /static/ { root /var/www/html; expires 1y; }

# SPA fallback location / { root /var/www/html; try_files $uri $uri/ /index.html; } ```

With named location fallback: ```nginx location / { root /var/www/html; index index.html; try_files $uri $uri/ @backend; }

location @backend { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ```

Quick Reference

IssueCauseFix
All requests go to fallbackWrong argument orderPut $uri first
404 on existing filesPermission deniedFix file permissions
Infinite redirect loopFallback triggers same locationUse named location
Alias doesn't work$uri doesn't match alias pathUse $request_filename
Directories return 404No index directiveAdd index index.html
API goes to SPA fallbackLocation priorityUse ^~ for API
Named location incompleteMissing proxy headersConfigure named location fully

try_files requires understanding the argument sequence, fallback behavior, and interaction with other directives. Check order first, then verify permissions and path resolution.