When working with Nginx Ingress on Kubernetes, developers often need to rewrite URL paths to backend services while keeping the original browser URL intact. This becomes particularly important when you want to:
- Expose a backend service under a specific path prefix
- Maintain clean URLs for end users
- Handle static assets and API endpoints consistently
In traditional Nginx configuration, we'd use something like:
location /path/ { proxy_pass http://service/; }
The trailing slash in proxy_pass is crucial as it strips the /path
prefix when forwarding to the backend. However, with Nginx Ingress, we need to approach this differently.
The most effective way to achieve this in Nginx Ingress is through annotations:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/use-regex: "true" spec: rules: - host: example.com http: paths: - path: /path(/|$)(.*) pathType: Prefix backend: service: name: service port: number: 80
The configuration works through these mechanisms:
use-regex: "true"
enables regular expression matching- The path regex
/path(/|$)(.*)
captures everything after /path rewrite-target: /$2
uses the second capture group for the backend request
This setup properly handles all the mentioned cases:
# Original: http://example.com/path # Backend receives: http://service/ # Original: http://example.com/path/bar # Backend receives: http://service/bar # Original: http://example.com/path/file.css # Backend receives: http://service/file.css
For more complex scenarios, you might need additional annotations:
annotations: nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Forwarded-Prefix /path;
This preserves the original path information while still rewriting the target URL.
If you encounter issues:
- Check ingress controller logs with
kubectl logs -n ingress-nginx [controller-pod]
- Verify annotation spelling (they're case-sensitive)
- Ensure your ingress controller version supports these annotations
When working with Kubernetes Nginx Ingress, a common requirement is to rewrite backend paths while keeping the original browser URL intact. This becomes particularly important when you need to:
- Expose services at different paths than their internal structure
- Maintain clean public URLs while routing to complex backend paths
- Implement path-based routing without exposing internal service structures
The most straightforward approach uses Nginx Ingress annotations:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-rewrite-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- host: example.com
http:
paths:
- path: /path(/|$)(.*)
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
The magic happens in the regex pattern /path(/|$)(.*)
:
/path
- Matches the literal path prefix(/|$)
- Captures either a trailing slash or end-of-string(.*)
- Captures everything after the prefix
The rewrite-target: /$2
tells Nginx to use the second capture group (everything after the prefix) as the new path.
For more complex scenarios, consider these additional annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-Prefix /path;
nginx.ingress.kubernetes.io/server-snippet: |
location ~* ^/path(/.*)?$ {
proxy_pass http://my-service$1$is_args$args;
}
After applying your Ingress, verify the behavior:
kubectl describe ingress path-rewrite-ingress
curl -v http://example.com/path/some-resource
Check that:
- The browser URL remains unchanged
- The backend receives the modified path
- All resources (CSS, JS, etc.) load correctly
If you encounter problems:
- 404 errors: Verify your service is running and the port matches
- Infinite redirects: Check your rewrite rules aren't creating loops
- CSS/JS not loading: Ensure relative paths work or use absolute paths
Kubernetes 1.18+ offers more path matching options:
paths:
- path: /path
pathType: Prefix
backend:
service:
name: my-service
port:
number: 80
Combine this with the rewrite-target
annotation for precise control.