kubernetes ingress nginx rewrite partially working - sometimes wrong context path

1/20/2020

I'm setting up simple Kubernetes cluster using GKE. I've set up Java Spring boot app as Kubernetes Deployment and Service (with type Load Balancer, exposed on port 80). This app is working perfectly fine when accessed directly using external IP for the service.

I've also installed nginx-ingress for GKE and provided following Ingress resource:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
  name: rewrite
  namespace: default
spec:
  rules:
  - host: "myhost.ddns.net"
    http:
      paths:
      - backend:
          serviceName: app-java
          servicePort: 80
        path: /app-java/?(.*)

From now on, funny things occur:

Problem 1: if I access site at http://myhost.ddns.net/app-java - I get only HTML file, all other resources have 404 (download attempt from http://myhost.ddns.net/foo.js instead of http://myhost.ddns.net/app-java/foo.js.

Problem 2: If I access site at http://myhost.ddns.net/app-java/ - I get both HTML file and all scripts and images. However, when I dig deeper, sending form content via POST fails. It's HTML code is:

<form action="/select" method="post">

Which tries to access http://myhost.ddns.net/select instead of http://myhost.ddns.net/app-java/select.

I found out that it might me strongly connected to this question: Thymeleaf template (in Spring boot application) behind reverse proxy not forming url's correctly. SOlution provided there is to write following nginx reverse proxy configuration:

location /app-java {
    proxy_pass http://10.0.0.0:80;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host:$server_port;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Prefix /app-java;
}

However, I have no idea how to translate it to ingress resource yaml.

How can I fix this url-rewrite problem using ingress?


Edit: After hints from @HelloWorld I've reorganized application to serve content on /app-java context path (using Spring Boot 2 property server.servlet.context-path=/app-java). After that, I've changed rewrite-target to:

nginx.ingress.kubernetes.io/rewrite-target: /app-java/$1

And now it's working fine.

-- Greg Witczak
kubernetes-ingress
nginx-ingress
url-rewriting

1 Answer

1/21/2020

I see you are trying to make your browser to add a prefix to all paths in flight.

I believe you must have misunderstood the idea of X-Forwarded-Prefix and whatever was described in Thymeleaf template (in Spring boot application) behind reverse proxy not forming url's correctly, where community member described how to pass this header to your application. If you want to try it and see how it works you can achieve this by simply adding this annotation to your ingress object:

nginx.ingress.kubernetes.io/x-forwarded-prefix: "/app-java"

but notice this is not going to solve your problem.

Of course you can also add these headers to the response from application so that they get sent to your browser (what I believe you were expecting to achieve) but browsers don't care about these headers so there is no point in doing it.

If you still want to try it yourself and prove it, you can add this annotation to the ingress object:

nginx.ingress.kubernetes.io/configuration-snippet: |
    more_set_headers "X-Forwarded-Prefix: /app-java";

The only way as far as I know to solve this issue is to modify your application code so that it's responding with correct paths.

You can find that many applications use customizable base path, configurable either by env variables, config files or by cli arguments.

-- HelloWorld
Source: StackOverflow