Tailscale — Structure#

Note on analysis scope: The local checkout is a sparse clone — approximately 1,438 of the full ~2,083 .go files are present on disk. Missing directories (wgengine/, tsnet/, types/, util/, tsd/, tsweb/, tstest/, tstime/, tool/, version/, wf/, wif/, tsconsensus/, tsconst/, words/) were inspected via git show and git ls-tree. The structure analysis covers the full repository.

Layout pattern#

Custom flat-domain layout (monorepo product suite)

Tailscale does not follow the standard Go layout (cmd/ + internal/ + pkg/). Instead, every domain area lives as a top-level or shallow directory — net/, ipn/, control/, derp/, tka/, tailcfg/, etc. — all exported at tailscale.com/<name>. The internal/ directory exists but is tiny (2 sub-packages). This is a deliberate choice: the vanity module path tailscale.com means the entire module is treated as a stable public library API. Third-party projects and Tailscale’s own mobile apps all import packages directly from this module.

The repo also functions as a monorepo for the complete Tailscale product: VPN daemon, CLI, DERP relay server, Kubernetes operator, SSH server, OIDC provider, embedded library (tsnet), and dozens of ancillary tools — all in one go.mod.

Directory map#

tailscale/
├── cmd/                    # 50+ binary entry points (tailscale, tailscaled, derper, k8s-operator, …)
├── ipn/                    # IPN daemon: state machine, local backend, server, API
│   ├── ipnlocal/           # LocalBackend — the central daemon orchestrator
│   ├── ipnserver/          # Unix socket server, IPN protocol
│   ├── localapi/           # LocalAPI HTTP server (used by tailscale CLI)
│   ├── store/              # State persistence backends (file, AWS, kube, mem)
│   ├── ipnauth/            # Authentication helpers
│   ├── ipnext/             # Extension points for daemon subsystems
│   └── conffile/           # Declarative config file support
├── wgengine/               # WireGuard engine interface + userspace implementation [git only]
│   ├── magicsock/          # MagicSock: multi-path UDP with DERP fallback
│   ├── filter/             # Packet filter (firewall)
│   ├── netstack/           # Userspace network stack integration
│   ├── router/             # OS kernel route management
│   ├── wgcfg/              # WireGuard configuration types
│   └── wgint/              # WireGuard internal helpers
├── control/                # Control plane client
│   ├── controlclient/      # Long-poll client to Tailscale coordination server
│   ├── controlhttp/        # HTTP transport for control protocol
│   ├── controlbase/        # Noise-based session layer (ts2021 protocol)
│   └── ts2021/             # ts2021 protocol implementation
├── derp/                   # DERP relay protocol (Designated Encrypted Relay for Packets)
│   ├── derpserver/         # DERP server implementation
│   ├── derphttp/           # DERP over HTTP(S) client/server
│   ├── derpconst/          # Protocol constants
│   └── xdp/               # XDP/eBPF acceleration for DERP
├── net/                    # Networking library (~40 sub-packages)
│   ├── dns/                # DNS manager + resolver
│   ├── netcheck/           # NAT type detection / reachability
│   ├── portmapper/         # UPnP, NAT-PMP, PCP port mapping
│   ├── tstun/              # TUN device wrapper
│   ├── tsdial/             # Tailscale dialer
│   ├── netmon/             # Network interface monitor
│   ├── art/                # Allotment Routing Table (IP route lookup)
│   ├── packet/             # Packet parsing
│   └── stun/               # STUN protocol
├── tailcfg/                # Wire format types: NodeView, NetworkMap, DERPMap, …
├── tsd/                    # System container: dependency wiring for all subsystems [git only]
├── tsnet/                  # Embedded Tailscale library for user applications [git only]
├── tka/                    # Tailscale Key Authority (distributed trust log)
├── types/                  # Core shared types: key, logger, netmap, prefs, … [git only]
├── util/                   # ~50 utility packages: deephash, eventbus, lru, dnsname, … [git only]
├── feature/                # Compile-time feature flag system
│   ├── buildfeatures/      # Generated _enabled/_disabled file pairs (~100 features)
│   └── condregister/       # Conditional feature registration via blank imports
├── k8s-operator/           # Kubernetes operator implementation
│   ├── apis/               # CRD API types
│   ├── reconciler/         # Kubernetes reconcilers
│   └── sessionrecording/   # SSH session recording integration
├── kube/                   # Kubernetes client and support packages
├── ssh/tailssh/            # Tailscale SSH server
├── client/                 # API clients
│   ├── tailscale/          # Go client library for the Tailscale HTTP API
│   ├── local/              # Local daemon IPC client
│   └── web/                # Web client (browser UI)
├── appc/                   # App Connectors subsystem
├── drive/driveimpl/        # Tailscale Drive (file sharing) implementation
├── sessionrecording/       # SSH session recording
├── logtail/                # Structured log streaming to log.tailscale.io
├── logpolicy/              # Logging policy and log ID management
├── log/                    # Log sink implementations
├── health/                 # Health tracker subsystem
├── envknob/                # Environment-variable feature knobs
├── hostinfo/               # Host metadata collection
├── disco/                  # Disco protocol (peer discovery handshake)
├── doctor/                 # Network diagnostics framework
├── posture/                # Device posture checking
├── prober/                 # Service probing (used internally)
├── safeweb/                # Hardened HTTP server wrapper
├── safesocket/             # Cross-platform Unix socket with auth
├── syncs/                  # Sync primitives (typed atomics, mutexes)
├── chirp/                  # Chirp UDP protocol (lightweight IPC)
├── tempfork/               # Patched vendored copies of upstream libraries
├── omit/                   # Omit-tag stubs (pair with feature/ for dead-code elim)
├── tsweb/                  # Internal web utilities [git only]
├── tstest/                 # Test helpers [git only]
├── version/                # Version embedding and parsing [git only]
├── release/                # Packaging: deb, rpm, dist
├── docs/                   # Documentation and example configs
└── scripts/                # Maintenance scripts

