Search code examples
kubernetesnginx-ingress

How to properly configure k8s nginx ingress base url and path to handle vuejs client side routing and nodejs server side api


I'm trying to deploy my frontend client application and backend API on the same domain and I want the frontend on the base path: /

However, I realized that the frontend and the backend need two different rewrite-target to accomplish this.

front-end works with:

nginx.ingress.kubernetes.io/rewrite-target: /

while the backend works with:

nginx.ingress.kubernetes.io/rewrite-target: /$2

I tried using two different ingress services in order to accommodate different rewrite-target, but that fails because the host was the same domain.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: test
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-staging
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/service-upstream: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
    nginx.ingress.kubernetes.io/proxy-buffering: "on"
    nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "server: hide";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-Xss-Protection: 1";
spec:
  tls:
  - hosts:
    - test.eastus.cloudapp.azure.com
    secretName: tls-secret
  rules:
  - host: test.eastus.cloudapp.azure.com
    http:
      paths:
      - backend:
          serviceName: webapp
          servicePort: 80
        path: /
      - backend:
          serviceName: api
          servicePort: 80
        path: /api(/|$)(.*)

I know I can make both work with the same rewrite-target /$2 if I change the frontend path to path: /app(/|$)(.*) but I don't want to that except it is the only option.

Is there a way for me to better configure a single ingress to work for 2 different rewrite-target?


Solution

  • Ingress with API version networking.k8s.io/v1 with k8s version 1.19+ can solve your problem. I have given an example below.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: simple-fanout-example
    spec:
      rules:
      - host: foo.bar.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 80
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: backend-service
                port:
                  number: 8080
    
    

    According to kubernetes documentation:

    In some cases, multiple paths within an Ingress will match a request. In those cases precedence will be given first to the longest matching path. If two paths are still equally matched, precedence will be given to paths with an exact path type over prefix path type.

    So, when you are looking for a resource located at path "/home.html", it only matches with your frontend service. But when you are looking for a resource located at path "/api/something" then it matches both service. But it will go to backend service always because of maximum path match stated above.