Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 1, 2026

Tailscale operator rejects ingresses with explicit spec.rules[].host, emitting InvalidIngressBackend and NoValidBackends events. Operator requires "hostless" ingresses, determining hostname from spec.tls[0].hosts[0].

Changes

  • All Tailscale ingresses: Removed spec.rules[].host field (7 ingresses total)
  • Crafty service: Changed hostname annotation from crafty-controller to crafty-controller-ports to avoid collision with ingress

Example

Before:

spec:
  ingressClassName: tailscale
  rules:
    - host: crafty-controller.rohu-shark.ts.net  # Operator rejects this
      http:
        paths:
          - path: /

After:

spec:
  ingressClassName: tailscale
  rules:
    - http:  # Operator derives hostname from tls.hosts
        paths:
          - path: /
  tls:
    - hosts:
        - crafty-controller  # Shortname used for tailnet DNS

Affected Resources

  • Crafty (ingress + service split)
  • Paperless
  • Homepage
  • Omada Controller
  • Alloy
  • Netbox (Ansible template)
  • Frigate (Ansible template)
Original prompt

This section details on the original issue you should resolve

<issue_title>Fix Tailscale Ingress backends + split Crafty UI vs game ports exposure</issue_title>
<issue_description>Goal

  • Make all Tailscale-managed Ingress resources valid for the Tailscale k8s operator (stop InvalidIngressBackend / NoValidBackends).

  • For Crafty specifically:

    • Crafty UI must be exposed via Ingress.
    • Crafty game ports/services must be exposed via Service port exposure (not via Ingress).

Context / Current Symptoms

  • Tailscale operator events on ingresses:

    • InvalidIngressBackend ... rule with host "...ts.net" ignored, unsupported
    • NoValidBackends ... no valid backends
  • Current Crafty Ingress uses spec.rules[].host: crafty-controller.rohu-shark.ts.net, which Tailscale operator treats as unsupported.

  • Crafty Service is already annotated for service exposure and has valid EndpointSlices.


Scope

Only touch:

  • argocd/apps/** manifests that define Tailscale ingresses and the Crafty service/ingress.
  • (If present) any shared “template” or generator used for these ingresses.

Do not change:

  • Cluster-wide Tailscale operator installation/helm chart unless explicitly required.
  • Storage, PVCs, or app deployments.

Requirements

1) Tailscale Ingress resources must be “hostless”

For any Ingress with spec.ingressClassName: tailscale:

  • Remove spec.rules[].host entirely.
  • Keep spec.rules[].http.paths[] intact.
  • Ensure spec.tls[0].hosts[0] is set to the desired shortname (e.g., crafty-controller, paperless, homepage, etc.). This is what Tailscale uses to create the tailnet hostname/service.

Acceptance criteria

  • kubectl describe ingress <name> no longer shows:

    • InvalidIngressBackend “host ignored, unsupported”
    • NoValidBackends
  • Tailscale operator logs show it successfully exposes the ingress.


2) Crafty: split UI ingress from game/service port exposure

2a) Crafty UI via Ingress

  • Crafty UI Ingress must:

    • ingressClassName: tailscale
    • Have no spec.rules[].host
    • Route / to the Crafty UI backend service on port 443 (targetPort 8443 already).
    • tls.hosts should contain exactly: crafty-controller (shortname)

Do not include tailscale.com/expose: "true" on the Ingress unless it is already required in your repo patterns; prefer only the tags/hostname config needed for ingress.

2b) Crafty game ports via Service (port exposure)

  • Keep Crafty Service exposing non-HTTP ports directly (Minecraft Java ports, Bedrock UDP, dynmap, voice chat, etc.).

  • Crafty Service should retain:

    • tailscale.com/expose: "true"
    • tailscale.com/hostname: crafty-controller (BUT: hostname collisions must be avoided; see below)

Important collision rule
You cannot have the Ingress and Service both trying to claim the same Tailscale hostname (crafty-controller) unless you intentionally want only one and the other fails/flaps.

So:

  • The Ingress should own the hostname crafty-controller for the UI.

  • The Service should use a distinct hostname for raw ports, e.g.:

    • crafty-controller-svc
    • crafty-controller-ports
    • crafty-mc
      Pick one and apply consistently.

Acceptance criteria

  • UI reachable at https://crafty-controller.<tailnet-domain> (or whatever tailnet DNS pattern you use).
  • Raw game ports reachable at <service-hostname>.<tailnet-domain>:25565 etc.
  • Operator no longer “unexposes” Crafty resources repeatedly.

Implementation Tasks (Copilot steps)

Task A — Fix all Tailscale ingresses

  1. Search repo for ingresses using Tailscale class:

    • ingressClassName: tailscale
  2. For each, remove spec.rules[].host keys.

  3. Ensure spec.rules[].http.paths[].backend.service.name and .port remain correct.

  4. Ensure spec.tls[0].hosts[0] exists and is a shortname (no .ts.net).

Task B — Crafty-specific split

  1. Update Crafty Ingress:

    • remove spec.rules[0].host
    • ensure backend points to service: crafty-controller port 443
    • ensure tls.hosts: [crafty-controller]
  2. Update Crafty Service annotations:

    • keep tailscale.com/expose: "true"
    • change tailscale.com/hostname to a non-conflicting name, e.g. crafty-controller-ports
    • keep tags as-is unless tags are failing in operator logs (see non-goal note below)

Task C — Validation commands documented in PR description

Add to the PR description (not as code comments in manifests):

  • kubectl -n apps-crafty-controller describe ingress crafty-controller
  • kubectl -n apps-crafty-controller get ingress crafty-controller -o yaml
  • kubectl -n apps-crafty-controller get svc crafty-controller -o yaml
  • kubectl -n tailscale logs deploy/operator -c operator --tail=200
  • Confirm no InvalidIngressBackend/NoValidBackends events.
  • Confirm both hostnames appear in tailnet DNS and are reachable.

Out of Scope (expl...


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

- Remove spec.rules[].host from all Tailscale ingresses (operator requirement)
- Keep TLS shortnames intact for hostname assignment
- Change Crafty Service hostname to crafty-controller-ports to avoid collision
- Fixed ingresses: crafty, paperless, homepage, omada, alloy, netbox, frigate

Co-authored-by: SRF-Audio <16975040+SRF-Audio@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Tailscale Ingress backends and Crafty UI exposure Fix Tailscale ingress backends by removing spec.rules[].host Jan 1, 2026
Copilot AI requested a review from SRF-Audio January 1, 2026 20:19
@SRF-Audio SRF-Audio marked this pull request as ready for review January 1, 2026 20:26
@SRF-Audio SRF-Audio merged commit 51cdd02 into main Jan 1, 2026
3 of 5 checks passed
@SRF-Audio SRF-Audio deleted the copilot/fix-tailscale-ingress-backends branch January 1, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix Tailscale Ingress backends + split Crafty UI vs game ports exposure

2 participants