Entry points#

The cmd/ directory contains 50+ binaries. The most significant:

BinaryPurpose
cmd/tailscaledPrimary daemon — the Tailscale node agent (Linux, Windows, macOS, BSDs)
cmd/tailscaleCLI client — controls and queries tailscaled via LocalAPI
cmd/derperDERP relay server binary
cmd/k8s-operatorKubernetes operator for Tailscale
cmd/k8s-proxyKubernetes proxy (egress/ingress)
cmd/k8s-nameserverKubernetes MagicDNS nameserver
cmd/tsidpTailscale OIDC identity provider
cmd/tsshdTailscale SSH server daemon
cmd/containerbootContainer bootstrap for Tailscale in Docker/K8s
cmd/natcNAT connector binary
cmd/stundSTUN server daemon
cmd/derpprobeDERP health probe
cmd/vnetVirtual network for testing
cmd/tsconnectBrowser/WASM-based Tailscale connection
cmd/sniproxySNI proxy for subnet routing
cmd/nginx-authnginx auth helper for Tailscale
cmd/pgproxyPostgreSQL proxy
cmd/derper, cmd/xdpderperDERP + XDP-accelerated DERP
cmd/featuretagsPrints build tags for feature selection
cmd/mkversion, cmd/mkpkgBuild/packaging tooling

Most cmd/ subdirectories do not have a main.go at the root; instead they have domain-named *.go files that are package main (e.g., cmd/tailscaled/tailscaled.go).

