Traefik Ingress

Introduction

This page describes how to use various features of Traefik as an Ingress Controller in your Kubernetes cluster. These are the most common examples we notice when helping our customers to set up Ingresses.

Pre-requisites

First determine whether you want to use Traefik for your Ingress, we offer several options depending on your needs: Explanation: Ingress.

The Traefik Ingress Controller(s) also need to be deployed in your cluster. Usually this is determined and set-up during customer onboarding, however you can verify if Traefik is enabled by checking your Cluster Definition files for the following snippets:

apiVersion: skyscrapers.eu/v1beta2
kind: EksCluster
metadata:
  [...]
spec:
  [...]
  traefik:
    public:
      enabled: true
      [...]
    internal:
      enabled: true
      [...]

To ensure Traefik is correctly deployed, get in touch with our support team. By default you should have at least the internal-only controller deployed, as this is used for dashboarding like Grafana etc.

General usage

To create a basic Internet-facing Ingress with Traefik, you need to create an Ingress resource with the appropriate ingressClassName. Below is an example of a simple Ingress that routes traffic for foo.example.com to a backend Service named foo in the default namespace:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: my-public-ingress
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: foo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: # you need to point this to your app's K8s Service
                name: foo
                port:
                  name: http
  tls:
    - secretName: foo-example-com-tls
      hosts:
        - foo.example.com

There are a couple of other things that are happening in the background to make this work:

  1. The cert-manager.io/cluster-issuer: letsencrypt-prod annotation tells cert-manager to automatically issue a TLS certificate for this Ingress using Let’s Encrypt. The certificate will be requested for the specified hosts and stored in the foo-example-com-tls Secret. Further examples on how to use cert-manager with Traefik check our Cert-Manager How To Guide.
  2. Through external-dns we will automatically create a DNS A record for foo.example.com pointing to the Traefik load balancer. This requires that the DNS zone for example.com is hosted in Route53 in the same AWS account as the cluster.
    • If you don’t wish to auto-create a DNS record for this Ingress, you can add the annotation external-dns.alpha.kubernetes.io/exclude: "true" to disable this for this specific Ingress, for example when using an external CDN like CloudFront or Cloudflare.
  3. By default we will listen on both HTTP and HTTPS, where HTTP traffic is automatically redirected to HTTPS. You can disable this behaviour as described below.

Internal vs Internet-facing Ingress

The Skyscrapers platform supports both internal and Internet-facing Ingresses with Traefik. Internal-only Ingresses are only exposed within the AWS VPC, while Internet-facing Ingresses are exposed to the public Internet.

You can specify this by setting the appropriate IngressClassName when creating your Ingress resource:

  • traefik for Internet-facing Ingresses
  • traefik-internal for internal-only Ingresses

Internal-only example:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-ip-allowlist@kubernetescrd
  name: my-private-ingress
  namespace: default
spec:
  ingressClassName: traefik-internal
  rules: []

Note

It’s important to remember that, by default, internal Ingresses will automatically have public DNS resolving configured like a normal Internet-facing Ingresses. This means anybody outside the VPC can still resolve the DNS name, but it will resolve to private IP addresses that are not reachable from the Internet. This is because we don’t currently support private hosted zones in Route53. Similarly, if you add the cert-manager.io/cluster-issuer: letsencrypt-prod annotation for automatic TLS certificates, the domain name will be registered in the public Certificate Transparency logs, even though the Ingress is internal-only.

Installing Traefik plugins

Traefik supports plugins — Go modules loaded at Traefik startup that extend its functionality (most commonly as custom middlewares). Plugin support on the Skyscrapers platform is opt-in behind a feature gate, since plugins run arbitrary third-party code inside Traefik and a broken plugin can take down the ingress.

To enable plugins:

  1. Turn on the feature gate at the cluster spec top level:

    spec:
      featureGates:
        traefikPlugins: true
  2. Declare each plugin under traefik.public.plugins and/or traefik.internal.plugins. Entries are keyed by a plugin name of your choice and must specify a moduleName (Go module path from the Traefik Plugin Catalog) and a version (Git tag):

    spec:
      traefik:
        public:
          plugins:
            plugindemo:
              moduleName: github.com/traefik/plugindemo
              version: v0.2.2
        internal:
          plugins:
            plugindemo:
              moduleName: github.com/traefik/plugindemo
              version: v0.2.2

