Nginx ingress controller rewrite-target annotation and rule to add a trailing slash to url

12/28/2020

I'm trying to deploy a static website to a Kubernetes cluster which is using the official Nginx Ingress controller. The folder structure of the website looks somewhat like this:

/
├── about
│   └── index.html
├── casestudy
│   ├── data-and-analytics
│   │   └── index.html
│   └── workflow-automation
│       └── index.html
├── contact
│   └── index.html
├── css
│   ├── font-awesome.min.css
│   ├── fonts
│   │   ├── slick.eot
│   │   ├── slick.svg
│   │   ├── slick.ttf
│   │   └── slick.woff
│   ├── footer.css
│   ├── layout.css
...

My ingress definition looks like this:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: website-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    # nginx.ingress.kubernetes.io/rewrite-target: /$2
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
    - hosts:
        - website.com
      secretName: website-tls
  rules:
    - host: website.com
      http:
        paths:
          - path: /
            backend:
              serviceName: website-svc
              servicePort: 8080

This works fine for the most part, except that if I forget to put a trailing slash at the end of the URL like https://website.com/about I get routed into an error page. I understand why this is happening - Nginx is looking for a about.html file and is failing to find one. But I don't know how to fix this.

What I'd ideally like to do is that I want to add a trailing / to requests which don't have one. But I also want to not do this when the browser is requesting for a css file.

What redirect annotation and rule should I use for this?

Thanks.

-- Rajshri Mohan K S
kubernetes
kubernetes-ingress
nginx-ingress

2 Answers

12/29/2020

Try this:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: website-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1/
spec:
  rules:
    - http:
        paths:
          - path: /(.*)
            backend:
              serviceName: website-svc
              servicePort: 8080

It works perfectly for me. After running:

curl <ingress ip>/about

You can see in logs the following:

ingress controller

kubectl logs -n ingress-nginx ingress-nginx-controller-6dc856845b-rf2ft

<ip address> - - [29/Dec/2020:18:40:13 +0000] "GET /about HTTP/1.1" 200 7 "-" "curl/7.64.0" 83 0.000 [default-nginx-deployment-80] [] 10.0.1.8:80 7 0.000 200 (...)

nginx pod serving the website

kubectl logs nginx-deployment-6c8c7fdf65-w4h4b

10.0.1.10 - - [29/Dec/2020:18:40:13 +0000] "GET /about/ HTTP/1.1" 200 7 "-" "curl/7.64.0" "<ip address>"
-- mario
Source: StackOverflow

1/28/2021

What ultimately worked for this situation is a snippet like this:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: website-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt
    nginx.ingress.kubernetes.io/rewrite-target: /
    # Rewrite all URLs not ending with a segment containing . or ? with a trailing slash
    # So basically we are rewriting all folder names with a trailing slash.
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^([^.?]*[^/])$ $1/ redirect;
spec:
  tls:
    - hosts:
        - website.com
      secretName: website-tls
  rules:
    - host: website.com
      http:
        paths:
          - path: /
            backend:
              serviceName: website-svc
              servicePort: 8080

This will let us rewrite all URLs ending with a segment containing no . (period - thus avoiding filenames) and ? (question mark - thus avoiding all query strings) with a trailing slash. This works for my case.

-- Rajshri Mohan K S
Source: StackOverflow