Skip to content

Server: one tailnet node per host — <server>.<tailnet>.ts.net/<service> instead of a sidecar per service #86

Description

@ulises-c

Problem

Every web service gets its own Tailscale sidecar, which means its own tailnet node and its own <service>.<tailnet>.ts.net name:

  • linux-server/: 18 sidecars (adguard, atvloadly, cockpit, filebrowser, forgejo, glances, homepage, nginx-proxy-manager, ntfy, openspeedtest, portainer, qbittorrent, speedtest-tracker, syncthing, tailscale-web, ups, uptime-kuma, watchtower)
  • linux-pi/: 4 more (adguard, cups, homepage, motioneye)

Each new service adds a node, which floods the tailnet's machine list. The flat namespace also doesn't scale to more servers: the name doesn't say which host a service runs on, and two servers can't both run a service with the same name.

Goal

One tailnet node per host, with services addressed under it:

https://<server>.<tailnet>.ts.net/<service>

Adding a server should add exactly one node. Adding a service should add none.

Things to settle before implementing

  • Subpath support per app. Path routing (tailscale serve --set-path /<service>) only works cleanly when the app can run under a base path or uses only relative URLs. Each service needs checking. Some have a base-path setting (forgejo ROOT_URL, filebrowser baseURL, cockpit UrlRoot). Others are known to be awkward behind a path prefix. Services that can't take a path need a fallback:
    • a per-service HTTPS port on the host node (https://<server>.<tailnet>.ts.net:<port>), or
    • keep that one service as its own node.
  • Tailscale Services. Evaluate Tailscale's newer "Services" feature (svc:<name>, its own MagicDNS name, hosted by one or more nodes) as an alternative or complement. It could keep short names for a few key services without a node per service, and it fits multiple servers hosting the same service.
  • Host serve vs one proxy container. Either run tailscale serve on the host's own tailscaled (see linux-server/tailscale-web.service), or run one reverse-proxy sidecar per host. With host serve, backends are reached on 127.0.0.1:<published-port>. Services that currently share the sidecar's netns (network_mode: service:<svc>-ts) would need ports published to localhost instead.
  • Non-HTTP endpoints. forgejo exposes git SSH on :22 through its sidecar, and that clashes with the host's sshd if moved onto the host node. It needs another port, or forgejo stays its own node.
  • URL consumers to migrate. homepage links and widgets, uptime-kuma monitors, ntfy base URL (subscribed phone clients and publishers), forgejo remotes on every machine and CI runners, .env files referencing *.ts.net hosts, HTTPS.md/post-install.md.
  • Cleanup. Remove the old nodes from the admin console, delete ts-state/ dirs and the per-service TS_AUTHKEY entries, and update the ACL to the new per-host tags.

Related

Acceptance

  • Each server/Pi is one tailnet node, and every web service is reachable at https://<server>.<tailnet>.ts.net/<service> (or a documented fallback)
  • Per-service sidecars and their ts-state/ removed; old nodes gone from the tailnet
  • homepage, uptime-kuma, ntfy, forgejo remotes, and docs updated to the new URLs
  • Adding a new service needs no new tailnet node; adding a new host needs exactly one

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions