Configure Ingress
Helm creates the dashboard Ingress. The operator creates one Ingress for each controller that resolves an external host. The mite gateway remains cluster-internal.
Choose a Controller Route
Section titled “Choose a Controller Route”| Mode | Route | Use when |
|---|---|---|
subdomain | https://<controller>.<root-domain>/ | Wildcard DNS and certificates are available. |
path | https://<dashboard-host>/jenkins/<namespace>/<controller>/ | One hostname and shared ingress are preferred. |
subdomain is the default. spec.ingressSpec.mode is immutable after controller creation. The dashboard Spec Editor shows the mode as read-only. A missing ingressSpec block or a missing mode counts as subdomain. A patch cannot remove the block or add it with another mode. The API server refuses it with ingressSpec.mode is immutable.
Path mode uses the dashboard host and its TLS configuration. Do not set tlsSecretName on a path-mode controller. Varroa configures the Jenkins URL prefix automatically.
Expose the Dashboard
Section titled “Expose the Dashboard”global: domain: example.comfrontend: host: app.example.comingress: enabled: true className: nginx annotations: cert-manager.io/cluster-issuer: letsencrypt-prod tls: - hosts: [app.example.com] secretName: varroa-dashboard-tlsauth: dashboardUrl: https://app.example.com cookieDomain: .example.comUse HTTPS. Set auth.cookieDomain to the shared parent domain when dashboard authentication must work on controller subdomains.
Set Controller Defaults
Section titled “Set Controller Defaults”The cluster-scoped object must be named varroa-defaults:
apiVersion: varroa.dev/v1alpha1kind: ProvisioningDefaultsmetadata: name: varroa-defaultsspec: rootDomain: example.com ingressClassName: nginx ingressAnnotations: cert-manager.io/cluster-issuer: letsencrypt-prodkubectl apply -f defaults.yamlA subdomain controller without an explicit host then uses <name>.example.com.
Override One Controller
Section titled “Override One Controller”apiVersion: varroa.dev/v1alpha1kind: Controllermetadata: name: build namespace: jenkins-platformspec: ingressSpec: host: build.example.com ingressClassName: nginx tlsSecretName: build-tls annotations: nginx.ingress.kubernetes.io/proxy-body-size: 512mController annotations merge over ProvisioningDefaults.spec.ingressAnnotations. Controller values win on conflicts. You can also edit host, class, TLS secret, and annotations in the Spec Editor Form tab.
For path routing:
spec: ingressSpec: mode: path host: app.example.comIf no host can be resolved, Varroa creates no controller Ingress and sets the informational NoExternalURL condition. The in-cluster Service and port forwarding remain available.
A headless controller receives no Ingress at all, whatever host would resolve. Use spec.headless: true for a one-tenant controller. A cell is always headless.
Verify
Section titled “Verify”kubectl get ingress -Akubectl get controller build -n jenkins-platform \ -o jsonpath='{.status.endpoint}{"\n"}'The operator writes the external URL to status.endpoint. The value is empty for a headless controller and when no host resolves. For a controller on a member cluster, the dashboard shows the URL that the member’s operator wrote. The core’s rootDomain does not apply to it.
Ingress host, class, annotations, and TLS changes converge without restarting Jenkins.
| Symptom | Check |
|---|---|
| 404 response | Host rule, ingress class, and ingress-controller events. |
| Login loop | HTTPS, OIDC callback URL, and cookie domain. |
| No controller Ingress | rootDomain, controller host, and NoExternalURL. |
| Path route redirects incorrectly | Dashboard host and immutable path mode. |
See Network policies and Authentication.