Once Traefik has rolled out, use the plugin by creating a Middleware that references it — the spec field matches the plugin’s name key. Check the plugin’s own documentation for its configuration schema; it differs per plugin.

Warning

Plugins are downloaded and loaded during Traefik startup. Adding, changing, or removing a plugin triggers a Traefik rollout; more plugins mean slower pod startup, and startup will fail outright if a plugin module is unavailable (GitHub outage, bad module path, yanked version). You are responsible for plugin selection, version pinning, and compatibility — a broken plugin can break Traefik.

If the featureGates.traefikPlugins gate is off, any entries under traefik.*.plugins are silently ignored.

Using Traefik Middlewares

Traefik uses the concept of Middlewares to modify requests and responses. Middlewares are defined as separate Kubernetes Custom Resources (CRDs) and then referenced from your Ingress via annotations.

The general pattern is:

  1. Create a Middleware Custom Resource in your namespace
  2. Reference it from your Ingress using the annotation: traefik.ingress.kubernetes.io/router.middlewares: <namespace>-<middleware-name>@kubernetescrd

You can chain multiple middlewares by comma-separating them:

annotations:
  traefik.ingress.kubernetes.io/router.middlewares: default-auth@kubernetescrd,default-ratelimit@kubernetescrd

Tip

If you want to create shared middlewares that can be used across multiple namespaces, consider creating them in a common namespace (e.g., default, production) and referencing them in your Ingress annotations. Please only use application-specific namespaces, and not any of the platform namespaces like infrastructure or traefik; these are reserved for Skyscrapers-provided components and middlewares.

Basic authentication

Upstream documentation

Traefik’s BasicAuth middleware requires credentials in htpasswd format, stored in a Kubernetes Secret.

Generate htpasswd credentials:

# Generate a password hash (requires apache2-utils or httpd-tools)
htpasswd -nb admin t0p-Secret
# Output: admin:$apr1$xyz123$hashedpasswordhere

Example:

---
# Secret containing htpasswd-formatted credentials
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth-secret
  namespace: default
type: Opaque
stringData:
  users: |
    admin:$apr1$xyz123$hashedpasswordhere
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: basic-auth
  namespace: default
spec:
  basicAuth:
    secret: basic-auth-secret
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-basic-auth@kubernetescrd
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

For multiple users, add one per line in the users field:

stringData:
  users: |
    admin:$apr1$...
    developer:$apr1$...
    readonly:$apr1$...

Note

This differs from ingress-nginx which uses kubernetes.io/basic-auth type secrets. When migrating, you’ll need to regenerate secrets in htpasswd format.

Buffering

Upstream documentation

The Buffering middleware controls how Traefik reads and buffers requests and responses. This is useful for handling large uploads or protecting backends from slow clients.

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: buffering
  namespace: default
spec:
  buffering:
    maxRequestBodyBytes: 10485760    # 10MB - max request body size
    memRequestBodyBytes: 2097152     # 2MB - threshold before buffering to disk
    maxResponseBodyBytes: 10485760   # 10MB - max response body size
    memResponseBodyBytes: 2097152    # 2MB - threshold before buffering to disk
    retryExpression: "IsNetworkError() && Attempts() < 3"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-buffering@kubernetescrd
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

CORS

Upstream documentation

CORS (Cross-Origin Resource Sharing) is configured using the Headers middleware. When CORS headers are set, Traefik handles preflight (OPTIONS) requests automatically without forwarding them to the backend.

Basic CORS example:

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: cors
  namespace: default
spec:
  headers:
    accessControlAllowMethods:
      - "GET"
      - "POST"
      - "PUT"
      - "DELETE"
      - "OPTIONS"
    accessControlAllowHeaders:
      - "Content-Type"
      - "Authorization"
    accessControlAllowOriginList:
      - "https://app.example.com"
      - "https://admin.example.com"
    accessControlMaxAge: 86400
    addVaryHeader: true
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-cors@kubernetescrd
  name: api
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

Allow all origins (use with caution):

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: cors-allow-all
  namespace: default
spec:
  headers:
    accessControlAllowMethods:
      - "GET"
      - "POST"
      - "PUT"
      - "DELETE"
      - "OPTIONS"
    accessControlAllowHeaders:
      - "*"
    accessControlAllowOriginList:
      - "*"
    accessControlMaxAge: 86400
    addVaryHeader: true

With credentials support (cannot use * for origin):

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: cors-with-credentials
  namespace: default
