# littledivy/tailnet-do architecture

> Architecture diagram of the GitHub repository littledivy/tailnet-do, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-10). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/littledivy/tailnet-do
- Repository: https://github.com/littledivy/tailnet-do

## Overview

tailnet-do runs Tailscale’s userspace client inside a Cloudflare Durable Object, exposing the node to Workers and other tailnet devices. A Worker can use the Durable Object RPC methods to reach private hosts; the node can also serve HTTP or TCP to tailnet peers, and can be configured as an exit node or subnet router. The JavaScript layer adapts Cloudflare sockets and Durable Object storage to the Go/Wasm engine. Some advertised capabilities are documented but their implementation details are not shown in the excerpts, so those links cite the README.

Main entry points: [`go/main.go`](https://github.com/littledivy/tailnet-do/blob/main/go/main.go) (Tailscale engine), [`src/index.js`](https://github.com/littledivy/tailnet-do/blob/main/src/index.js) (Tailnet API), [`go`](https://github.com/littledivy/tailnet-do/tree/main/go) (Exit node), [`src/wasm_exec.js`](https://github.com/littledivy/tailnet-do/blob/main/src/wasm_exec.js) (Go Wasm runtime)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_worker_api["Worker API"]
  node_do_wrapper["TailnetObject<br/>[index.js]"]
  node_tailnet_api["Tailnet API<br/>[index.js]"]
  node_wasm_runtime["Go Wasm runtime<br/>[wasm_exec.js]"]
end

subgraph group_tailnet_node["Tailnet node"]
  node_engine["Tailscale engine<br/>[main.go]"]
  node_node_lifecycle["Node lifecycle<br/>[main.go]"]
  node_identity_status["Identity and status<br/>[main.go]"]
end

subgraph group_traffic["Tailnet traffic"]
  node_peer_dial["Peer TCP dial<br/>[main.go]"]
  node_tailnet_fetch["Tailnet HTTP client<br/>[main.go]"]
  node_http_serve["Tailnet HTTP server<br/>[main.go]"]
  node_tcp_listen["Tailnet TCP listener<br/>[main.go]"]
  node_exit_node["Exit node"]
  node_subnet_router["Subnet router"]
end

subgraph group_platform_network["Platform and network"]
  node_do_storage[("DO state storage")]
  node_cloudflare_sockets["Cloudflare sockets"]
  node_doh["DNS over HTTPS<br/>[index.js]"]
end

node_worker(("Worker"))
node_tailnet_network(("Tailnet peers"))
node_control_derp["Control plane and DERP"]
node_private_hosts["Private hosts"]
node_internet["Internet destinations"]

node_worker -->|"calls RPC"| node_do_wrapper
node_do_wrapper -->|"starts node"| node_tailnet_api
node_tailnet_api -->|"loads runtime"| node_wasm_runtime
node_tailnet_api -->|"creates node"| node_engine
node_engine -->|"starts node"| node_node_lifecycle
node_tailnet_api -->|"reads and writes state"| node_do_storage
node_engine -->|"connects by WebSocket"| node_control_derp
node_engine -->|"reports status"| node_identity_status
node_do_wrapper -->|"exposes connect"| node_peer_dial
node_do_wrapper -->|"exposes fetch"| node_tailnet_fetch
node_worker -->|"requests via node"| node_private_hosts
node_tailnet_api -->|"opens sockets"| node_cloudflare_sockets
node_engine -->|"dials outbound"| node_cloudflare_sockets
node_engine -->|"queries DNS"| node_doh
node_peer_dial -->|"dials TCP"| node_private_hosts
node_tailnet_network -->|"sends HTTP"| node_http_serve
node_tailnet_network -->|"opens TCP"| node_tcp_listen
node_http_serve -->|"resolves caller"| node_identity_status
node_node_lifecycle -->|"configures option"| node_exit_node
node_node_lifecycle -->|"advertises routes"| node_subnet_router
node_exit_node -->|"forwards TCP"| node_internet
node_subnet_router -->|"routes traffic"| node_private_hosts

click node_do_wrapper "https://github.com/littledivy/tailnet-do/blob/main/src/index.js"
click node_tailnet_api "https://github.com/littledivy/tailnet-do/blob/main/src/index.js"
click node_wasm_runtime "https://github.com/littledivy/tailnet-do/blob/main/src/wasm_exec.js"
click node_engine "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_node_lifecycle "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_identity_status "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_peer_dial "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_tailnet_fetch "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_http_serve "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_tcp_listen "https://github.com/littledivy/tailnet-do/blob/main/go/main.go"
click node_exit_node "https://github.com/littledivy/tailnet-do/tree/main/go"
click node_subnet_router "https://github.com/littledivy/tailnet-do/tree/main/go"
click node_doh "https://github.com/littledivy/tailnet-do/blob/main/src/index.js"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_do_wrapper,node_tailnet_api,node_wasm_runtime toneBlue
class node_engine,node_node_lifecycle,node_identity_status toneAmber
class node_peer_dial,node_tailnet_fetch,node_http_serve,node_tcp_listen,node_exit_node,node_subnet_router toneMint
class node_do_storage,node_cloudflare_sockets,node_doh,node_worker toneRose
class node_tailnet_network,node_control_derp,node_private_hosts,node_internet toneIndigo
```

## Components

### Worker API

- [TailnetObject](https://github.com/littledivy/tailnet-do/blob/main/src/index.js): `src/index.js`
- [Tailnet API](https://github.com/littledivy/tailnet-do/blob/main/src/index.js): `src/index.js`
- [Go Wasm runtime](https://github.com/littledivy/tailnet-do/blob/main/src/wasm_exec.js): `src/wasm_exec.js`

### Tailnet node

- [Tailscale engine](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Node lifecycle](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Identity and status](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`

### Tailnet traffic

- [Peer TCP dial](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Tailnet HTTP client](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Tailnet HTTP server](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Tailnet TCP listener](https://github.com/littledivy/tailnet-do/blob/main/go/main.go): `go/main.go`
- [Exit node](https://github.com/littledivy/tailnet-do/tree/main/go): `go`
- [Subnet router](https://github.com/littledivy/tailnet-do/tree/main/go): `go`

### Platform and network

- **DO state storage**
- **Cloudflare sockets**
- [DNS over HTTPS](https://github.com/littledivy/tailnet-do/blob/main/src/index.js): `src/index.js`

### Other components

- **Worker**
- **Tailnet peers**
- **Control plane and DERP**
- **Private hosts**
- **Internet destinations**

## Connections

- Worker → TailnetObject: calls RPC (evidence: `README.md`)
- TailnetObject → Tailnet API: starts node (evidence: `src/index.js`)
- Tailnet API → Go Wasm runtime: loads runtime (evidence: `src/index.js`)
- Tailnet API → Tailscale engine: creates node (evidence: `src/index.js`)
- Tailscale engine → Node lifecycle: starts node (evidence: `go/main.go`)
- Tailnet API → DO state storage: reads and writes state (evidence: `src/index.js`)
- Tailscale engine → Control plane and DERP: connects by WebSocket (evidence: `README.md`)
- Tailscale engine → Identity and status: reports status (evidence: `go/main.go`)
- TailnetObject → Peer TCP dial: exposes connect (evidence: `README.md`)
- TailnetObject → Tailnet HTTP client: exposes fetch (evidence: `README.md`)
- Worker → Private hosts: requests via node (evidence: `README.md`)
- Tailnet API → Cloudflare sockets: opens sockets (evidence: `src/index.js`)
- Tailscale engine → Cloudflare sockets: dials outbound (evidence: `go/main.go`)
- Tailscale engine → DNS over HTTPS: queries DNS (evidence: `src/index.js`)
- Peer TCP dial → Private hosts: dials TCP (evidence: `README.md`)
- Tailnet peers → Tailnet HTTP server: sends HTTP (evidence: `README.md`)
- Tailnet peers → Tailnet TCP listener: opens TCP (evidence: `README.md`)
- Tailnet HTTP server → Identity and status: resolves caller (evidence: `go/main.go`)
- Node lifecycle → Exit node: configures option (evidence: `README.md`)
- Node lifecycle → Subnet router: advertises routes (evidence: `README.md`)
- Exit node → Internet destinations: forwards TCP (evidence: `README.md`)
- Subnet router → Private hosts: routes traffic (evidence: `README.md`)
