Location Matching and Routing

Introduction

Nginx routes requests using location blocks. Prefix, exact, and regex matches follow priority rules—getting them wrong sends API traffic to static files or vice versa. This chapter explains match types, order of evaluation, and a practical split between /, /assets/, and /api/.

Prerequisites

Location Match Types

ModifierSyntaxMatches
Exactlocation = /favicon.icoURI exactly /favicon.ico
Prefer prefixlocation ^~ /static/Prefix; stops regex search if matched
Regex (case sensitive)location ~ \.php$Pattern in URI
Regex (case insensitive)location ~* \.(jpg|png)$Pattern, ignore case
Prefix (default)location /api/URI starting with /api/

Priority Order (Simplified)

Nginx chooses one location per request:

  1. Exact = — highest if match
  2. Longest prefix match among ^~ and plain prefix
  3. If longest prefix is plain (not ^~), try regex ~ / ~* in config file order; first match wins
  4. If no regex, use the longest prefix match

Tip

Draw a Table for Complex Sites

List your paths (/, /api/, /assets/, /admin/) and assign location types before editing config.

Examples

Code explanation:

  • = /health — exact probe, no file lookup
  • ^~ /assets/ — static hashed files; regex locations skipped if this prefix matches
  • /api/ — proxy before catch-all /
  • / — SPA fallback to index.html

Longest Prefix Wins

nginx
location / {
    return 200 'root';
}
 
location /api/ {
    return 200 'api';
}

Request /api/usersapi (longer prefix /api/ beats /).

Regex for File Extensions

nginx
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2)$ {
    expires 30d;
    try_files $uri =404;
}

Useful when not using a dedicated /assets/ prefix—be careful regex order if multiple patterns overlap.

Named Locations (Preview)

nginx
location / {
    try_files $uri @backend;
}
 
location @backend {
    proxy_pass http://127.0.0.1:8080;
    include /etc/nginx/proxy_params;
}

@name — internal redirect target, not client-visible URL. Used with try_files and error_page.

default_server and server_name

Multiple server blocks on port 80:

nginx
server {
    listen 80 default_server;
    server_name _;
    return 444;
}

Catches requests with unknown Host header—optional hardening.

Debugging Which location Matched

Add temporary headers (remove after debug):

nginx
add_header X-Debug-Location "api" always;

Only inside one location at a time—or use error_log notice and rewrite_log (verbose).

Test paths:

bash
curl -I http://app.example.com/
curl -I http://app.example.com/api/items
curl -I http://app.example.com/assets/main.css

Anti-Patterns

MistakeEffect
Catch-all / before /api/ in file order without prefix lengthStill OK if prefixes differ—longest wins; confusion is order of regex vs prefix
Regex catches .js but proxy neededAPI JSON mistaken—use ^~ or precise prefixes
Duplicate overlapping regexFirst in file wins—unpredictable

Full Split-Host Pattern

FAQ

location order in file?

Prefix length and match type matter more than physical order—except regex order among regexes.

Why ^~?

Stops searching regex locations when prefix matches—faster and predictable for /static/.

Can one URI match two locations?

Nginx picks one winner per request.

internal locations?

location @foo and internal directive restrict internal redirects only.

Case sensitivity in paths?

URI paths are case-sensitive on Linux backends—/API//api/.

Merge with map?

map directive sets variables for complex routing—advanced alternative to many locations.