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_passdirective
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_passmust 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
rewritewithbreakstops further processing - Test your configuration with
nginx -tbefore 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_uriincludes the original query string - For complex routing, you might need additional
rewriterules - Always test with
nginx -tbefore 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;
}