How to Catch All Unmatched Routes in Nginx with Location Block Priority


2 views

When handling web requests, Nginx processes location blocks in a specific order of priority:

  1. Exact matches (=)
  2. Prefix matches (^~)
  3. Regular expressions (~ and ~*)
  4. Standard prefixes

To handle all unmatched routes, simply add this as your final location block:

location / {
    # Your catch-all handling logic here
    return 301 https://www.google.de;
    # Alternative options:
    # return 404;
    # proxy_pass http://backend;
}

Here's a full server block demonstrating the pattern:

server {
    listen 80;
    server_name example.com;

    location /api/v1 {
        proxy_pass http://api_backend;
    }

    location /static {
        root /var/www;
        expires 30d;
    }

    location /admin {
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }

    location / {
        return 301 https://www.google.de;
        # You could also:
        # - Serve a custom 404 page
        # - Redirect to maintenance page
        # - Log suspicious requests
    }
}

For more complex routing needs, you can combine regex patterns:

location ~* \.(jpg|jpeg|png|gif)$ {
    root /var/www/images;
}

location ~* \.(css|js)$ {
    root /var/www/assets;
    expires 1y;
}

location / {
    # Catch everything else
    try_files $uri $uri/ =404;
}
  • Order matters - the first matching location wins
  • Use "=" for exact matches when needed
  • Prefix ^~ stops regex evaluation
  • Named locations (@) can be useful for error handling

While catch-all locations are convenient, consider:

map $uri $is_valid_route {
    default 0;
    ~^/valid-path 1;
    ~^/another-valid 1;
}

server {
    # ...
    if ($is_valid_route) {
        proxy_pass http://backend;
    }

    location / {
        return 404;
    }
}

Add this to debug which location matches requests:

location / {
    add_header X-Location-Match "catch-all";
    # ...
}

location /special {
    add_header X-Location-Match "special";
    # ...
}

Then check response headers to verify matching behavior.


When configuring Nginx server blocks, you'll often need to handle requests that don't match any of your defined location blocks. This is particularly useful for:

  • Redirecting undefined routes to a maintenance page
  • Implementing custom 404 handling
  • Preventing access to unspecified paths
  • Creating fallback mechanisms

The simplest way to catch unmatched locations is by placing a location / block at the end of your configuration:

server {
    listen 80;
    server_name example.com;
    
    location /api {
        # API specific configuration
    }
    
    location /admin {
        # Admin panel configuration
    }
    
    location / {
        # This will catch all other requests
        return 301 https://www.google.com;
    }
}

Remember that Nginx processes location blocks in a specific order:

  1. Exact matches (location = /path)
  2. Prefix matches with ^~
  3. Regular expressions (~ or ~*)
  4. Standard prefix matches

The last location / acts as a catch-all because prefix matches have lower priority than other match types.

For more control, you can use regex to exclude certain paths:

server {
    # ... other configurations ...
    
    location ~ ^/(images|css|js)/ {
        # Handle static assets normally
        try_files $uri =404;
    }
    
    location / {
        # Catch-all for non-static requests
        if ($request_uri !~* "\.(jpg|jpeg|png|gif|css|js)$") {
            return 301 https://alternative-site.com$request_uri;
        }
    }
}

Here are three common use cases with their implementations:

# Case 1: Simple redirect
location / {
    return 301 https://fallback.example.com;
}

# Case 2: Custom 404 page
location / {
    try_files $uri $uri/ /custom_404.html;
    error_page 404 /custom_404.html;
}

# Case 3: Proxy pass to another service
location / {
    proxy_pass http://backend-service;
    proxy_set_header Host $host;
}

When using catch-all locations:

  • Place static asset handling before the catch-all
  • Use try_files efficiently to avoid unnecessary checks
  • Consider using map directives for complex routing logic
  • Benchmark your configuration with tools like ab or wrk

If your catch-all isn't working:

  1. Check the order of location blocks
  2. Verify there are no conflicting regex matches
  3. Test with curl -v to see request handling
  4. Examine Nginx error logs (/var/log/nginx/error.log)