From 3910ad2769b65013811206e97b8aa17f9742116b Mon Sep 17 00:00:00 2001 From: vthwang Date: Mon, 17 Aug 2026 03:25:03 -0700 Subject: [PATCH 1/2] fix: set the Traefik entrypoints through Rancher, not kubectl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every fpp cluster is Rancher-managed, and Rancher owns the HelmChartConfig object (objectset.rio.cattle.io/owner-name: managed-chart-config). Applying it with kubectl holds until the next sync or upgrade and is then reverted, which is the same thing that kept wiping ingress-nginx's default-ssl-certificate. The values belong in the cluster's rkeConfig.chartValues; the manifest stays for clusters Rancher does not manage. Trimmed to what is not already a chart default. Only the redirect and isDefaultClass were doing anything — the providers block and the websecure TLS flag matched the chart's own values, and websecure TLS is kept explicit only because its silent absence takes down HTTPS everywhere. Also worth knowing when verifying: a values change re-runs the helm-install job whether or not it changes anything, so a completed job proves nothing. dev has the proof — the job re-ran while the pod stayed older than it, because the mistyped paths rendered identical args. Read the rendered args instead. Signed-off-by: vthwang --- README.md | 45 +++++++++++++++++--- k8s/tls/rke2-traefik-config.yaml | 73 +++++++------------------------- 2 files changed, 54 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index ddae96b..cf0c2ee 100644 --- a/README.md +++ b/README.md @@ -178,17 +178,50 @@ runs elsewhere in your cluster. #### Step 4 — Configure Traefik -RKE2 manages its bundled ingress controller through the `HelmChartConfig` CRD. -Two objects: the controller's entrypoints, and the default certificate. +Two things: the controller's entrypoints, and the default certificate. + +**Entrypoints — through Rancher, not kubectl.** All fpp clusters are +Rancher-managed, and Rancher owns the `HelmChartConfig` object +(`objectset.rio.cattle.io/owner-name: managed-chart-config`). A `kubectl apply` +holds until the next sync or upgrade and is then reverted — this is exactly +what kept wiping ingress-nginx's `default-ssl-certificate`. Put the values in +the cluster spec so they survive: + +Rancher UI → Cluster Management → the cluster → Edit YAML → `rkeConfig.chartValues`: + +```yaml +rkeConfig: + chartValues: + rke2-traefik: + ingressClass: + isDefaultClass: true + ports: + web: + http: + redirections: + entryPoint: + to: websecure + scheme: https + permanent: true + websecure: + http: + tls: + enabled: true +``` + +Drop any `rke2-ingress-nginx` entry while you are in there; it is dead once the +controller is gone. On a cluster Rancher does not manage, the same values are +in `k8s/tls/rke2-traefik-config.yaml` — `kubectl apply` that instead. + +**The default certificate** is a plain CRD object, not chart config, so Rancher +never touches it: ```bash -kubectl apply -f k8s/tls/rke2-traefik-config.yaml kubectl apply -f k8s/tls/tlsstore-default.yaml ``` -RKE2 reconciles the change and restarts Traefik automatically. After this every -Ingress gets HTTPS and an HTTP→HTTPS redirect with no annotation, `tls:` block -or cert-manager annotation of its own. +After this every Ingress gets HTTPS and an HTTP→HTTPS redirect with no +annotation, `tls:` block or cert-manager annotation of its own. Verify before going further — this is the step whose failure shows up several minutes later as a mediator crash loop rather than as a TLS error. diff --git a/k8s/tls/rke2-traefik-config.yaml b/k8s/tls/rke2-traefik-config.yaml index c8b9182..cbb25a4 100644 --- a/k8s/tls/rke2-traefik-config.yaml +++ b/k8s/tls/rke2-traefik-config.yaml @@ -1,57 +1,23 @@ -# Ingress controller configuration — the settings that used to be per-Ingress -# annotations under ingress-nginx. +# Traefik entrypoint settings — the HTTP→HTTPS redirect that replaces +# ingress-nginx's per-Ingress ssl-redirect annotation. # -# kubectl apply -f k8s/tls/rke2-traefik-config.yaml +# ⚠️ On a Rancher-managed cluster this object belongs to Rancher +# (objectset.rio.cattle.io/owner-name: managed-chart-config). Applying it with +# kubectl works until the next sync or upgrade, which reverts it — the same way +# rke2-ingress-nginx kept losing its default-ssl-certificate. There, put these +# same values in the cluster's rkeConfig.chartValues instead; see README §1 +# Step 4. This file is for clusters Rancher does not manage. # -# RKE2 reconciles the change and restarts Traefik on its own. If Rancher manages -# this cluster it also writes to this object (it injects global.cattle.clusterId) -# — the values merge, but check the object after applying rather than assuming. +# Everything here except the redirect is either a chart default (websecure TLS) +# or a safety net (isDefaultClass, for manifests that forget the class). # -# Installing Traefik from the upstream chart instead? The same keys go straight -# into values.yaml; only the HelmChartConfig wrapper is RKE2-specific. -# -# **Mind the `http:` level.** Helm merges keys it does not recognise without -# complaining, so a values path that is one level off is accepted, produces no -# argument, and looks exactly like a working config. Both entrypoint settings -# below live under `http:` — verify against the rendered args after applying, -# never against this file: +# Helm accepts a values path that is one level off without complaining: it +# produces no argument and looks exactly like a working config. Both settings +# below live under `http:`. Verify against the rendered args, never this file: # # kubectl -n kube-system get ds rke2-traefik \ -# -o jsonpath='{.spec.template.spec.containers[0].args}' | tr ',' '\n' -# -# You want to see --entryPoints.web.http.redirections.entryPoint.to=websecure -# and --entryPoints.websecure.http.tls=true. (The TLS one is also the chart's -# default, so its presence proves nothing about whether this file applied — the -# redirect is the one to look for.) -# -# ── What each block is load-bearing for ────────────────────────────────────── -# -# websecure.tls.enabled Routers built from an Ingress with no tls: block get -# TLS from the entrypoint, and their certificate from the -# `default` TLSStore. This is what replaces -# --default-ssl-certificate. **Without it every managed -# and platform hostname serves plain HTTP on :443 only — -# i.e. no HTTPS at all — and the full_stack pipeline dies -# at step_vta_register_dids.** -# -# web.redirections Replaces nginx.ingress.kubernetes.io/ssl-redirect on -# every Ingress, which is why the ones this API creates -# now carry no annotations. cert-manager's HTTP-01 -# challenge is redirected too; Let's Encrypt follows the -# redirect and does not validate the certificate it lands -# on, so custom-domain issuance still works. -# -# kubernetesCRD Middleware is a CRD. allowCrossNamespace stays false — -# vtafarm-api creates one Middleware per user namespace -# precisely so it never needs the cluster-wide grant. -# -# publishedService Writes the published Service's external address into -# each Ingress's status. Note this leaves ADDRESS **empty** -# in the RKE2 layout, where Traefik takes traffic on -# hostPort 80/443 and its Service is ClusterIP — there is -# no external address to publish. Cosmetic either way, but -# it means an empty ADDRESS is NOT evidence that something -# is broken; check the CLASS column and curl instead. +# -o jsonpath='{.spec.template.spec.containers[0].args}' | tr ',' '\n' \ +# | grep redirections apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: @@ -60,7 +26,6 @@ metadata: spec: valuesContent: |- ingressClass: - enabled: true isDefaultClass: true ports: web: @@ -74,11 +39,3 @@ spec: http: tls: enabled: true - providers: - kubernetesCRD: - enabled: true - allowCrossNamespace: false - kubernetesIngress: - enabled: true - publishedService: - enabled: true From 3a5f7e447d0e93cd280cdaa8ba4ca9a5304f46d3 Mon Sep 17 00:00:00 2001 From: vthwang Date: Mon, 17 Aug 2026 03:44:02 -0700 Subject: [PATCH 2/2] docs: make the Rancher chartValues block paste-ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The block now carries a sibling entry so it is obvious the map is added to rather than replaced, and says plainly that the chart ships no values schema — a misspelled or misplaced key is accepted, emits no argument, and reads as a working config. Also completes the hand-applied ClusterRole further down, which was missing traefik.io/middlewares and cert-manager.io/certificates. It is the list a manually built cluster copies, so without them Middlewares and custom-domain certificates fail there while the Helm-deployed chart works. Signed-off-by: vthwang --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cf0c2ee..c1c653f 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,7 @@ Rancher UI → Cluster Management → the cluster → Edit YAML → `rkeConfig.c ```yaml rkeConfig: chartValues: + rke2-calico: {} # other charts' entries — leave them alone rke2-traefik: ingressClass: isDefaultClass: true @@ -209,9 +210,14 @@ rkeConfig: enabled: true ``` -Drop any `rke2-ingress-nginx` entry while you are in there; it is dead once the -controller is gone. On a cluster Rancher does not manage, the same values are -in `k8s/tls/rke2-traefik-config.yaml` — `kubectl apply` that instead. +Add these keys, do not replace the map — the siblings are other charts' values. + +The chart ships no values schema, so a key that is misspelled or one level off +is accepted, produces no argument, and looks exactly like a working config. +Verify against the rendered args, never against what you typed. + +On a cluster Rancher does not manage, the same values are in +`k8s/tls/rke2-traefik-config.yaml` — `kubectl apply` that instead. **The default certificate** is a plain CRD object, not chart config, so Rancher never touches it: @@ -404,4 +410,10 @@ rules: - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "create", "update", "delete", "watch"] +- apiGroups: ["cert-manager.io"] + resources: ["certificates"] + verbs: ["get", "list", "watch", "create", "delete"] +- apiGroups: ["traefik.io"] + resources: ["middlewares"] + verbs: ["get", "list", "create", "delete"] ```