Package organization#

  • Internal packages: internal/client/tailscale (private API client), internal/tooldeps (tool dependency tracking). Minimal use of internal/ — Tailscale chose public packages everywhere to enable broad embedding.

  • Public packages (pkg-equivalent, all at module root):

    • tailcfg — wire protocol types; the lingua franca between daemon and control plane
    • types/* — key, logger, netmap, prefs, views, ipproto, dnstype, …
    • net/* — 40+ networking sub-packages used as a standard library extension
    • wgengine — Engine interface + userspace WireGuard
    • ipn — IPN state machine types
    • derp — DERP protocol library
    • control/controlclient — control plane client library
    • tka — Key Authority library
    • tsnet — embedded Tailscale library (the “tsnet” package for app embedding)
    • util/* — ~50 generic utilities
    • client/tailscale — public Go API client for Tailscale’s HTTP API
  • Layering: No strict clean-architecture layering. Dependencies flow as follows:

    cmd/tailscaled
        └── tsd (system wiring)
            ├── wgengine (WireGuard engine)
            │   └── magicsock (UDP + DERP relay)
            ├── ipn/ipnlocal (local backend orchestrator)
            │   ├── control/controlclient
            │   ├── tailcfg (wire types)
            │   └── net/* (networking)
            └── ipn/ipnserver (socket server)
                └── ipn/localapi (REST API)

    tailcfg and types/* are leaf packages with minimal external dependencies. net/* depends on tailcfg and types. wgengine wraps net/*. ipn/* wraps all of the above. tsd wires them together. cmd/* are at the top.

Build system#

  • Build tool: GNU Make (Makefile) orchestrating a pinned Go toolchain via ./tool/go (a wrapper script that downloads and caches the exact toolchain version specified in go.toolchain.rev)

  • Key targets:

    • make vetgo vet ./...
    • make staticcheck — staticcheck analysis
    • make depaware — dependency awareness check (validates no unexpected imports)
    • make buildwindows/build386/buildlinuxarm/buildwasm — cross-compilation tests
    • make check — comprehensive pre-merge check
    • make generate — code generation (go generate ./...)
    • make kube-generate-all — regenerate Kubernetes CRD code
    • make sshintegrationtest — Docker-based SSH integration tests
    • make updatedeps — update depaware lockfiles
  • Docker: Yes, multi-stage. Dockerfile builds tailscaled, tailscale, and other binaries then packages them in Alpine. Actual published images use build_docker.sh + the external mkctr tool for multi-architecture builds. The Makefile publishdevimage target drives build_docker.sh.

  • Toolchain pinning: The repository pins its Go toolchain via go.toolchain.rev, go.toolchain.version, and an SRI hash. The ./tool/go script enforces this — no system Go is used for builds. This is unusually strict but ensures reproducible builds across contributors and CI.

  • Release packaging: release/ contains Debian (.deb) and RPM (.rpm) packaging logic. cmd/dist is a distribution build tool. cmd/mkpkg builds platform packages.

Notable structural decisions#

  1. Flat public namespace with vanity module path. Using tailscale.com as the module path and exporting almost everything (no broad internal/) is an architectural commitment: Tailscale is as much a library as an application. The tsnet package is a first-class embedded-Tailscale API specifically for this purpose.

  2. Feature flag architecture as physical structure. The feature/buildfeatures/ directory contains ~100+ feature pairs (feature_X_enabled.go / feature_X_disabled.go). Combined with build tags and the omit/ stub package, this lets the same codebase produce a minimal mobile build or a full-featured server build with dead-code elimination — without #ifdef-style guards scattered through the code.

  3. tsd as explicit dependency injection container. Rather than passing individual subsystems around (or using a DI framework), the tsd.System struct holds all daemon subsystems as SubSystem[T] values. This was an intentional 2023 redesign to unify initialization across tailscaled, Windows service, macOS GUI, tsnet, and WASM — documented in the package comment.

  4. tempfork/ as a managed vendor-patch area. Dependencies that needed patching (e.g., gliderlabs/ssh, acme) live in tempfork/ rather than in vendor/. This is more honest than silently patching vendor files and makes upstream-porting efforts visible.

  5. wgengine/magicsock as the connectivity core. MagicSock is arguably the most complex and critical package: it manages multiple UDP endpoints per peer, falls back to DERP relay when direct paths fail, implements STUN-based NAT traversal, and supports XDP acceleration. Its placement under wgengine/ reflects that it is conceptually part of the WireGuard layer, not the OS networking layer.

  6. Kubernetes integration at product scale. k8s-operator/, kube/, and the cmd/k8s-* binaries form a substantial product sub-system. The operator uses the standard controller-runtime reconciler pattern and has its own CRD types in k8s-operator/apis/. The presence of a sessionrecording/ sub-package within the operator reflects the complexity of the Kubernetes SSH session recording feature.