spec:
  headers:
    accessControlAllowMethods:
      - "GET"
      - "POST"
      - "OPTIONS"
    accessControlAllowHeaders:
      - "Content-Type"
      - "Authorization"
      - "X-Requested-With"
    accessControlAllowOriginList:
      - "https://app.example.com"
    accessControlAllowCredentials: true
    accessControlExposeHeaders:
      - "X-Custom-Header"
    accessControlMaxAge: 86400
    addVaryHeader: true

Using regex for origin matching:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: cors-regex
  namespace: default
spec:
  headers:
    accessControlAllowMethods:
      - "GET"
      - "POST"
    accessControlAllowOriginListRegex:
      - "https://.*\\.example\\.com"  # Match all subdomains
    accessControlMaxAge: 86400
    addVaryHeader: true

Note

By default we provide a shared CORS middleware in the traefik namespace named cors-permissive, which you can reference from your Ingresses as traefik-cors-permissive@kubernetescrd. This CORS middleware is based upon the old ingress-nginx defaults and meant as a drop-in replacement.

Custom TLS configuration

Upstream documentation

To configure custom TLS options (minimum version, cipher suites), create a TLSOption resource:

---
apiVersion: traefik.io/v1alpha1
kind: TLSOption
metadata:
  name: strict-tls
  namespace: default
spec:
  minVersion: VersionTLS12
  cipherSuites:
    - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
  curvePreferences:
    - CurveP521
    - CurveP384
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.tls.options: default-strict-tls@kubernetescrd
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules: []
  tls:
    - secretName: foo-tls
      hosts:
        - foo.example.com

For TLS 1.3 only:

apiVersion: traefik.io/v1alpha1
kind: TLSOption
metadata:
  name: tls13-only
  namespace: default
spec:
  minVersion: VersionTLS13

TLS/SSL Passthrough

Upstream documentation

To enable TLS/SSL passthrough (for end-to-end TLS), you need to create an IngressRouteTCP resource instead of a normal Ingress as we’ll leave the TLS termination to the backend service instead of Traefik.

Example:

apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
  name: foo
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
    - match: HostSNI(`foo.example.com`)
      services:
        - name: foo
          port: 8443
  tls:
    passthrough: true
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: foo.example.com

Note

The Ingress object is not strictly necessary here, but it allows external-dns to automatically create the DNS record for foo.example.com. At a later time we will try to automate this process for IngressRouteTCP resources as well.

Disable automatic HTTPS redirection

By default, our Traefik controller redirects HTTP traffic to HTTPS. To disable this for a specific Ingress, create an IngressRoute with a higher priority than our default redirection rule (100).

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: foo
  namespace: default
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`foo.example.com`)
      kind: Rule
      priority: 200
      services:
        - name: foo
          port: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: foo.example.com

Note

The Ingress object is not strictly necessary here, but it allows external-dns to automatically create the DNS record for foo.example.com. At a later time we will try to automate this process for IngressRoute resources as well.

IP allowlisting

Upstream documentation

Restrict access to specific IP ranges using the IPAllowList middleware:

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: ip-allowlist
  namespace: default
spec:
  ipAllowList:
    sourceRange:
      - "10.0.0.0/8"
      - "172.16.0.0/12"
      - "192.168.0.0/16"
      - "203.0.113.0/24"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-ip-allowlist@kubernetescrd
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

Tip

You can create a shared IPAllowList middleware in a common namespace and reference it across multiple Ingresses. This makes it easier to maintain a central list of allowed IPs.

OAuth / OIDC integration

Upstream documentation

Traefik supports external authentication via the ForwardAuth middleware. This allows integration with OAuth2-Proxy, which we provide by default.

Example using our OAuth2-Proxy service for authentication:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: infrastructure-oauth-errors@kubernetescrd,infrastructure-oauth-auth@kubernetescrd
  name: protected-app
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

Rate limiting

Upstream documentation

Traefik has native rate limiting support via the RateLimit middleware:

Basic rate limiting:

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: ratelimit
  namespace: default
spec:
  rateLimit:
    average: 100   # Average requests per second
    burst: 50      # Maximum burst size
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    traefik.ingress.kubernetes.io/router.middlewares: default-ratelimit@kubernetescrd
  name: foo
  namespace: default
spec:
  ingressClassName: traefik
  rules: []

Rate limiting per client IP:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: ratelimit-per-ip
  namespace: default
