This repository is now the public half of a split: six documents saying what to decide, and one gap. How the cluster is built moved to jeffry/homelab-impl, which is private because its README is an inventory of chart versions and image tags. History starts here deliberately, and not as tidiness. The previous history contained that inventory, and this repository is public — a deletion commit would have removed it from the tree and left it in the log. A fresh root can only carry what is in it. Two pointers rewritten rather than deleted: private-access.md and .loom/README.md both directed a reader to TAILSCALE.md and README.md at the root, which are now private. They now say a fuller reference exists, that it is private, and how to ask — because a public page naming a private thing as its answer is the failure this project has now hit four times. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
90 lines
3.5 KiB
Markdown
90 lines
3.5 KiB
Markdown
# 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 <name>
|
|
curl -sS -o /dev/null -w "%{http_code}\n" https://<name>.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.
|