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.
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.