spec:
  rateLimit:
    average: 10
    period: 1m     # Per minute instead of per second
    burst: 20
    sourceCriterion:
      ipStrategy: {}

Rate limiting by header (e.g., API key):

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: ratelimit-by-apikey
  namespace: default
spec:
  rateLimit:
    average: 100
    burst: 50
    sourceCriterion:
      requestHeaderName: X-API-Key

Redirects

Upstream documentation | RedirectRegex

Redirect to another domain

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: redirect-domain
  namespace: default
spec:
  redirectRegex:
    regex: "^https://old-domain\\.com/(.*)"
    replacement: "https://new-domain.com/${1}"
    permanent: true

Non-www to www redirect

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: www-redirect
  namespace: default
spec:
  redirectRegex:
    regex: "^https://example\\.com/(.*)"
    replacement: "https://www.example.com/${1}"
    permanent: true

Redirect with path modification

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: redirect-path
  namespace: default
spec:
  redirectRegex:
    regex: "^https://example\\.com/old-path/(.*)"
    replacement: "https://example.com/new-path/${1}"
    permanent: true

Session affinity / stickiness

Upstream documentation

Session affinity in Traefik is configured on the Service resource, not on the Ingress. This is a fundamental difference from ingress-nginx.

Example using sticky session annotations on the Service:

---
apiVersion: v1
kind: Service
metadata:
  annotations:
    traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
    traefik.ingress.kubernetes.io/service.sticky.cookie.name: sticky-app-session
    traefik.ingress.kubernetes.io/service.sticky.cookie.secure: "true"
  name: sticky-app
  namespace: default
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app.kubernetes.io/name: sticky-app
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  name: sticky-app
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: foo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: sticky-app
                port:
                  name: http
  tls:
    - secretName: foo-example-com-tls
      hosts:
        - foo.example.com

Timeouts

Timeouts in Traefik are configured at different levels depending on the type:

Response forwarding timeout (via ServersTransport)

For backend connection timeouts, create a ServersTransport:

---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
  name: custom-timeouts
  namespace: default
spec:
  serverName: "backend"
  forwardingTimeouts:
    dialTimeout: 30s           # Time to establish connection
    responseHeaderTimeout: 60s # Time to wait for response headers
    idleConnTimeout: 90s       # Keep-alive timeout
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  namespace: default
  annotations:
    traefik.ingress.kubernetes.io/service.serverstransport: default-custom-timeouts@kubernetescrd
spec:
  ports:
    - port: 80
  selector:
    app: my-app

Request timeout via middleware

For request-level timeouts, you can use a combination of retry and circuit breaker middlewares:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: retry
  namespace: default
spec:
  retry:
    attempts: 3
    initialInterval: 100ms

Note

Traefik doesn’t have direct equivalents for all ingress-nginx proxy timeout annotations. The proxy-read-timeout and proxy-send-timeout are handled via ServersTransport, while request-level timeouts require middleware or service mesh integration.

URL rewriting

Upstream documentation | ReplacePathRegex

Strip path prefix

Remove a prefix from the URL path before forwarding to the backend:

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: strip-api-prefix
  namespace: default
spec:
  stripPrefix:
    prefixes:
      - "/api"
    # forceSlash: false  # Don't add a trailing slash
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-strip-api-prefix@kubernetescrd
  name: api
  namespace: default
spec:
  ingressClassName: traefik
  rules:
    - host: example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

Request to /api/users → Backend receives /users

Strip prefix with regex

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: strip-version-prefix
  namespace: default
spec:
  stripPrefixRegex:
    regex:
      - "/v[0-9]+/"

Request to /v1/users → Backend receives /users

Replace path

Replace the entire path:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: replace-path
  namespace: default
spec:
  replacePath:
    path: "/new-path"

Replace path with regex

For more complex rewriting patterns:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rewrite-api
  namespace: default
spec:
  replacePathRegex:
    regex: "^/api/v1/(.*)"
    replacement: "/internal/$1"

Request to /api/v1/users → Backend receives /internal/users

Add prefix

Add a prefix to all requests:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: add-prefix
  namespace: default
spec:
  addPrefix:
    prefix: "/backend"

Request to /users → Backend receives /backend/users

Migration from ingress-nginx

When migrating from ingress-nginx to Traefik, use this annotation mapping table:

