How to permanently redirect traffic with nginx in Kubernetes

In this article I will show a quick way to permanently redirect traffic with the nginx Ingress Controller in Kubernetes using an Ingress object.

How to permanently redirect traffic with nginx in Kubernetes
Photo by Brendan Church / Unsplash

Recently I had to move my blog - the one you are reading now - from https://blog.knell.it to https://christianhuth.de. To create the blog and write my articles, I use the open-source Software Ghost, which does not have a native feature to redirect traffic from an old domain to a new one. As I deploy my instance of Ghost on a self-hosted Kubernetes cluster with a Helm Chart from Bitnami, I had to find a way to redirect the traffic using the Ingress Controller nginx. The quick fix I came up with is the subject of this article.

Prerequisites

  • A Kubernetes Cluster
  • A running Ghost instance
  • nginx as Ingress Controller
  • A configured Ingress Class

The way to the solution

There are two ways to solve this problem. You can either redirect the URL using the application itself, or you can use the reverse proxy that sits in front of the application. As I mentioned earlier, my blogging application, Ghost, doesn't have native support for redirecting traffic, so the first solution doesn't work in this case. So I had to find a solution using the reverse proxy, which in the context of Kubernetes is the installed Ingress controller - in my case nginx.

An Ingress controller respondes based on Kubernetes resources called Ingress. If you look at the specification of the Ingress resource - using kubectl explain ingress.spec - you'll see that there is no way to define what I was looking for.

However, a look into the documentation of the nginx Ingress controller shows that you have advanced configuration options if you use annotations: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations.

The solution

Reading through the list of available annotations nginx.ingress.kubernetes.io/permanent-redirect sounded like exactly what I was looking for. But I didn't just want to redirect all traffic to one domain. I also wanted to persist the requested path. Fortunately, the nginx configuration provides the $request_uri variable for this.

So I created an Ingress resource using this annotation and the service that was created by the Helm Chart, and ended up with this working version:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/permanent-redirect: "https://NEWDOMAIN$request_uri"
  name: ghost-redirect
spec:
  ingressClassName: nginx
  rules:
    - host: OLDDOMAIN
      http:
        paths:
          - backend:
              service:
                name: ghost
                port:
                  name: https
            path: /
            pathType: ImplementationSpecific

I added this definition to my Git repository, synchronised everything with ArgoCD and tested it using curl:

curl -v http://blog.knell.it
curl -v https://blog.knell.it
# both resulted in
# location: https://christianhuth.de/

curl -v http://blog.knell.it/tag/kubernetes
curl -v https://blog.knell.it/tag/kubernetes
# both resulted in
# location: https://christianhuth.de/tag/kubernetes

As you can see, the redirect works as expected and the context path is also persisted across the redirect. Hopefully this article has helped you to easily redirect traffic from an old to a new domain using the nginx Ingress controller in Kubernetes.