When configuring Nginx as an API gateway, we often need to capture specific path segments from the incoming request URI and dynamically insert them into the proxy_pass destination. This becomes particularly useful when routing requests to different backend services based on path patterns.
The solution lies in Nginx's powerful regex location matching and capture groups. Here's the basic syntax:
location ~ ^/([^/]+)/v2/(.*)$ { proxy_pass http://app.domain.com/api/$1/v2/$2; }
Let's examine the key components of this approach:
1. ~ : Enables regex matching 2. ^ : Anchors the match at the start of the URI 3. ([^/]+) : Captures the first path segment (non-slash characters) 4. /v2/ : Matches the literal "/v2/" portion 5. (.*) : Captures the remaining path 6. $1 and $2 : Reference the captured groups
Basic API Version Routing
location ~ ^/([^/]+)/v([0-9]+)/(.*)$ { proxy_pass http://api-backend/$1/v$2/$3; proxy_set_header X-API-Version $2; }
Multi-segment Capture
location ~ ^/([^/]+)/([^/]+)/(.*)$ { proxy_pass http://$1-service.domain.com/$2/$3; proxy_set_header X-Service-Name $1; }
With Rewrite Rules
location ~ ^/api/([^/]+)/(.*)$ { rewrite ^/api/([^/]+)/(.*)$ /$2 break; proxy_pass http://$1.internal.domain.com; }
For Microservices Architecture
location ~ ^/services/([^/]+)/(.*)$ { resolver kube-dns.kube-system.svc.cluster.local; proxy_pass http://$1-service.default.svc.cluster.local/$2; }
Watch out for these issues when implementing path segment extraction:
- Forgetting the 'break' flag in rewrite rules
- Not accounting for trailing slashes
- Overlooking URL encoding of captured segments
- Missing resolver for internal DNS in containerized environments
When building API gateways with Nginx, we often need to capture specific path segments to construct dynamic upstream endpoints. This becomes crucial when routing requests to microservices or versioned APIs while maintaining clean URL structures.
Nginx provides a powerful way to capture path segments using named regular expression groups:
location ~ ^/(?<service>[^/]+)/v2/(.*)$ {
proxy_pass http://app.domain.com/api/$service/v2/$1;
}
Let's examine three common use cases with increasing complexity:
# Basic capture for service name
location ~ ^/(?<api_module>[^/]+)/v1/ {
proxy_pass http://backend/$api_module/v1/;
}
# Multi-segment version-aware routing
location ~ ^/(?<team>[^/]+)/(?<service>[^/]+)/v(?<version>\d+)/ {
proxy_pass http://$team.services.domain.com/$service/api/v$version/;
}
# Full path reconstruction with query params
location ~ ^/gateway/(?<namespace>[^/]+)/(?<endpoint>.*)$ {
proxy_pass http://$namespace.internal.domain.com/$endpoint$is_args$args;
}
While regex locations are powerful, they're slightly slower than prefix matches. For high-traffic endpoints, consider:
- Using the most specific patterns first
- Limiting capture groups to only what you need
- Using
^~
modifier for priority prefixes
For more complex scenarios, combine map directives with captured variables:
map $service $backend_host {
users users-cluster.internal;
products catalog-service.internal;
default fallback.internal;
}
server {
location ~ ^/(?<service>[^/]+)/ {
proxy_pass http://$backend_host/api/$service;
}
}
Watch out for these gotchas:
- Trailing slashes in location and proxy_pass must match
- URI segments are case-sensitive by default
- Special characters in paths may require escaping
- Variables in proxy_pass require Nginx 1.17+ for full support