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:
Comments
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
Author
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!