Nginx Proxy Pass Error: Fixing URI Issues in Regex Location Blocks


2 views

When working with Nginx's location blocks that use regular expressions, you might encounter this frustrating error:

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression

The error occurs specifically when you try to combine these three elements:

  • Regular expression location blocks (location ~)
  • Path capturing in the regex
  • A URI component in the proxy_pass directive

Nginx intentionally restricts URI components in proxy_pass when used with regex locations because it can lead to ambiguous request routing. The exact rules are:

  1. In regex locations, proxy_pass must point to a bare host (optional port)
  2. You cannot include path components after the host
  3. This ensures predictable request URI transformation

Here's how to rewrite your configuration correctly:

location ~ ^/smx/(test|production) {
    proxy_pass http://localhost:8181;
    proxy_set_header X-Forwarded-Path /cxf$request_uri;
}

location ~ ^/es/(test|production) {
    proxy_pass http://localhost:9200;
    rewrite ^/es/(.*) /$1 break;
}

If you need more complex URI manipulation:

# Using rewrite with capture groups
location ~ ^/api/v(\d+)/(.*) {
    rewrite ^/api/v(\d+)/(.*) /api/$2?v=$1 break;
    proxy_pass http://backend;
}

# Using variables for dynamic routing
location ~ ^/services/([^/]+)/(.*) {
    set $service $1;
    set $path $2;
    proxy_pass http://$service.internal/$path;
}
  • Don't mix regex captures with proxy_pass URIs
  • Remember that rewrite with break stops further processing
  • Test your configuration with nginx -t before reloading

For complex scenarios, consider using Nginx's map directive or separate server blocks instead of trying to handle everything in location regexes.


When working with Nginx's location blocks that use regular expressions, there's an important restriction that catches many developers off guard: you cannot specify a URI part in the proxy_pass directive when using regex locations (location ~ or location ~*). This explains why your configuration fails with the error:

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression

The error occurs because you're trying to combine two behaviors that Nginx considers incompatible:

location ~ ^/smx/(test|production) {
    proxy_pass   http://localhost:8181/cxf;  # The /cxf part is problematic
}

In regex locations, Nginx requires the proxy_pass value to be either:

  • A plain domain/IP with port (no URI path)
  • A variable containing the full destination URL

Here are three ways to properly implement your routing:

Option 1: Use Variables

location ~ ^/smx/(test|production) {
    set $backend "http://localhost:8181/cxf";
    proxy_pass $backend;
}

location ~ ^/es/(test|production) {
    set $backend "http://localhost:9200";
    proxy_pass $backend$request_uri;
}

Option 2: Rewrite Before Proxy

location ~ ^/smx/(test|production) {
    rewrite ^/smx/(.*) /cxf/$1 break;
    proxy_pass http://localhost:8181;
}

location ~ ^/es/(test|production) {
    rewrite ^/es/(.*) /$1 break;
    proxy_pass http://localhost:9200;
}

Option 3: Use Prefix Locations When Possible

location /smx/ {
    proxy_pass http://localhost:8181/cxf/;
}

location /es/ {
    proxy_pass http://localhost:9200/;
}

When using the variable approach (Option 1):

  • The $request_uri includes the original query string
  • For complex routing, you might need additional rewrite rules
  • Always test with nginx -t before reloading

Here's how we implemented this in a production environment with multiple API endpoints:

location ~ ^/api/(v1|v2)/(users|products) {
    set $api_root "http://api-backend:8000";
    set $api_path $1/$2;
    
    proxy_pass $api_root/$api_path$is_args$args;
    proxy_set_header X-Forwarded-Proto $scheme;
}