ingress-nginxTraefik
nginx.ingress.kubernetes.io/ssl-redirect: "true"Default behavior (automatic HTTPS redirect)
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"Default behavior
nginx.ingress.kubernetes.io/rewrite-target: /$1StripPrefix or ReplacePathRegex middleware
nginx.ingress.kubernetes.io/whitelist-source-rangeIPAllowList middleware
nginx.ingress.kubernetes.io/auth-url & nginx.ingress.kubernetes.io/auth-signinForwardAuth + Errors middleware chain, use traefik.ingress.kubernetes.io/router.middlewares: infrastructure-oauth-errors@kubernetescrd,infrastructure-oauth-auth@kubernetescrd annotation
nginx.ingress.kubernetes.io/proxy-body-sizeBuffering middleware
nginx.ingress.kubernetes.io/proxy-read-timeoutServersTransport CRD
nginx.ingress.kubernetes.io/enable-corsHeaders middleware with CORS options
nginx.ingress.kubernetes.io/limit-rpsRateLimit middleware
nginx.ingress.kubernetes.io/affinity: cookieUse traefik.ingress.kubernetes.io/service.sticky.cookie* annotations on the Service
nginx.ingress.kubernetes.io/auth-secret (basic auth)BasicAuth middleware with htpasswd secret
nginx.ingress.kubernetes.io/permanent-redirectRedirectRegex middleware
nginx.ingress.kubernetes.io/ssl-ciphersTLSOption CRD

Warning

Custom nginx snippets (server-snippet, configuration-snippet) have no direct equivalent in Traefik. These require refactoring to use appropriate middleware or moving the logic to the application layer.

Installing Traefik plugins

Traefik supports loadable plugins that extend its behavior beyond the built-in middlewares — for example, rewrite-header to modify response headers like Set-Cookie, which isn’t possible with the built-in Headers middleware.

Warning

Plugins are experimental and run inside the Traefik process. You, the customer, are responsible for:

  • Selecting the plugin and pinning a specific version.
  • Keeping the plugin version compatible with the Traefik version currently deployed in your cluster. Plugin upgrades are your responsibility.
  • Testing plugin changes in a non-production cluster first. A broken plugin can prevent Traefik from starting, taking down all ingress traffic.

Installing a plugin is a three-step process: declare the plugin in your Cluster Definition, create a Middleware that uses it, then attach the Middleware to an Ingress.

Step 1 — Declare the plugin in your Cluster Definition

Open a Pull Request against your Cluster Definition repository adding the plugin under spec.traefik.public.plugins (or internal.plugins, or both — they are separate Traefik instances). The key (rewriteheader below) is a name you pick; it’s what you’ll reference in the Middleware later.

apiVersion: skyscrapers.eu/v1beta2
kind: EksCluster
metadata:
  [...]
spec:
  [...]
  traefik:
    public:
      plugins:
        rewriteheader:
          moduleName: github.com/traefik/plugin-rewriteheader
          version: v0.1.0
    internal:
      plugins:
        rewriteheader:
          moduleName: github.com/traefik/plugin-rewriteheader
          version: v0.1.0

Look up moduleName and version on the Traefik Plugin Catalog page for the plugin you want. Once the PR is merged and applied, Traefik rolls out with the plugin available.

Step 2 — Create a Middleware that uses the plugin

Create a Middleware resource in your application namespace with a plugin: spec keyed by the name you used in Step 1. The fields under the plugin name are specific to each plugin — consult the plugin’s documentation.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rewrite-set-cookie
  namespace: my-app
spec:
  plugin:
    rewriteheader:
      rewrites:
        - header: Set-Cookie
          regex: "Domain=example\\.com"
          replacement: "Domain=app.example.com"

Step 3 — Attach the Middleware to your Ingress

Reference the Middleware from your Ingress using the standard traefik.ingress.kubernetes.io/router.middlewares annotation, as described in Using Traefik Middlewares:

annotations:
  traefik.ingress.kubernetes.io/router.middlewares: my-app-rewrite-set-cookie@kubernetescrd

Troubleshooting

If Traefik fails to start after a plugin change (pods in CrashLoopBackOff), check the Traefik logs for the plugin load error:

kubectl logs -n traefik deploy/traefik-public
kubectl logs -n traefik deploy/traefik-internal

To recover, revert the Cluster Definition PR that added or changed the plugin. The previous Traefik pods keep serving until the failed rollout is reverted.

Further reading

Last updated on