Skip to content

Traefik & Ingresses with NGINX Annotations

Enable seamless migration from NGINX Ingress Controller to Traefik with NGINX annotation compatibility.

NGINX Ingress Controller Retirement

The Kubernetes NGINX Ingress Controller project has announced its retirement in March 2026 and will no longer receive updates or security patches. Traefik provides a migration path by supporting NGINX annotations, allowing you to transition your workloads without rewriting all your Ingress configurations.

For more information about the NGINX Ingress Controller retirement, see the official Kubernetes blog announcement.

Ingress Discovery

This provider discovers all Ingresses in the cluster by default, which may lead to duplicated routers if you are also using the standard Kubernetes Ingress provider.

Best Practices:

  • Use IngressClass to specify which Ingresses should be handled by this provider
  • Configure watchNamespace to limit discovery to specific namespaces
  • Use watchNamespaceSelector to target Ingresses based on namespace labels

Routing Configuration

This provider watches for incoming Ingress events and automatically translates NGINX annotations into Traefik's dynamic configuration, creating the corresponding routers, services, middlewares, and other components needed to handle your traffic.

Configuration Example

Configuring Kubernetes Ingress NGINX Controller
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: traefik-ingress-controller
rules:
  - apiGroups:
      - ""
    resources:
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - endpoints
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingressclasses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - discovery.k8s.io
    resources:
      - endpointslices
    verbs:
      - list
      - watch
      - get

    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: traefik-ingress-controller
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: traefik-ingress-controller
    subjects:
      - kind: ServiceAccount
        name: traefik-ingress-controller
        namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: traefik-ingress-controller

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: traefik
  labels:
    app: traefik

spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      containers:
        - name: traefik
          image: traefik:v3.6
          args:
            - --entryPoints.web.address=:80
            - --providers.kubernetesingressnginx
          ports:
            - name: web
              containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: traefik
spec:
  type: LoadBalancer
  selector:
    app: traefik
  ports:
    - name: web
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
  labels:
    app: whoami

spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: traefik/whoami
          ports:
            - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: whoami

spec:
  selector:
    app: whoami
  ports:
    - name: http
      port: 80
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress

spec:
  ingressClassName: nginx
  rules:
    - host: whoami.localhost
      http:
        paths:
          - path: /bar
            pathType: Exact
            backend:
              service:
                name:  whoami
                port:
                  number: 80
          - path: /foo
            pathType: Exact
            backend:
              service:
                name:  whoami
                port:
                  number: 80

Annotations Support

This section lists all known NGINX Ingress annotations. The following annotations are organized by category for easier navigation.

Authentication

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/auth-type
nginx.ingress.kubernetes.io/auth-secret
nginx.ingress.kubernetes.io/auth-secret-type
nginx.ingress.kubernetes.io/auth-realm
nginx.ingress.kubernetes.io/auth-url Only URL and response headers copy supported. Forward auth behaves differently than NGINX.
nginx.ingress.kubernetes.io/auth-method
nginx.ingress.kubernetes.io/auth-response-headers

SSL/TLS

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/ssl-redirect Cannot opt-out per route if enabled globally.
nginx.ingress.kubernetes.io/force-ssl-redirect Cannot opt-out per route if enabled globally.
nginx.ingress.kubernetes.io/ssl-passthrough Some differences in SNI/default backend handling.
nginx.ingress.kubernetes.io/proxy-ssl-server-name
nginx.ingress.kubernetes.io/proxy-ssl-name
nginx.ingress.kubernetes.io/proxy-ssl-verify
nginx.ingress.kubernetes.io/proxy-ssl-secret

Session Affinity

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/affinity
nginx.ingress.kubernetes.io/affinity-mode Only persistent mode supported; balanced/canary not supported.
nginx.ingress.kubernetes.io/session-cookie-name
nginx.ingress.kubernetes.io/session-cookie-path
nginx.ingress.kubernetes.io/session-cookie-domain
nginx.ingress.kubernetes.io/session-cookie-samesite

