# Reach something without putting it on the internet **For when a thing is half-built, or private, or only ever needed by one person**, and the ceremony of a public name is the wrong size for it. **What you get:** a name that resolves and a certificate that verifies, for anyone already on the tailnet — **and nothing at all for anyone else.** No DNS record, no `Certificate` resource, no router forward. Tear it down and it is gone from the tailnet within seconds. The tailnet is **`akita-velociraptor.ts.net`**. --- ## The one that will burn you **`traefik` is the default IngressClass on this cluster.** > **An `Ingress` that omits `ingressClassName` goes to Traefik — which, for > something you meant to keep private, means publishing it to the internet.** **There is no warning.** Set it explicitly, every time, and confirm with `kubectl get ingress -A` that the class column says `tailscale`. ## Two ways, and they are not interchangeable **HTTPS with a real certificate** — an `Ingress` with `ingressClassName: tailscale`. The single entry under `tls.hosts` becomes the tailnet hostname: `myapp` gives you `https://myapp.akita-velociraptor.ts.net`. **Use `defaultBackend` for the whole service, or `rules:` if you need paths.** **Raw TCP** — a `Service` annotated `tailscale.com/expose: "true"`. The service gets its own tailnet IP. **No TLS is added; this is a plain L4 proxy.** For anything that is not HTTP, or when you want the `Service` itself on the tailnet. ## What you do not have to do **Obtain a certificate.** One exists and it is genuine, but it is issued outside this cluster and nothing here holds it. **Publish a DNS record.** MagicDNS answers for the name. **Open anything on the router.** Nothing here touches Traefik, the Gateway, DNS or the firewall. ## Two things that look like faults and are not **The first HTTPS request to a new device can take over twenty seconds** and appears to hang — certificates are provisioned lazily, on first connection. *Every request after is fast. Observed 2026-09-04: first `curl` timed out at 20s; the retry returned 200 in 0.17s.* **Retry with `--max-time 60` before assuming anything is broken.** **`ProxyGroup "" does not exist` in the operator log is noise.** It is the optional HA path, which this cluster does not use. ## What it costs **Every exposed service is a real device on the tailnet**, with its own proxy pod. **Fine at this scale**, but ephemeral deployments that come and go churn the device list, and devices count against tailnet limits. *Prune occasionally in the admin console.* ## Also available this way **`kubectl` from any tailnet machine**, with no LAN access and no VPN routing — the API server is on the tailnet too. `tailscale configure kubeconfig tailscale-operator`. **Authorisation is your Tailscale identity, mapped onto Kubernetes RBAC.** --- ## Checking this is still true **Verified 2026-09-04**, when the operator was installed. ```sh kubectl get ingressclass # tailscale present, traefik still default kubectl get pods -n tailscale # one proxy pod per exposed service tailscale status | grep curl -sS -o /dev/null -w "%{http_code}\n" https://.akita-velociraptor.ts.net/ ``` **There is a fuller reference — reinstall steps, the OAuth prerequisites, the manifests — and it is private**, because it sits beside an inventory of what is running here. *Ask for `jeffry/homelab-impl` by name if you need it.* **This page is what you need in order to decide. It does not tell you how to run the cluster**, and it will not send you somewhere you cannot go.