NGINX Architecture for RKE2

RKE2 used to ship the Ingress NGINX Controller as its built-in ingress. That project is now retired, and RKE2 v1.36 deploys Traefik by default on new clusters. This page covers the current known good design for ingress on RKE2 and how to move existing clusters off ingress-nginx.

Status of Ingress NGINX

  • Upstream: Kubernetes SIG Network and the Security Response Committee announced on November 11, 2025 that Ingress NGINX would be retired in March 2026. After that there are no further releases, bug fixes, or security patches, and the repositories become read-only (announcement). The Steering and Security Response Committees repeated the warning on January 29, 2026 (statement). They recommend migrating to Gateway API or another Ingress controller.
  • RKE2: According to the RKE2 networking services docs:
    • Starting with v1.36, Traefik is the default ingress controller for new clusters.
    • v1.36 still ships ingress-nginx as deprecated. You must opt in with ingress-controller: ingress-nginx.
    • In v1.37, ingress-nginx is removed and unavailable for new clusters.
    • The RKE2 docs note that SUSE Rancher Prime LTS customers get extended Ingress NGINX support through December 2027 (migration guide). Everyone else should migrate.

Choosing the Ingress Controller

RKE2 selects its packaged ingress controller with the ingress-controller key in /etc/rancher/rke2/config.yaml on every server node:

yaml
# traefik (default for new clusters on v1.36+), ingress-nginx (deprecated), or none
ingress-controller: traefik

Set none if you deploy your own controller or rely only on Gateway API through another implementation.

To see what an existing cluster runs:

bash
kubectl get ingressclass
kubectl -n kube-system get daemonset | grep -E 'traefik|ingress-nginx'

How RKE2 Deploys Traefik

RKE2 manages Traefik as the rke2-traefik HelmChart in kube-system, upgraded together with RKE2 itself. The RKE2 packaging of the upstream Traefik chart changes several defaults (see the rke2-traefik chart patch):

SettingUpstream Traefik chartRKE2 rke2-traefik
Workload kindDeploymentDaemonSet
Host portsnone80 and 443 on every node
Service typeLoadBalancerClusterIP
IngressClassdefault class, unnamedtraefik, not marked default

Because Traefik binds host ports 80 and 443 on every node, you can put any layer 4 load balancer (hardware, cloud, kube-vip, or DNS round robin) in front of the nodes on those ports. Ports 80 and 443 on the nodes are then not available for other HostPort or NodePort services.

Set ingressClassName: traefik explicitly on your Ingress objects so they do not depend on a cluster default class.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
  namespace: default
spec:
  ingressClassName: traefik
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: example
            port:
              number: 80

Customizing Traefik on RKE2

Do not edit the HelmChart object directly; RKE2 overwrites it. Use a HelmChartConfig named rke2-traefik in kube-system, either applied with kubectl or dropped into /var/lib/rancher/rke2/server/manifests/ on a server node:

yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: rke2-traefik
  namespace: kube-system
spec:
  valuesContent: |-
    logs:
      general:
        level: INFO
    ports:
      websecure:
        transport:
          respondingTimeouts:
            readTimeout: 600s

The valuesContent keys are values of the upstream Traefik Helm chart. RKE2’s own example in the networking docs sets the log level the same way.

Gateway API

The RKE2 docs state that Gateway API on RKE2 requires Traefik. Enable Traefik’s Gateway provider in the same HelmChartConfig:

yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: rke2-traefik
  namespace: kube-system
spec:
  valuesContent: |-
    providers:
      kubernetesGateway:
        enabled: true

The RKE2 docs list Traefik v3.7.x with Gateway API v1.5. From v1.37, the Gateway API CRDs ship in a standalone chart instead of with Traefik. Before the April 2026 RKE2 releases, disabling Traefik after enabling it removed the Gateway API CRDs (and every Gateway and HTTPRoute with them), so do not toggle Traefik off on clusters that use Gateway API.

After enabling, check the class name before writing Gateways:

bash
kubectl get gatewayclass

Migrating an Existing ingress-nginx Cluster

Upgrading an existing cluster does not by itself move your Ingress objects. Follow the RKE2 ingress migration guide; in short:

  1. Set ingressClassName: nginx explicitly on every existing Ingress.
  2. On each server, set ingress-controller to both controllers (ingress-nginx and traefik) and add a rke2-traefik HelmChartConfig that moves Traefik to ports 8000 and 8443 and enables Traefik’s Ingress NGINX compatibility provider (kubernetesIngressNGINX).
  3. Restart rke2-server on the control plane nodes and confirm both the rke2-ingress-nginx-controller and rke2-traefik DaemonSets are running.
  4. Create copies of your Ingresses with the migration IngressClass rke2-ingress-nginx-migration and test them through ports 8000 and 8443. Load balancer health checks differ: /healthz for NGINX, /ping for Traefik.
  5. Set ingress-controller to only traefik, remove the temporary ports from the HelmChartConfig, and restart.
  6. Delete the old nginx Ingress objects.

Traefik’s compatibility provider does not support every NGINX annotation. Check the Traefik Ingress NGINX provider docs for your annotations, especially configuration-snippet and other snippet annotations, before migrating. The RKE2 guide notes the provider name in the HelmChartConfig changed from kubernetesIngressNginx to kubernetesIngressNGINX in the June 2026 RKE2 releases.

Rancher-provisioned downstream RKE2 clusters have their own migration guide in the Rancher documentation, linked from the RKE2 for Rancher page.


Design of NGINX Ingress Controller on RKE2

The diagram above shows the legacy ingress-nginx layout. Traefik on RKE2 follows the same pattern: one controller pod per node, bound to host ports 80 and 443, with an external layer 4 load balancer in front of the nodes.


References