Load Balancing & Backend

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/load-balance Only round_robin supported; ewma and IP hash not supported.
nginx.ingress.kubernetes.io/backend-protocol FCGI and AUTO_HTTP not supported.
nginx.ingress.kubernetes.io/service-upstream

CORS

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/enable-cors Partial support.
nginx.ingress.kubernetes.io/cors-allow-credentials
nginx.ingress.kubernetes.io/cors-allow-headers
nginx.ingress.kubernetes.io/cors-allow-methods
nginx.ingress.kubernetes.io/cors-allow-origin
nginx.ingress.kubernetes.io/cors-max-age

Routing

Annotation Limitations / Notes
nginx.ingress.kubernetes.io/use-regex

Limitations

Caveats and Key Behavioral Differences

  • Authentication: Forward auth behaves differently and session caching is not supported. NGINX supports sub-request based auth, while Traefik forwards the original request.
  • Session Affinity: Only persistent mode is supported.
  • Leader Election: Not supported; no cluster mode with leader election.
  • Default Backend: Only defaultBackend in Ingress spec is supported; the annotation is ignored.
  • Load Balancing: Only round_robin is supported; EWMA and IP hash are not supported.
  • CORS: NGINX responds with all configured headers unconditionally; Traefik handles headers differently between pre-flight and regular requests.
  • TLS/Backend Protocols: AUTO_HTTP, FCGI and some TLS options are not supported in Traefik.
  • Path Handling: Traefik preserves trailing slashes by default; NGINX removes them unless configured otherwise

Unsupported Annotations

Want to Add Support for More Annotations?

You can help extend support in two ways:

All contributions and suggestions are welcome — let's build this together!

