Nginx Location Directive: Trailing Slash Best Practices for Proxy Pass Configuration


1 views

When configuring Nginx proxy_pass, the trailing slash behavior in location blocks often causes confusion. The difference between location /product and location /product/ is subtle but significant for proper routing.

Consider these two configurations:

# Configuration A (without trailing slash)
location /product {
    proxy_pass http://10.0.0.25:8080;
}

# Configuration B (with trailing slash)
location /product/ {
    proxy_pass http://10.0.0.25:8080;
}

Configuration A will match:

  • /product (exact match)
  • /product/ (redirects to /product)
  • /product123 (prefix match)

Configuration B will match:

  • /product/ (exact match)
  • /product/subpath (prefix match)
  • Will not match /product without trailing slash

To properly handle both forms, use this optimized configuration:

location /product {
    # Handle case without trailing slash
    proxy_pass http://10.0.0.25:8080;
    
    # Optional: Add redirect for consistency
    if ($request_uri ~ ^/product[^/]$) {
        return 301 $uri/;
    }
}

location /product/ {
    proxy_pass http://10.0.0.25:8080/;  # Note the trailing slash here
}

For more complex scenarios where you need to preserve the URI path:

location ~ ^/product(/.*)?$ {
    proxy_pass http://10.0.0.25:8080$1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}
  • Forgetting the trailing slash in proxy_pass when using trailing slash in location
  • Not considering HTTP to HTTPS redirect chains
  • Overlooking the difference between prefix matches (=, ~, ^~)

The regex solution (~) is slightly less efficient than prefix matching. For high-traffic sites, consider:

location = /product {
    return 301 /product/;
}

location /product/ {
    proxy_pass http://backend/;
}

When configuring Nginx proxy rules, the presence or absence of a trailing slash in your location block can significantly impact request routing. Consider these two common but subtly different configurations:

location /product {
    proxy_pass http://10.0.0.25:8080;
}

location /product/ {
    proxy_pass http://10.0.0.25:8080;
}

The first configuration (/product) will only match requests to /product exactly. Meanwhile, the second (/product/) requires a trailing slash and will match any URI starting with /product/.

To handle both cases elegantly, you have several options:

Option 1: Exact Match + Prefix Match

location = /product {
    return 301 /product/;
}

location /product/ {
    proxy_pass http://10.0.0.25:8080/;
}

Option 2: Rewrite Approach

location /product {
    rewrite ^/product$ /product/ permanent;
    proxy_pass http://10.0.0.25:8080/;
}

Notice the trailing slash in proxy_pass http://10.0.0.25:8080/. This is crucial for proper URI reconstruction. Without it, Nginx would pass the full original URI to the backend server.

server {
    listen 80;
    server_name example.com;
    
    # Handle both /api and /api/
    location = /api {
        return 301 /api/;
    }
    
    location /api/ {
        proxy_set_header Host $host;
        proxy_pass http://backend:3000/;
        proxy_redirect off;
    }
}

Using exact matches (location =) first improves performance as Nginx checks these before prefix locations. The 301 redirect has minimal overhead while providing clean URLs.