Move to k8s: Using nginx rewrite rule to preserve permalinks

kubernetes Aug 9, 2019

I have been moving all of my side projects to a kubernetes cluster to simplify my life. It's been going slow due to my commitments to my day jobs and (new side projects). While I had to say goodbye to my old personal website because it was difficult to migrate to a Linux environment, all other the services only required some docker magic as I have already upgraded them to .NET Core, or they were already written in cross-platform languages (like my secret crush Go).

One exception to that was go.mustak.im - I used it over the years to generate permalinks (for ex: go.mustak.im/linkedIn - takes to my LinkedIn page). It is a simple PHP script backed by MySQL database. Why PHP and MySQL for such a simple site? ... ahem, it was simple at that time when I wrote this ... a long time ago. I already had MySQL installed and IIS had PHP extension installed in my Windows Server VPS. It handled a decent amount of traffics over the years and never required any maintenance.

Being written using a programming language and a database meant I had an admin interface to add/remove permalinks and view hit counts etc. Here's how it looked, nice wasn't it?

Now, the whole reason I am writing this post - I didn't want to carry the weight of MySQL server for this in my new kubernetes environment. So I had to come up with a simple solution. Here's the idea and what it meant-

  • Kubernetes ingress with hardcoded rewrite rule - simple, lightweight.
  • I will lose access to hit counts - I couldn't care less!
  • I will lose access to a back panel - It's fine, how often do I need to add a permalink? and how difficult it is to do kubectl apply -f k8s-spec.yaml?

Rewrite rules

Here is the Ingress resource with most of the rewrite rules removed for beivety

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: go-mustakim-ing
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      rewrite ^/cant-run-linqpad(.*) "https://about.mustak.im/cant-run-linqpad/$1" last;
      rewrite ^/linked[I|i]n(.*)     "http://uk.linkedin.com/in/mustakimali/$1" last;
      rewrite ^/(.*)$                "https://mustak.im/";

spec:
  tls:
    - hosts:
      - go.mustak.im
  rules:
  - host: go.mustak.im
go-mustak-im.yaml

Few things to notice here,

  • Each of the rules only matches the first part of the request and preserves the rest of the url across the redirect. so the rule /foo -> /dest will also match /foo/bar and redirect to /dest/bar.
  • All of the rewrite rules have last flag so that nginx skips checking any other rules - to improve the speed and to avoid any issues when multiple rules matches.
  • The last rule is a catch-all when none of the rule works - it redirects to the homepage.
rewrite ^/(.*)$                "https://mustak.im/";

Mohammad Mustakim Ali

I'm a Software Engineer living in London, UK. My passion is to make *very fast* software with great user experience and I have just got little better on this than I was yesterday.