Kubernetes Multi-Domain Setup with Traefik, Cert-Manager & Helm

Struggling with Kubernetes multi-domain setup? This guide walks you through configuring Traefik and Let’s Encrypt, providing a clear, step-by-step process to securely add new domains & streamline your deployment.

Alec Di Vito
Alec Di Vito 3 min read
Kubernetes Multi-Domain Setup with Traefik, Cert-Manager & Helm
Me trying to navigate Traefik docs

I recently helped a friend migrate their blog from Gatsby to Ghost – a familiar story for me, since I’ve done it myself. Naturally, I offered to host it locally on my Kubernetes cluster, as any reasonable person would. But I could never have predicted how Traefik’s confusing configuration was conspiring to turn a routine deployment into a 45-minute saga.

This post is born from my humbling experience. As I quickly learned, adding one more domain name to Traefik isn’t as straightforward as it seems. Despite the minor frustrations, I'm still grateful to have Traefik and Cert-Manager in my life. If you're struggling to add a new domain to your cluster, this short guide is for you. Consider it a slightly-less-frustrating walkthrough – I’m sharing the battle scars, so you don’t have to earn them yourself.

Valeriia Zub
I turn problems to opportunities using design thinking tools and AI

The website in question I was helping to deploy

Supporting many domain names

With traffic and let's encrypt

Before we begin, there are some assumptions that I’m making about you, the reader, and what you have.

  1. You run Traefik as your ingress of choice, deployed with helm.
  2. You use cert-manager and let's encrypt to manage SSL certificates. It’s been configured with something like Cloudflare so it’s an automated process.
  3. You've already configured a default certificate with Traefik.

Creating another certificate with Cert-manager

First step is to create a new certificate. This code would probably look very similar to your existing code for your existing domain name. I was successful in coping and pasting And just changing the domain names.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example-com
spec:
  secretName: wildcard-example-com-tls
  dnsNames:
    - "example.com"
    - "*.example.com"
  issuerRef:
    name: <your-prod-issuer-here>
    kind: ClusterIssuer
💡
If you are using the traefik helm chart, you can place this in the extraObjects portion of the chart.

The above example shows me adding the example.com domain.

New certificates take a moment, but it should succeed as long as you added your new domain to the same platform of your existing domain.

TLSStores

Traefik manages certificates through their own CRD objects called TLS Stores. Creating them is easy, especially when using the Helm chart. These CRD's let Traefik know which SSL certificate to use to serve a given route depending on the domain name.

Back to assumptions, I’m assuming you've already created a default TLSStore in the following way.

# ... traefik/values.yaml ...
tlsStore:
  default:
    defaultCertificate:
      secretName: wildcard-existing-domain-com

To add support for our new certificate you'll need to update this object in a particular way. The confusing part is that you are supposed to add certificates back into the default section. Therefore, you'll end up with an updated object like this.

# ... traefik/values.yaml ...
tlsStore:
  default:
    certificates:
      - secretName: wildcard-example-com-tls
    defaultCertificate:
      - secretName: wildcard-existing-domain-com

The key here is that all other domains (that aren’t default) would be added under the tlsStore.default.certificates field. The extra certificates can be added by pointing at the secrets that hold the SSL certificates.

💡
your certificate and ingress need to live in the same namespace.

Finally, because you aren't going to be using the default tlsStore , you'll need to declare which one you want the IngressRoute to use.

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: example-ingress
spec:
  entryPoints:
    - your-entry-point
  routes:
    - kind: Rule
      match: Host(`example.com`)
      services:
        - name: example-service
          port: 8080
  tls:
    store:
      name: default
      namespace: certificate-location

And believe it or not, that’s all it takes to support a new domain name in your Kubernetes cluster. I hope this post motivates you to host your friends apps on your cluster! The reason I wrote this post was because it was unclear what the process was to add another domain on my cluster.