22

I have an ingress controller and ingress resource running with all /devops mapped to devopsservice in the backend. When I try to hit "http://hostname/devops" things work and I get a page (although without CSS and styles) with a set of hyperlinks for e.g one of them is "logs".

When I click on the "logs" hyperlink, it is redirecting me to http://hostname/logs whereas I need it to be http://hostname/devops/logs.

Any idea what I can do?

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: my-ingress
 namespace: ingress-nginx
 annotations:
   kubernetes.io/ingress.class: nginx
   nginx.ingress.kubernetes.io/rewrite-target: /
   nginx.ingress.kubernetes.io/add-base-url : "true"
spec:
 rules:
 - host: master1.dev.local
   http:
     paths:
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /devops
Rico
  • 58,485
  • 12
  • 111
  • 141
user1722908
  • 535
  • 2
  • 9
  • 21

4 Answers4

11

Looks like your ingress is not serving anything /devops/*. Try adding another path /devops/* with the same backend. Basically this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: my-ingress
 namespace: ingress-nginx
 annotations:
   kubernetes.io/ingress.class: nginx
   nginx.ingress.kubernetes.io/rewrite-target: /
   nginx.ingress.kubernetes.io/add-base-url : "true"
spec:
 rules:
 - host: master1.dev.local
   http:
     paths:
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /devops/*
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /devops

Update: the above has been deprecated in favor of something like this:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: rewrite
  namespace: default
spec:
  rules:
  - host: master1.dev.local
    http:
      paths:
      - backend:
          serviceName: devops1
          servicePort: 10311
        path: /devops(/|$)(.*)
Rico
  • 58,485
  • 12
  • 111
  • 141
6

If you access http://hostname/devops/logs directly from your browser, certainly you will get what you want. But since you click the hyperlink in the homepage, then you can only get http://hostname/logs, which will be certainly failed.

So, you need /logs backend configured in your ingress yaml to get it processed, and configure nginx.ingress.kubernetes.io/configuration-snippet to ensure /logs not get rewrote, like this:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: my-ingress
 namespace: ingress-nginx
 annotations:
   kubernetes.io/ingress.class: nginx
   nginx.ingress.kubernetes.io/rewrite-target: /
   nginx.ingress.kubernetes.io/add-base-url : "true"
   nginx.ingress.kubernetes.io/configuration-snippet: |
     rewrite ^/logs /logs break;
spec:
 rules:
 - host: master1.dev.local
   http:
     paths:
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /logs
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /devops
Kun Li
  • 2,570
  • 10
  • 15
  • 1
    `add-base-url` was [removed](https://github.com/kubernetes/ingress-nginx/pull/3174) in 0.22.0. – Jan Molnár Mar 13 '20 at 21:09
  • Hey, thanks for this solution. I was looking more than 4 hours to a clear reference on internet to this configuration. Nginx should put this topics more easily to find.! – Vicente Zambrano Dec 18 '22 at 20:43
  • Also worth to add this documentation link for better clarity: https://kubernetes.github.io/ingress-nginx/examples/rewrite/ – Vicente Zambrano Dec 18 '22 at 20:51
2

I met the similar issue recently.

Assuming the "logs" hyperlink in your html uses a relative path, which means the hyperlink doesn't start with '/', then I think you can try to hit the page at http://hostname/devops/ instead of http://hostname/devops. (Note a / suffix in the first url.).

Then the "logs" hyperlink will be formed as http://hostname/devops/logs.

I think it's about how the browser identifies the 'base' url. With accessing 'http://hostname/devops/, if there is no 'base' tag in the html header, the 'base' url will be figured out to be http://hostname/devops; while with 'http://hostname/devops', the base url will be http://hostname.

If it's not the case, there is discussion at https://github.com/kubernetes/ingress-nginx/issues/4149. It's suggested a workaround to use the nginx directive subs_filter with a configuration-snippet to make the href attributes relative and also add the base tag in the html header.

The ingress used is as below,

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  name: rewrite
  namespace: default
spec:
  rules:
  - host: master1.dev.local
    http:
      paths:
      - backend:
          serviceName: devops1
          servicePort: 10311
        path: /devops(/|$)(.*)
SZ Yang
  • 41
  • 3
1

The nginx.ingress.kubernetes.io/x-forwarded-prefix annotation can be used for this purpose.

It adds x-forwarded-prefix header to http request with a value from this annotation. You can use it, if your backend support such header.

For example, Spring Boot application can handle it by using property:

server.forward-headers-strategy=framework

In your case ingress would look like the following:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: my-ingress
 namespace: ingress-nginx
 annotations:
   kubernetes.io/ingress.class: nginx
   nginx.ingress.kubernetes.io/rewrite-target: /
   nginx.ingress.kubernetes.io/x-forwarded-prefix: /devops
spec:
 rules:
 - host: master1.dev.local
   http:
     paths:
     - backend:
         serviceName: devops1
         servicePort: 10311
       path: /devops

This solution has its downsides. It forces you to declare each service in separate ingress.