Nginx Ingress URL Path Rewrite While Preserving Original Browser URL


2 views

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:

  1. 404 errors: Verify your service is running and the port matches
  2. Infinite redirects: Check your rewrite rules aren't creating loops
  3. 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.