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:
- In regex locations,
proxy_pass
must point to a bare host (optional port) - You cannot include path components after the host
- 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
withbreak
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;
}