Removing url prefixes in nginx Kubernetes Ingress

Getting an NGINX ingress running on a cluster is really easy, but the documentation did not immediately tell me how to strip the path prefix off at the ingress. I know I can use something like Istio to do this for me but for this specific project I didn’t need all of the additional complexity of that tool. So, how do I have nginx rewrite away the path prefix I use to target my services? It turns out it’s simple; although nowhere near as capable as Istio’s VirtualServices.

First, let’s define (possibly) the most simple ingress possible:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-namespace
spec:
  rules:
  - http:
      paths:
      - pathType: Prefix
        path: /api
        backend:
          service:
            name: my-api
            port:
              number: 8080

I think this is quite straightforward: I want anything with the prefix /api to get sent to a service named my-api running at port 8080. The drawback to this ingress definition is that now my service must run expecting the path to include /api. That’s not the end of the world I suppose, but I prefer my services to not care about things outside their control.

In my case I want NGINX to basically erase that path match before the request is routed to my service. I can do that with a little regular expression with a capture group for my path: /api(/|$)(.*) instead of /api and the rewrite-target annotation, like so:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-namespace
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - http:
      paths:
      - pathType: Prefix
        path: /api(/|$)(.*)
        backend:
          service:
            name: my-api
            port:
              number: 8080

That’s it! Now the /api prefix will be “erased” – Really I’m just not including it in our rewrite target. I’ve told NGINX to rewrite the path to / plus the second capture group (that’s $2), which is anything in the (.*) capture group. As an example requests coming in to /api/person will be rewritten to /person, /api and /api/ will be rewritten to /. To learn more about regular expression capture groups read here.

Sources:

  1. https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/rewrite/README.md
  2. https://kubernetes.io/docs/concepts/services-networking/ingress/

Comments

  1. Spencer

    hi, i tried running this code with a little modification. But I get 404 Not found when i try to curl or access the page. Also the nginx ingress pod shows this log:
    [error] 97#97: *148 open() “/etc/nginx/html/game” failed (2: No such file or directory), client: 10.0.1.158, server: apps.test, request: “GET /game HTTP/1.1”, host: “apps.test”
    10.0.1.158 – – [29/Mar/2023:00:30:53 +0000] “GET /game HTTP/1.1” 404 153 “-” “curl/7.77.0” “-“;
    i was wondering if you know if there was something else I missed? Here is my yaml:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: apps-ingress
    namespace: test
    annotations:
    nginx.ingress.kubernetes.io/use-regex: ‘true’
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    spec:
    ingressClassName: nginx
    rules:
    – host: apps.test
    http:
    paths:
    – path: /nginx(/|$)(.*)
    pathType: Prefix
    backend:
    service:
    name: nginx-test
    port:
    name: http
    – path: /game(/|$)(.*)
    pathType: Prefix
    backend:
    service:
    name: game
    port:
    name: http

    1. Post
      Author
      Kyle Diedrick

      Sorry for the (very!) late reply. I’m no expert but some things I would check:
      1. Make sure the service named “game” is listening on the appropriate port
      2. I’m not sure how adding the host rule might impact the http rule. I remember reading that there were a bunch of caveats around the http path rules…but I don’t remember what those were now.

      I hope you got it figured out!

Leave a Reply

Your email address will not be published. Required fields are marked *