Routes that find themselves,Traefik.
A cloud-native reverse proxy that discovers services dynamically from Docker labels, Kubernetes CRDs, or file config — and provisions Let's Encrypt TLS automatically. This guide moves from local to production: Docker Compose, k3s patching, BasicAuth middleware, and Cloudflare DNS-01 challenges for ACME certificates.
No reloads, no config drift
Traefik watches a provider — the Docker socket, Kubernetes CRDs, or a config file — and rebuilds its routers as containers start and stop. Certificates renew themselves through ACME, so routing stays hands-off.
- Discovery — routers built from labels and CRDs.
- Middleware — BasicAuth, rate limits, rewrites.
- TLS — automatic ACME via Cloudflare DNS-01.
On this page
What this guide covers
Docker Compose
Stand up Traefik locally with the socket mounted read-only, label-driven routing, and a whoami test service.
Kubernetes & CRDs
Patch the k3s service, add the Helm repo, and wire Middleware resources into Ingress annotations.
Config & IngressRoute
Static vs dynamic configuration, the chmod 600 acme.json store, and Traefik's native IngressRoute CRD.
Cloudflare ACME
Scoped DNS:Edit and Zone:Read API tokens so Traefik solves the DNS-01 challenge automatically.
Start here
Overview
Traefik is a cloud-native reverse proxy and load balancer that makes deploying, configuring, and integrating infrastructure components easy and automatic. Unlike a static proxy, Traefik discovers services dynamically from providers — Docker labels, Kubernetes CRDs, or file config — and reconfigures its routes as containers start and stop. It also provisions Let’s Encrypt TLS certificates automatically.
This guide moves from local to production: run Traefik with Docker Compose, patch and install it on a k3s Kubernetes cluster, attach BasicAuth middleware, and automate Cloudflare DNS challenges for ACME certificates.
-
Docker — Stand up Traefik locally with Compose and an
acme.jsonfor certificates. -
Kubernetes — Install the CRDs and RBAC, then patch the service and add Helm.
-
Middleware — Isolate concerns like auth into
Middlewareresources referenced by Ingress. -
Cloudflare — Wire scoped API tokens so Traefik solves the ACME DNS-01 challenge automatically.
Local first
Docker
Docker Compose - There should be an acme.json file that you create and pass through the docker with the permission of chmod 600. - Furthermore, there are two more files that you will have to configure and pass through before launching the traefik container. We provided them in the #config section below.
A complete docker-compose.yml that runs Traefik, mounts the Docker socket for auto-discovery, and routes to a whoami test service:
services: traefik: image: traefik:v3.1 command: - "--providers.docker=true" - "--providers.docker.exposedByDefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--api.dashboard=true" ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./acme.json:/acme.json" restart: unless-stopped
whoami: image: traefik/whoami labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)" - "traefik.http.routers.whoami.entrypoints=web"Traefik reads the traefik.* labels on each container and builds routers automatically — no separate config file needed for basic routing. Mounting the Docker socket read-only (:ro) lets Traefik watch for containers starting and stopping.
Cluster ingress
Kubernetes
-
Patching Traefik on k3s cluster
-
We want to find the instance of where traefik is running. Running
sudo kubectl get all -o wide --all-namespacesshould display all your containers, look for traefik. -
Patch
-
Terminal window sudo kubectl patch svc traefik -n kube-system -p '{"spec":{"externalTrafficPolicy":"Cluster"}}'
-
-
std output should be
service/traefik patched
-
-
Helm Charts
-
Terminal window helm repo add traefik https://helm.traefik.io/traefik-
Sucess: std output should be
-
Terminal window "traefik" has been added to your repositories
-
-
-
Terminal window helm repo update
-
-
Traefik Middleware for Kubernetes
-
Middleware kind should be isolated for performance and security reasons.
-
Auth - Kind: Middleware
-
Example:
-
apiVersion: traefik.containo.us/v1alpha1kind: Middlewaremetadata:name: longhorn-authnamespace: longhorn-systemspec:basicAuth:secret: authsecret
- The middleware should be saved as a yaml / yml file and applied using kubectl.
-
-
-
Auth - Kind: Ingress
-
Calling the
longhorn-authin theIngressviaannotations:-
Example:
-
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: longhorn-ing-traefiknamespace: longhorn-systemannotations:externalTrafficPolicy: Localkubernetes.io/ingress.class: traefiktraefik.ingress.kubernetes.io/router.middlewares: longhorn-system-longhorn-auth@kubernetescrdingress.kubernetes.io/whitelist-x-forwarded-for: 'true'spec:rules:- host: 'x.kbve.com'http:paths:- path: /pathType: Prefixbackend:service:name: longhorn-service-providerport:number: 8000
-
In our PoC above, we see that the middleware is referenced as:
traefik.ingress.kubernetes.io/router.middlewares: longhorn-system-longhorn-auth@kubernetescrdIts important to note the namespace of the middleware,
longhorn-system, before calling the middleware’s name. This is to let the crd know where the middleware is located.
-
-
-
-
-
Static & dynamic
Config
Traefik reads two kinds of configuration: static (traefik.yml, entrypoints and providers, loaded once at startup) and dynamic (routers, services, middleware, hot-reloaded at runtime). For Docker deployments, create the ACME store first so Traefik can persist issued certificates:
touch acme.jsonchmod 600 acme.jsonA minimal static traefik.yml enabling the Docker provider and a Let’s Encrypt resolver:
entryPoints: websecure: address: ":443"
providers: docker: exposedByDefault: false
certificatesResolvers: letsencrypt: acme: storage: acme.json dnsChallenge: provider: cloudflareMount acme.json and traefik.yml into the container and pass the Cloudflare token (see Cloudflare below) so the dnsChallenge resolver can complete.
CRDs & IngressRoute
Notes
According to the notes on Traefik & Kubernetes
we first need to install the Resource Definitions and RBAC into kubectl by running the following commands:
# Install Traefik Resource Definitions:kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
# Install RBAC for Traefik:kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v2.8/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.ymlAfter this installation, we’ll have a set of Custom Resource Definitions which should have the following benefits:
- The usage of
nameandnamespaceto refer to another Kubernetes resource. - The usage of secret for sensitive data (TLS certificates and credentials).
- The structure of the configuration.
- The requirement to declare all the definitions.
See the list of CRDs in the dedicated routing section.
The biggest thing we need from this is the ability to add the BasicAuth plugin.
This plugin (which is what we tried to reference before with the auth@file line) uses an htpasswd password to block incoming traffic to the pod.
This will require setting up an IngressRoute (which is a specific Kubernetes resource added by the Traefik Resource Definitions) with settings to specify what the middlewares are. Find more info on the Traefik Middlewares Here
IngressRoute Example
Section titled “IngressRoute Example”IngressRoute is Traefik’s native alternative to the standard Kubernetes Ingress. It exposes Traefik-specific features — middleware chains, TLS resolvers, and match rules — directly, without annotation soup. This route attaches the longhorn-auth middleware from the previous example:
apiVersion: traefik.io/v1alpha1kind: IngressRoutemetadata: name: longhorn-route namespace: longhorn-systemspec: entryPoints: - websecure routes: - match: Host(`x.kbve.com`) kind: Rule middlewares: - name: longhorn-auth services: - name: longhorn-service-provider port: 8000 tls: certResolver: letsencryptThe match rule uses Traefik’s expression syntax — combine with &&, ||, and PathPrefix(...) for fine-grained routing. certResolver: letsencrypt triggers automatic ACME certificate issuance for the host.
See every route
Dashboard
Traefik ships a web dashboard that visualizes every router, service, and middleware it has discovered — invaluable for debugging why a route isn’t matching. Enable it with --api.dashboard=true (see the Compose example above), then secure it behind BasicAuth:
labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.kbve.com`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=dashboard-auth" - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$..."Automated TLS
Cloudflare
These are notes on integrating Cloudflare with Traefik, including automating some of the actions so that you may not have to repeat them.
Acme Docs
Section titled “Acme Docs”Access the API Tokens directly from Cloudflare Profile
Common environmental variable names and their purpose:
CF_API_EMAIL- The Cloudflare account holder’s email.CF_API_KEY- The Cloudflare API key.CF_DNS_API_TOKEN- The API token withDNS:Editpermission.CF_ZONE_API_TOKEN- The API token withZone:Readpermission.
Questions
Frequently asked
What is Traefik?
Traefik is a cloud-native reverse proxy and load balancer that automatically discovers services from providers like Docker and Kubernetes, and provisions Let's Encrypt TLS certificates without manual configuration.
How is Traefik different from Nginx?
Traefik discovers routes dynamically from labels and CRDs, so it reconfigures itself as containers start and stop. Nginx uses static config files that require a reload. Traefik also ships automatic ACME TLS, whereas Nginx needs an external tool like certbot.
What is a Traefik middleware?
Middleware modifies requests or responses as they pass through a router — for example BasicAuth, rate limiting, or header rewrites. On Kubernetes it is a Middleware CRD referenced from an Ingress or IngressRoute by namespace-qualified name.
How does Traefik get TLS certificates from Cloudflare?
Traefik uses the ACME DNS-01 challenge with Cloudflare's API. You supply a scoped API token (DNS:Edit and Zone:Read) via environment variables, and Traefik creates the required DNS TXT record automatically to prove domain ownership.
What is the difference between Ingress and IngressRoute in Traefik?
Ingress is the standard Kubernetes resource that Traefik supports via annotations. IngressRoute is Traefik's own CRD that exposes middleware chains, TLS resolvers, and expressive match rules directly, without relying on annotations.
How do I secure the Traefik dashboard?
Enable it with --api.dashboard=true, then attach a BasicAuth middleware referencing api@internal and never expose it publicly without authentication. In Docker Compose, escape dollar signs in the htpasswd hash as double dollar signs.
Why does my Traefik htpasswd password break in Docker Compose?
Compose treats a single dollar sign as variable substitution. Escape every dollar sign in the BasicAuth hash as a double dollar sign so the literal htpasswd value is passed through to Traefik.
How does Traefik discover services automatically?
Traefik watches a provider — the Docker socket, Kubernetes CRDs, or a config file — and builds routers from labels or resources as containers start and stop. This is why it needs no manual reload when your services change.
