Ghost in k8s with traefik

After trying out many different CMS and blogging solutions, I decided to stick with ghost. Ghost's WYSIWYG editor is the best on the market in my opinion. Deploying a ghost instance is pretty straightforward as well. Since I use containers for almost everything, I started with a simple docker-compose file:

version: '3.1'
services:
  ghost:
    image: ghost
    restart: always
    ports:
      - 2368:2368
    environment:
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: example
      database__connection__database: ghost
      url: http://localhost:2368
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example

That allows to deploy a ghost instance in seconds:

After this successful test I decided to deploy ghost directly to my k8s cluster. The deployment itself is straightforward, I basically just changed the "url" environment variable to match my URL:

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: ghost
  name: ghost
  labels:
    app: ghost
spec:
  [...]
  template:
    [...]
    spec:
      containers:
      - name: ghost
        image: ghost
        ports:
        - containerPort: 2368
        env:
        [...]
        - name: url
          value: https://blog.mrupp.eu
        [...]

I expected this to work just fine but the result was pretty unsatisfying:

It turned out that ghost tried to redirect me to https://blog.mrupp.eu
which is exactly the URL that I entered in my web browser. The problem is that the ingress controller (in this case traefik) access the ghost service via http - ghost expects https.

The fix is to write a traefik middleware that adds a X-Forwarded-Proto header that tells ghost that the site was originally accessed via https:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: proto-forward
  namespace: ghost
spec:
  headers:
    customRequestHeaders:
      X-Forwarded-Proto: "https"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ghost-ingress
  namespace: ghost
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: ghost-proto-forward@kubernetescrd
spec:
  rules:
  - host: blog.mrupp.eu
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ghost-service
            port:
              number: 80

Personally I think that the absolute URL configuration is a bad design choice. It not only causes errors like the above one, it also makes it very hard to deploy one ghost instance for multiple domains.

Show Comments