Tailscale — Knowledge
Verified tailnet facts and operational constraints for this host. For the step-by-step host procedure, see the Tailscale host runbook.
What it is
- Tailscale is an encrypted overlay network built on WireGuard. Tailnet access policies govern which devices/users can connect to which resources; the application behind an allowed endpoint may also require its own authentication and authorization. Tailnet membership is not unrestricted access.
- In this environment, Tailscale Serve provides tailnet HTTPS access for policy-authorized users. Remote agent-container participation is conditional on a separately verified container-to-tailnet gateway; joining the host by itself does not give its internal Docker network a path to fleet services.
- The primary fleet host is
jkdev001(IP100.70.216.68).
Tailnet facts (verified 2026-09-30, v1.102.4)
| Fact | Value |
|---|---|
| Primary host | jkdev001 — 100.70.216.68 (v4), fd7a:115c:a1e0::6e39:d845 (v6) |
| MagicDNS suffix | *.tail6817df.ts.net (e.g. jkdev001.tail6817df.ts.net) |
| Install version on jkdev001 | 1.102.4 |
| Public exposure | Funnel is not configured in the recorded Serve map. This does not establish that every backend is tailnet-only: the docsite Docker port is currently bound on all host interfaces. Review host firewall and binding before asserting public inaccessibility. |
Peer roster changes over time; tailscale status on any joined host is the
source of truth for who is online now.
tailscale serve — the only sanctioned exposure pattern
The tailscale serve command terminates HTTPS on a tailnet port and proxies
to a loopback-bound backend. From the client's view each service is:
https://jkdev001.tail6817df.ts.net:<tailnet-port>
Verified port map on jkdev001 (2026-09-30):
| Tailnet port | Loopback backend | Service | Auth |
|---|---|---|---|
8443 | 127.0.0.1:8097 (docker) | Research Hub | 401 without credentials |
8444 | 127.0.0.1:9750 (compatibility proxy) | Codebase Memory Graph UI | none |
8445 | 127.0.0.1:3000 (docker) | Docusaurus docsite (/portals service directory) | none |
8446 | 127.0.0.1:9119 (hermes) | Hermes dashboard | login |
8447 | 127.0.0.1:8787 (webui) | Hermes community WebUI | login |
Operational notes:
- The serve config lives in the Tailscale daemon state, not in any repo.
Read it with
tailscale serve status. - HTTP 421 from a backend over plain loopback means the backend expects the
tailnet SNI/Host header — probe with the real host header, not a bare
curl localhost. - Backends should be loopback-bound when served only through Tailscale. This
docsite currently publishes Docker port
3000on all host interfaces, so the Serve route is not proof that direct access is unavailable. Verify the firewall or separately authorize a loopback-only Docker binding.
How an agent joins (knowledge, not procedure)
- Auth key, not account sharing. New hosts join with a tailnet-scoped
auth key (
tailscale up --authkey=<key>). The owner generates/rotates keys in the admin console; an agent never receives or stores another host's node credentials. - MagicDNS is on. Hostnames like
jkdev001.tail6817df.ts.netresolve for any joined host; IPs work too. Prefer hostnames. - Fleet topology rule. Remote agent hosts run containers only — no ledger, broker, or controller; those stay on jkdev001. A remote container may reach fleet services only after its approved gateway/proxy path and tailnet policy have been tested from inside that container.
- Egress needs an explicit design. An internal Docker bridge blocks external routing; merely creating it does not make the host's tailnet reachable from containers. Before onboarding a remote agent, specify and test a constrained gateway/proxy for approved tailnet destinations and a separate model-provider egress path. Do not claim either path exists until a container-level probe proves it.
- Degraded mode is shared. Losing tailnet connectivity puts a remote agent in the same degraded mode as a local one (continue work, queue submissions, replay on reconnect). The watchdog treats silent heartbeats as escalations regardless of host.
- Never use Funnel for fleet traffic. Funnel is public by definition; the fleet's posture is tailnet-only. Human access convenience (Funnel) is an owner decision per service, never an agent action.
Common commands (cheatsheet)
| Task | Command |
|---|---|
| Am I joined? | tailscale status |
| My own address(es) | tailscale ip -4 / tailscale ip -6 |
| Who else is on the tailnet | tailscale status (peer list) |
| What HTTPS ports does this host expose | tailscale serve status |
| Reach jkdev001 docsite from any joined host | curl https://jkdev001.tail6817df.ts.net:8445/ |
| Health-check a peer from the tailnet | curl -s -o /dev/null -w '%{http_code}' https://<peer>.tail6817df.ts.net:<port>/ |
Pitfalls
- 421 Misdirected Request on a proxied backend: expected over bare loopback; retry with the tailnet Host header (see operational notes above).
- Serve config is not in git. Do not expect
docker-compose.ymlor repo files to describe tailnet ports — read the daemon (tailscale serve status). - Stale roster is normal. Peers drop to idle/offline frequently; "peer offline" is not an incident unless it is a fleet-critical host.
- One tailnet port = one backend. Port maps shift when services move;
re-verify against
tailscale serve statusbefore automating against a port. - Tailnet policy and application auth are separate. Tailscale access policies constrain network reachability; a permitted service may still require its own user or service authentication. Check both before treating a reachable port as authorized.
Published by Hermes · 2026-10-01.