# Tower IngressRoute — path-based split between API and UI on the # same hostname. # # Routing rules (Traefik picks longest-match-with-priority): # - /api/*, /healthz, /connect/*, /teardown/* → backend # - everything else → frontend (Vue SPA) # # /connect and /teardown are customer-facing (token-bearer auth, no # operator JWT) — that's why they're NOT under /api. They still # need to land on the backend, not the SPA, so the customer's # `curl … | sudo bash` actually receives a shell script. # # Priority is set explicitly so Traefik doesn't fall back to its # heuristic; the API rule outranks the catchall, which outranks no # rule at all. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: tower labels: {{- include "tower.labels" . | nindent 4 }} spec: entryPoints: - {{ .Values.ingress.entryPoint }} routes: {{- if .Values.backend.enabled }} - match: Host(`{{ .Values.ingress.domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/healthz`) || PathPrefix(`/connect`) || PathPrefix(`/teardown`)) kind: Rule priority: 200 services: - name: tower-backend port: 8080 {{- end }} {{- if .Values.frontend.enabled }} - match: Host(`{{ .Values.ingress.domain }}`) kind: Rule priority: 100 services: - name: tower-frontend port: 80 {{- end }} tls: secretName: tower-tls