Annotation Notes
nginx.ingress.kubernetes.io/app-root
nginx.ingress.kubernetes.io/affinity-canary-behavior
nginx.ingress.kubernetes.io/auth-tls-secret
nginx.ingress.kubernetes.io/auth-tls-verify-depth
nginx.ingress.kubernetes.io/auth-tls-verify-client
nginx.ingress.kubernetes.io/auth-tls-error-page
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream
nginx.ingress.kubernetes.io/auth-tls-match-cn
nginx.ingress.kubernetes.io/auth-cache-key
nginx.ingress.kubernetes.io/auth-cache-duration
nginx.ingress.kubernetes.io/auth-keepalive
nginx.ingress.kubernetes.io/auth-keepalive-share-vars
nginx.ingress.kubernetes.io/auth-keepalive-requests
nginx.ingress.kubernetes.io/auth-keepalive-timeout
nginx.ingress.kubernetes.io/auth-proxy-set-headers
nginx.ingress.kubernetes.io/auth-snippet
nginx.ingress.kubernetes.io/enable-global-auth
nginx.ingress.kubernetes.io/canary
nginx.ingress.kubernetes.io/canary-by-header
nginx.ingress.kubernetes.io/canary-by-header-value
nginx.ingress.kubernetes.io/canary-by-header-pattern
nginx.ingress.kubernetes.io/canary-by-cookie
nginx.ingress.kubernetes.io/canary-weight
nginx.ingress.kubernetes.io/canary-weight-total
nginx.ingress.kubernetes.io/client-body-buffer-size
nginx.ingress.kubernetes.io/configuration-snippet
nginx.ingress.kubernetes.io/custom-http-errors
nginx.ingress.kubernetes.io/disable-proxy-intercept-errors
nginx.ingress.kubernetes.io/default-backend Use defaultBackend in Ingress spec.
nginx.ingress.kubernetes.io/limit-rate-after
nginx.ingress.kubernetes.io/limit-rate
nginx.ingress.kubernetes.io/limit-whitelist
nginx.ingress.kubernetes.io/limit-rps
nginx.ingress.kubernetes.io/limit-rpm
nginx.ingress.kubernetes.io/limit-burst-multiplier
nginx.ingress.kubernetes.io/limit-connections
nginx.ingress.kubernetes.io/global-rate-limit
nginx.ingress.kubernetes.io/global-rate-limit-window
nginx.ingress.kubernetes.io/global-rate-limit-key
nginx.ingress.kubernetes.io/global-rate-limit-ignored-cidrs
nginx.ingress.kubernetes.io/permanent-redirect
nginx.ingress.kubernetes.io/permanent-redirect-code
nginx.ingress.kubernetes.io/temporal-redirect
nginx.ingress.kubernetes.io/preserve-trailing-slash Traefik preserves trailing slash by default.
nginx.ingress.kubernetes.io/proxy-cookie-domain
nginx.ingress.kubernetes.io/proxy-cookie-path
nginx.ingress.kubernetes.io/proxy-connect-timeout
nginx.ingress.kubernetes.io/proxy-send-timeout
nginx.ingress.kubernetes.io/proxy-read-timeout
nginx.ingress.kubernetes.io/proxy-next-upstream
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout
nginx.ingress.kubernetes.io/proxy-next-upstream-tries
nginx.ingress.kubernetes.io/proxy-request-buffering
nginx.ingress.kubernetes.io/proxy-redirect-from
nginx.ingress.kubernetes.io/proxy-redirect-to
nginx.ingress.kubernetes.io/proxy-http-version
nginx.ingress.kubernetes.io/proxy-ssl-ciphers
nginx.ingress.kubernetes.io/proxy-ssl-verify-depth
nginx.ingress.kubernetes.io/proxy-ssl-protocols
nginx.ingress.kubernetes.io/enable-rewrite-log
nginx.ingress.kubernetes.io/rewrite-target
nginx.ingress.kubernetes.io/satisfy
nginx.ingress.kubernetes.io/server-alias
nginx.ingress.kubernetes.io/server-snippet
nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none
nginx.ingress.kubernetes.io/session-cookie-expires
nginx.ingress.kubernetes.io/session-cookie-change-on-failure
nginx.ingress.kubernetes.io/ssl-ciphers
nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers
nginx.ingress.kubernetes.io/connection-proxy-header
nginx.ingress.kubernetes.io/enable-access-log
nginx.ingress.kubernetes.io/enable-opentracing
nginx.ingress.kubernetes.io/opentracing-trust-incoming-span
nginx.ingress.kubernetes.io/enable-opentelemetry
nginx.ingress.kubernetes.io/opentelemetry-trust-incoming-span
nginx.ingress.kubernetes.io/enable-modsecurity
nginx.ingress.kubernetes.io/enable-owasp-core-rules
nginx.ingress.kubernetes.io/modsecurity-transaction-id
nginx.ingress.kubernetes.io/modsecurity-snippet
nginx.ingress.kubernetes.io/mirror-request-body
nginx.ingress.kubernetes.io/mirror-target
nginx.ingress.kubernetes.io/mirror-host
nginx.ingress.kubernetes.io/x-forwarded-prefix
nginx.ingress.kubernetes.io/upstream-hash-by
nginx.ingress.kubernetes.io/upstream-vhost
nginx.ingress.kubernetes.io/denylist-source-range
nginx.ingress.kubernetes.io/whitelist-source-range
nginx.ingress.kubernetes.io/proxy-buffering
nginx.ingress.kubernetes.io/proxy-buffers-number
nginx.ingress.kubernetes.io/proxy-buffer-size
nginx.ingress.kubernetes.io/proxy-max-temp-file-size
nginx.ingress.kubernetes.io/stream-snippet

Global Configuration

Traefik does not expose all global configuration options to control default behaviors for Ingresses in the same way NGINX does.

Some behaviors that are globally configurable in NGINX (such as default SSL redirect, rate limiting, or affinity) are currently not supported and cannot be overridden per-Ingress as in NGINX. These limitations are noted in the annotation tables below where applicable.