tailscale
v0.1.9Tailscale as an iii worker — tailscale::* functions for connectivity and peers, exit nodes and preferences, Serve and Funnel publishing, Taildrop, certificates, Taildrive, accounts, tailnet lock, and updates, plus a Console page with QR links.
- macOS: arm64
- Linux: arm64 · armv7 · x64
- Windows: arm64 · x64
exact versions are immutable; binary and bundle artifacts are digest-pinned.
full markdown
/workers/tailscale.md. paste it into an llm prompt or pipe it through curl from a worker.install
dependencies
readme
tailscale
Tailscale as an iii worker. It drives the tailscale CLI on the Console host and exposes the whole client surface as typed tailscale::* functions: connectivity and peers, exit nodes and preferences, publishing local services or the Console to the tailnet with Serve or to the internet with Funnel, Taildrop file transfer, HTTPS certificates, Taildrive, accounts, tailnet lock, and updates. Every result is structured with keys and secrets stripped, every change to the network is approval-gated, and a Tailscale page in the Console puts the everyday actions one click away with QR codes for links.
Install
iii trigger compose::add worker=tailscaleiii trigger compose::add declares the worker in worker-compose.yaml and starts it as part of the Compose project. The host needs Tailscale installed; most functions also need the node signed in (tailscale::login returns the sign-in URL, tailscale::connect brings it up). Publishing needs MagicDNS and HTTPS certificates enabled for the tailnet; Funnel additionally needs a one-time tailnet-admin approval.
Quickstart
Open Tailscale from the Console navigation or press ⌘K and run Open Tailscale. The page shows the connection, the devices on your tailnet, network diagnostics, preferences, Taildrop, and publishing; its ⌘K rows refresh, create a link, copy it, open it, and stop the route.
From a function call, ask the node what it sees:
iii trigger tailscale::status
iii trigger tailscale::peers::list online_only=true
iii trigger tailscale::ping target=phone count=3{
"target": "phone",
"direct": true,
"replies": [
{ "via": "derp", "latency_ms": 41.2, "line": "pong from phone (100.64.0.2) via DERP(nyc) in 41.2ms" },
{ "via": "direct", "latency_ms": 3.4, "line": "pong from phone (100.64.0.2) via 192.0.2.7:41641 in 3.4ms" }
],
"raw": "…"
}Publish the Console to your own devices, then send a file to your phone:
iii trigger tailscale::share mode=serve https_port=443 path=/
iii trigger tailscale::file::send --json '{"paths":["/Users/me/report.pdf"],"target":"phone"}'tailscale::share returns the HTTPS link and its QR code; mode=funnel publishes to the internet and needs allow_funnel: true in the configuration plus confirm_public: true on the request. tailscale::serve::add publishes any local port, loopback URL, or directory the same way. Stopping a Funnel route (share::stop / serve::remove with mode=funnel) removes public access and keeps the tailnet route; mode=serve removes the route. The worker never resets routes it did not create unless serve::reset is called with confirm=true.
The full catalogue lives in skills/SKILL.md and in iii worker info tailscale.
Configuration
Settings live in the configuration worker under the id tailscale; edit them in the Console's global Settings modal and the worker reloads without a restart. An optional --config YAML seed is used only when the entry is first created.
tailscale_binary: tailscale # CLI name or absolute path
console_url: http://127.0.0.1:3113 # loopback Console root that tailscale::share publishes
default_https_port: 443 # port used when a publish request omits one
allow_funnel: false # operator lock for public Funnel routes
command_timeout_ms: 20000 # per CLI invocationRun from source with compose
Workers in this repository run locally through iii compose. Add a container after the console:
containers:
tailscale:
worker: path://../tailscale
start_after:
- console
environment:
RUST_LOG: info
scripts:
run: cargo run --locked --bin tailscaleThe first build runs pnpm install && pnpm build inside ui/ (Node 22 on PATH); set SKIP_UI_BUILD=1 to reuse an existing ui/dist. III_TAILSCALE_UI_WATCH=1 hot-reloads the page from ui/dist into open Console tabs while pnpm --dir ui watch runs.
Security
- Read-only functions (status, peers, netcheck, ping, whois, DNS, preferences, route list, Taildrop targets, lock status, accounts, metrics) are allowed for agents by default. Connect, login, logout, publishing, route removal, preference changes, exit node, Taildrop, Taildrive, certificates, account switch, and update need approval.
- Serve routes are reachable only by devices your tailnet policy admits and carry
Tailscale-User-Login/Tailscale-User-Nameheaders. Funnel routes are public and carry no identity headers; both locks (allow_funnelandconfirm_public) are required and the page confirms before publishing. serve::addtargets must be a local port, a loopback URL, or an absolute path; the Console target forsharemust be a loopback URL pointing at the Console root.- Responses never include node keys, private keys, capability maps, or login secrets;
tailscale debug prefsis read for preferences and itsConfigblock is dropped.
api reference (json)
{
"functions": [
{
"description": "List the Tailscale accounts logged in on this device and which one is active.",
"metadata": {},
"name": "tailscale::accounts::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Account": {
"properties": {
"account": {
"description": "Login name.",
"type": "string"
},
"id": {
"description": "Short id used by `switch`.",
"type": "string"
},
"nickname": {
"description": "Nickname, when set.",
"type": [
"string",
"null"
]
},
"selected": {
"description": "Whether this account is active.",
"type": "boolean"
},
"tailnet": {
"description": "Tailnet name.",
"type": "string"
}
},
"required": [
"account",
"id",
"selected",
"tailnet"
],
"type": "object"
}
},
"properties": {
"accounts": {
"description": "Accounts logged in on this device.",
"items": {
"$ref": "#/definitions/Account"
},
"type": "array"
}
},
"required": [
"accounts"
],
"title": "AccountsOutput",
"type": "object"
}
},
{
"description": "Switch this device to another logged-in Tailscale account by id, tailnet, or login name.",
"metadata": {},
"name": "tailscale::accounts::switch",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"account": {
"description": "Account id, tailnet, login name, or nickname from accounts::list.",
"type": "string"
}
},
"required": [
"account"
],
"title": "AccountSwitchInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Account": {
"properties": {
"account": {
"description": "Login name.",
"type": "string"
},
"id": {
"description": "Short id used by `switch`.",
"type": "string"
},
"nickname": {
"description": "Nickname, when set.",
"type": [
"string",
"null"
]
},
"selected": {
"description": "Whether this account is active.",
"type": "boolean"
},
"tailnet": {
"description": "Tailnet name.",
"type": "string"
}
},
"required": [
"account",
"id",
"selected",
"tailnet"
],
"type": "object"
}
},
"properties": {
"accounts": {
"description": "Accounts logged in on this device.",
"items": {
"$ref": "#/definitions/Account"
},
"type": "array"
}
},
"required": [
"accounts"
],
"title": "AccountsOutput",
"type": "object"
}
},
{
"description": "Generate a Tailscale bug report identifier that support can look up; optional note and in-depth diagnosis.",
"metadata": {},
"name": "tailscale::bugreport",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"diagnose": {
"default": false,
"description": "Run additional in-depth checks.",
"type": "boolean"
},
"note": {
"description": "Free-text note attached to the report.",
"type": [
"string",
"null"
]
}
},
"title": "BugreportInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
},
"report_id": {
"description": "Shareable bug report identifier.",
"type": "string"
}
},
"required": [
"output",
"report_id"
],
"title": "BugreportOutput",
"type": "object"
}
},
{
"description": "Fetch a Let's Encrypt certificate and key for one of this node's MagicDNS domains (`tailscale cert`). Requires HTTPS enabled for the tailnet.",
"metadata": {},
"name": "tailscale::cert",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"cert_file": {
"description": "Absolute path to write the certificate to.",
"type": "string"
},
"domain": {
"description": "One of this node's certificate domains, as reported by dns::status `cert_domains`.",
"type": "string"
},
"key_file": {
"description": "Absolute path to write the private key to.",
"type": "string"
}
},
"required": [
"cert_file",
"domain",
"key_file"
],
"title": "CertInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"cert_file": {
"description": "Path of the written certificate.",
"type": "string"
},
"domain": {
"description": "Domain the certificate was issued for.",
"type": "string"
},
"key_file": {
"description": "Path of the written private key.",
"type": "string"
},
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"cert_file",
"domain",
"key_file",
"output"
],
"title": "CertOutput",
"type": "object"
}
},
{
"description": "Return the non-secret worker settings and the current Serve configuration. The CLI path is omitted.",
"metadata": {},
"name": "tailscale::configuration",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"allow_funnel": {
"description": "Whether public Funnel shares are permitted by the operator.",
"type": "boolean"
},
"command_timeout_ms": {
"description": "Per-command timeout for the Tailscale CLI.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"console_url": {
"description": "Local Console URL the Console share routes proxy to.",
"type": "string"
},
"default_https_port": {
"description": "HTTPS port used when a share request omits one.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"routes": {
"description": "Active Serve and Funnel routes on this node.",
"items": {
"$ref": "#/definitions/Route"
},
"type": "array"
},
"serve_config": {
"description": "Raw `tailscale serve status --json` output."
}
},
"required": [
"allow_funnel",
"command_timeout_ms",
"console_url",
"default_https_port",
"routes",
"serve_config"
],
"title": "ConfigurationOutput",
"type": "object"
}
},
{
"description": "Connect this node to the tailnet (`tailscale up`). When the node still needs a sign-in, returns the Tailscale login URL instead of connecting.",
"metadata": {},
"name": "tailscale::connect",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"authorization_url": {
"description": "Tailscale sign-in page when the node still needs a login; open it, then call connect again.",
"type": [
"string",
"null"
]
},
"backend_state": {
"description": "Backend state reported by the client after the call.",
"type": [
"string",
"null"
]
},
"connected": {
"description": "True when the node is connected to the tailnet after the call.",
"type": "boolean"
}
},
"required": [
"connected"
],
"title": "ConnectOutput",
"type": "object"
}
},
{
"description": "Disconnect this node from the tailnet (`tailscale down`). Shared routes stop answering until the node connects again.",
"metadata": {},
"name": "tailscale::disconnect",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"backend_state": {
"description": "Backend state reported by the client after the call, normally `Stopped` or `NeedsLogin`.",
"type": [
"string",
"null"
]
},
"connected": {
"description": "False once the node has left the tailnet.",
"type": "boolean"
}
},
"required": [
"connected"
],
"title": "DisconnectOutput",
"type": "object"
}
},
{
"description": "Resolve a name through the Tailscale DNS forwarder (100.100.100.100).",
"metadata": {},
"name": "tailscale::dns::query",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Name to resolve.",
"type": "string"
},
"record_type": {
"default": "A",
"description": "Record type such as A, AAAA, CNAME, TXT; defaults to A.",
"type": "string"
}
},
"required": [
"name"
],
"title": "DnsQueryInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"answers": {
"description": "Answer records as the forwarder returned them."
},
"name": {
"description": "Name that was resolved.",
"type": "string"
},
"record_type": {
"description": "Record type that was queried.",
"type": "string"
}
},
"required": [
"answers",
"name",
"record_type"
],
"title": "DnsQueryOutput",
"type": "object"
}
},
{
"description": "Report the MagicDNS and split-DNS configuration the local Tailscale DNS forwarder is using.",
"metadata": {},
"name": "tailscale::dns::status",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SplitDnsRoute": {
"properties": {
"domain": {
"description": "Domain suffix routed to the resolvers.",
"type": "string"
},
"resolvers": {
"description": "Resolvers used for that suffix.",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"domain",
"resolvers"
],
"type": "object"
}
},
"properties": {
"cert_domains": {
"description": "Domains this node can obtain HTTPS certificates for.",
"items": {
"type": "string"
},
"type": "array"
},
"magic_dns": {
"description": "Whether MagicDNS is enabled for this node.",
"type": "boolean"
},
"magic_dns_suffix": {
"description": "MagicDNS suffix of the tailnet.",
"type": [
"string",
"null"
]
},
"resolvers": {
"description": "Upstream resolvers Tailscale forwards to.",
"items": {
"type": "string"
},
"type": "array"
},
"search_domains": {
"description": "Search domains pushed by the tailnet.",
"items": {
"type": "string"
},
"type": "array"
},
"split_dns_routes": {
"description": "Split-DNS routes: domain suffix to resolvers.",
"items": {
"$ref": "#/definitions/SplitDnsRoute"
},
"type": "array"
}
},
"required": [
"cert_domains",
"magic_dns",
"resolvers",
"search_domains",
"split_dns_routes"
],
"title": "DnsStatusOutput",
"type": "object"
}
},
{
"description": "List the directories this node shares with the tailnet through Taildrive. The macOS GUI app manages Taildrive in its own settings and rejects the CLI.",
"metadata": {},
"name": "tailscale::drive::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"DriveShare": {
"properties": {
"name": {
"description": "Share name.",
"type": "string"
},
"path": {
"description": "Directory shared.",
"type": "string"
}
},
"required": [
"name",
"path"
],
"type": "object"
}
},
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
},
"shares": {
"description": "Taildrive shares as `name path` lines from the CLI.",
"items": {
"$ref": "#/definitions/DriveShare"
},
"type": "array"
}
},
"required": [
"output",
"shares"
],
"title": "DriveListOutput",
"type": "object"
}
},
{
"description": "Share a directory with the tailnet through Taildrive under a name (`tailscale drive share`).",
"metadata": {},
"name": "tailscale::drive::share",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Share name.",
"type": "string"
},
"path": {
"description": "Absolute directory to share.",
"type": "string"
}
},
"required": [
"name",
"path"
],
"title": "DriveShareInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"DriveShare": {
"properties": {
"name": {
"description": "Share name.",
"type": "string"
},
"path": {
"description": "Directory shared.",
"type": "string"
}
},
"required": [
"name",
"path"
],
"type": "object"
}
},
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
},
"shares": {
"description": "Taildrive shares as `name path` lines from the CLI.",
"items": {
"$ref": "#/definitions/DriveShare"
},
"type": "array"
}
},
"required": [
"output",
"shares"
],
"title": "DriveListOutput",
"type": "object"
}
},
{
"description": "Stop sharing a Taildrive directory by name (`tailscale drive unshare`).",
"metadata": {},
"name": "tailscale::drive::unshare",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Share name.",
"type": "string"
}
},
"required": [
"name"
],
"title": "DriveUnshareInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"DriveShare": {
"properties": {
"name": {
"description": "Share name.",
"type": "string"
},
"path": {
"description": "Directory shared.",
"type": "string"
}
},
"required": [
"name",
"path"
],
"type": "object"
}
},
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
},
"shares": {
"description": "Taildrive shares as `name path` lines from the CLI.",
"items": {
"$ref": "#/definitions/DriveShare"
},
"type": "array"
}
},
"required": [
"output",
"shares"
],
"title": "DriveListOutput",
"type": "object"
}
},
{
"description": "List the available exit nodes for internet traffic, and which one this node uses.",
"metadata": {},
"name": "tailscale::exit-node::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Peer": {
"properties": {
"active": {
"description": "Whether this node currently exchanges traffic with the peer.",
"type": "boolean"
},
"dns_name": {
"description": "MagicDNS name without the trailing dot.",
"type": "string"
},
"exit_node": {
"description": "Whether this node routes internet traffic through the peer.",
"type": "boolean"
},
"exit_node_option": {
"description": "Whether the peer offers to be an exit node.",
"type": "boolean"
},
"hostname": {
"description": "Machine name.",
"type": "string"
},
"id": {
"description": "Stable node id.",
"type": "string"
},
"ingress": {
"description": "True for Tailscale's Funnel ingress relay nodes, which are infrastructure rather than devices.",
"type": "boolean"
},
"last_seen": {
"description": "When the peer was last seen, RFC 3339.",
"type": [
"string",
"null"
]
},
"online": {
"description": "Whether the peer is online.",
"type": "boolean"
},
"os": {
"description": "Operating system reported by the peer.",
"type": [
"string",
"null"
]
},
"relay": {
"description": "DERP relay the connection currently uses, empty when direct.",
"type": [
"string",
"null"
]
},
"rx_bytes": {
"description": "Bytes received from the peer.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"tags": {
"description": "ACL tags on the peer.",
"items": {
"type": "string"
},
"type": "array"
},
"taildrop_target": {
"description": "Whether the peer accepts Taildrop files from this node.",
"type": "boolean"
},
"tailscale_ips": {
"description": "Tailscale IPv4 and IPv6 addresses.",
"items": {
"type": "string"
},
"type": "array"
},
"tx_bytes": {
"description": "Bytes sent to the peer.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"active",
"dns_name",
"exit_node",
"exit_node_option",
"hostname",
"id",
"ingress",
"online",
"rx_bytes",
"tags",
"taildrop_target",
"tailscale_ips",
"tx_bytes"
],
"type": "object"
}
},
"properties": {
"current": {
"description": "MagicDNS name of the exit node in use, if any.",
"type": [
"string",
"null"
]
},
"exit_nodes": {
"description": "Peers offering to be an exit node.",
"items": {
"$ref": "#/definitions/Peer"
},
"type": "array"
}
},
"required": [
"exit_nodes"
],
"title": "ExitNodesOutput",
"type": "object"
}
},
{
"description": "Route this node's internet traffic through an exit node (by name or IP, or `auto:any`), or clear it with an empty value.",
"metadata": {},
"name": "tailscale::exit-node::set",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"allow_lan_access": {
"description": "Allow direct access to the local LAN while the exit node is in use.",
"type": [
"boolean",
"null"
]
},
"exit_node": {
"description": "Exit node by MagicDNS name, hostname, Tailscale IP, or `auto:any`; empty or omitted clears the exit node.",
"type": [
"string",
"null"
]
}
},
"title": "ExitNodeSetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"accept_dns": {
"description": "Accept DNS configuration from the tailnet.",
"type": "boolean"
},
"accept_routes": {
"description": "Accept subnet routes advertised by other nodes.",
"type": "boolean"
},
"advertise_exit_node": {
"description": "Whether this node advertises itself as an exit node.",
"type": "boolean"
},
"advertise_routes": {
"description": "Subnet routes this node advertises.",
"items": {
"type": "string"
},
"type": "array"
},
"advertise_tags": {
"description": "ACL tags requested by this node.",
"items": {
"type": "string"
},
"type": "array"
},
"app_connector": {
"description": "Advertised as an app connector.",
"type": "boolean"
},
"auto_update_apply": {
"description": "Automatic updates applied.",
"type": "boolean"
},
"auto_update_check": {
"description": "Automatic update checks enabled.",
"type": "boolean"
},
"control_url": {
"description": "Control server URL.",
"type": [
"string",
"null"
]
},
"exit_node_allow_lan_access": {
"description": "LAN access allowed while using an exit node.",
"type": "boolean"
},
"exit_node_id": {
"description": "Exit node in use, by id.",
"type": [
"string",
"null"
]
},
"exit_node_ip": {
"description": "Exit node in use, by IP.",
"type": [
"string",
"null"
]
},
"hostname": {
"description": "Hostname override, empty when the OS name is used.",
"type": [
"string",
"null"
]
},
"logged_out": {
"description": "Whether the node is logged out.",
"type": "boolean"
},
"posture_checking": {
"description": "Device posture reporting enabled.",
"type": "boolean"
},
"shields_up": {
"description": "Incoming connections blocked.",
"type": "boolean"
},
"ssh": {
"description": "Tailscale SSH server enabled on this node.",
"type": "boolean"
},
"want_running": {
"description": "Whether the node wants to be connected.",
"type": "boolean"
},
"webclient": {
"description": "Web client exposed on port 5252.",
"type": "boolean"
}
},
"required": [
"accept_dns",
"accept_routes",
"advertise_exit_node",
"advertise_routes",
"advertise_tags",
"app_connector",
"auto_update_apply",
"auto_update_check",
"exit_node_allow_lan_access",
"logged_out",
"posture_checking",
"shields_up",
"ssh",
"want_running",
"webclient"
],
"title": "Prefs",
"type": "object"
}
},
{
"description": "Ask Tailscale for the best available exit node for this node.",
"metadata": {},
"name": "tailscale::exit-node::suggest",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"message": {
"description": "The CLI's own wording.",
"type": "string"
},
"suggestion": {
"description": "Suggested exit node name, or null when Tailscale has none to offer.",
"type": [
"string",
"null"
]
}
},
"required": [
"message"
],
"title": "ExitNodeSuggestion",
"type": "object"
}
},
{
"description": "Move files that arrived in this node's Taildrop inbox into a directory (`tailscale file get`).",
"metadata": {},
"name": "tailscale::file::receive",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Conflict": {
"enum": [
"skip",
"overwrite",
"rename"
],
"type": "string"
}
},
"properties": {
"conflict": {
"allOf": [
{
"$ref": "#/definitions/Conflict"
}
],
"default": "skip",
"description": "What to do when a same-named file exists; defaults to `skip`."
},
"directory": {
"description": "Absolute directory that receives the inbox files.",
"type": "string"
},
"wait": {
"default": false,
"description": "Wait for at least one file to arrive before returning.",
"type": "boolean"
}
},
"required": [
"directory"
],
"title": "FileReceiveInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"description": "True when the CLI exited successfully.",
"type": "boolean"
},
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"ok",
"output"
],
"title": "CommandOutput",
"type": "object"
}
},
{
"description": "Send files to a tailnet device with Taildrop (`tailscale file cp`). Paths must be absolute and exist on this host.",
"metadata": {},
"name": "tailscale::file::send",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"description": "Alternate file name to use when sending a single file.",
"type": [
"string",
"null"
]
},
"paths": {
"description": "Absolute paths of the files to send.",
"items": {
"type": "string"
},
"minItems": 1,
"type": "array"
},
"target": {
"description": "Receiving device by machine name or Tailscale IP.",
"type": "string"
}
},
"required": [
"paths",
"target"
],
"title": "FileSendInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"description": "True when the CLI exited successfully.",
"type": "boolean"
},
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"ok",
"output"
],
"title": "CommandOutput",
"type": "object"
}
},
{
"description": "List the tailnet devices that accept Taildrop files from this node.",
"metadata": {},
"name": "tailscale::file::targets",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"FileTarget": {
"properties": {
"ip": {
"description": "Tailscale IP of the device.",
"type": "string"
},
"name": {
"description": "Machine name of the device.",
"type": "string"
}
},
"required": [
"ip",
"name"
],
"type": "object"
}
},
"properties": {
"targets": {
"description": "Devices that accept Taildrop files from this node.",
"items": {
"$ref": "#/definitions/FileTarget"
},
"type": "array"
}
},
"required": [
"targets"
],
"title": "FileTargetsOutput",
"type": "object"
}
},
{
"description": "Get this node's Tailscale IP addresses, or a peer's by name or IP.",
"metadata": {},
"name": "tailscale::ip",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"peer": {
"description": "Peer hostname or Tailscale IP; omitted means this node.",
"type": [
"string",
"null"
]
}
},
"title": "IpInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"addresses": {
"description": "Tailscale IPv4 and IPv6 addresses.",
"items": {
"type": "string"
},
"type": "array"
},
"peer": {
"description": "Peer the addresses belong to, or `self`.",
"type": "string"
}
},
"required": [
"addresses",
"peer"
],
"title": "IpOutput",
"type": "object"
}
},
{
"description": "Report whether tailnet lock is enabled and this node's tailnet-lock public key.",
"metadata": {},
"name": "tailscale::lock::status",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"enabled": {
"description": "Whether tailnet lock is enabled for the tailnet.",
"type": "boolean"
},
"node_key": {
"description": "This node's tailnet-lock public key (`tlpub:…`), safe to share with admins.",
"type": [
"string",
"null"
]
},
"node_signed": {
"description": "Whether this node is signed under tailnet lock, when enabled.",
"type": [
"boolean",
"null"
]
},
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"enabled",
"output"
],
"title": "LockStatusOutput",
"type": "object"
}
},
{
"description": "Sign in to Tailscale on this node (`tailscale login`). Returns the browser URL a person completes it at; call connect afterwards.",
"metadata": {},
"name": "tailscale::login",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"authorization_url": {
"description": "Tailscale sign-in page when the node still needs a login; open it, then call connect again.",
"type": [
"string",
"null"
]
},
"backend_state": {
"description": "Backend state reported by the client after the call.",
"type": [
"string",
"null"
]
},
"connected": {
"description": "True when the node is connected to the tailnet after the call.",
"type": "boolean"
}
},
"required": [
"connected"
],
"title": "ConnectOutput",
"type": "object"
}
},
{
"description": "Log this node out (`tailscale logout`): disconnects and expires the node key, so the next connect needs a fresh sign-in.",
"metadata": {},
"name": "tailscale::logout",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"backend_state": {
"description": "Backend state reported by the client after the call, normally `Stopped` or `NeedsLogin`.",
"type": [
"string",
"null"
]
},
"connected": {
"description": "False once the node has left the tailnet.",
"type": "boolean"
}
},
"required": [
"connected"
],
"title": "DisconnectOutput",
"type": "object"
}
},
{
"description": "Return the client's user-facing metrics in Prometheus text format.",
"metadata": {},
"name": "tailscale::metrics",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"output"
],
"title": "TextOutput",
"type": "object"
}
},
{
"description": "Analyse the local network for Tailscale: UDP reachability, IPv4/IPv6, NAT mapping, port-mapping protocols, the preferred DERP relay and relay latencies.",
"metadata": {},
"name": "tailscale::netcheck",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"RegionLatency": {
"properties": {
"latency_ms": {
"description": "Round-trip latency in milliseconds.",
"format": "double",
"type": "number"
},
"region": {
"description": "DERP region id.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"latency_ms",
"region"
],
"type": "object"
}
},
"properties": {
"captive_portal": {
"description": "Captive portal detected on the network.",
"type": [
"boolean",
"null"
]
},
"global_v4": {
"description": "Public IPv4 address seen by the relays.",
"type": [
"string",
"null"
]
},
"global_v6": {
"description": "Public IPv6 address seen by the relays.",
"type": [
"string",
"null"
]
},
"ipv4": {
"description": "Whether IPv4 is usable.",
"type": "boolean"
},
"ipv6": {
"description": "Whether IPv6 is usable.",
"type": "boolean"
},
"mapping_varies_by_dest_ip": {
"description": "True when the NAT maps to different ports per destination (hard NAT).",
"type": [
"boolean",
"null"
]
},
"pcp": {
"type": [
"boolean",
"null"
]
},
"pmp": {
"type": [
"boolean",
"null"
]
},
"preferred_derp": {
"description": "DERP relay region the client prefers.",
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"region_latency_ms": {
"description": "Round-trip latency to each DERP region in milliseconds.",
"items": {
"$ref": "#/definitions/RegionLatency"
},
"type": "array"
},
"udp": {
"description": "Whether UDP traffic reaches the internet.",
"type": "boolean"
},
"upnp": {
"description": "Port-mapping protocols the router offers.",
"type": [
"boolean",
"null"
]
}
},
"required": [
"ipv4",
"ipv6",
"region_latency_ms",
"udp"
],
"title": "NetcheckOutput",
"type": "object"
}
},
{
"description": "Internal: reload Tailscale settings after a configuration update.",
"metadata": {
"internal": true
},
"name": "tailscale::on-config-change",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OnConfigChangeInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ok": {
"type": "boolean"
}
},
"required": [
"ok"
],
"title": "OnConfigChangeOutput",
"type": "object"
}
},
{
"description": "List the devices on your Tailscale network (tailnet) and whether each is online. Also names, IPs, OS, tags, exit-node offers, traffic counters; keys omitted.",
"metadata": {},
"name": "tailscale::peers::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"include_ingress": {
"default": false,
"description": "Include Tailscale's Funnel ingress relay nodes (`funnel-ingress-node`, tag `tag:ingress`), which are infrastructure rather than devices.",
"type": "boolean"
},
"online_only": {
"default": false,
"description": "Only peers that are online right now.",
"type": "boolean"
}
},
"title": "PeersInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Peer": {
"properties": {
"active": {
"description": "Whether this node currently exchanges traffic with the peer.",
"type": "boolean"
},
"dns_name": {
"description": "MagicDNS name without the trailing dot.",
"type": "string"
},
"exit_node": {
"description": "Whether this node routes internet traffic through the peer.",
"type": "boolean"
},
"exit_node_option": {
"description": "Whether the peer offers to be an exit node.",
"type": "boolean"
},
"hostname": {
"description": "Machine name.",
"type": "string"
},
"id": {
"description": "Stable node id.",
"type": "string"
},
"ingress": {
"description": "True for Tailscale's Funnel ingress relay nodes, which are infrastructure rather than devices.",
"type": "boolean"
},
"last_seen": {
"description": "When the peer was last seen, RFC 3339.",
"type": [
"string",
"null"
]
},
"online": {
"description": "Whether the peer is online.",
"type": "boolean"
},
"os": {
"description": "Operating system reported by the peer.",
"type": [
"string",
"null"
]
},
"relay": {
"description": "DERP relay the connection currently uses, empty when direct.",
"type": [
"string",
"null"
]
},
"rx_bytes": {
"description": "Bytes received from the peer.",
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"tags": {
"description": "ACL tags on the peer.",
"items": {
"type": "string"
},
"type": "array"
},
"taildrop_target": {
"description": "Whether the peer accepts Taildrop files from this node.",
"type": "boolean"
},
"tailscale_ips": {
"description": "Tailscale IPv4 and IPv6 addresses.",
"items": {
"type": "string"
},
"type": "array"
},
"tx_bytes": {
"description": "Bytes sent to the peer.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"active",
"dns_name",
"exit_node",
"exit_node_option",
"hostname",
"id",
"ingress",
"online",
"rx_bytes",
"tags",
"taildrop_target",
"tailscale_ips",
"tx_bytes"
],
"type": "object"
}
},
"properties": {
"hidden_ingress_count": {
"description": "Funnel ingress relay nodes left out because `include_ingress` was false.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"peers": {
"description": "Peers in name order.",
"items": {
"$ref": "#/definitions/Peer"
},
"type": "array"
}
},
"required": [
"hidden_ingress_count",
"peers"
],
"title": "PeersOutput",
"type": "object"
}
},
{
"description": "Ping a peer at the Tailscale layer and report whether each reply came over a DERP relay or a direct path.",
"metadata": {},
"name": "tailscale::ping",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"count": {
"default": 5,
"description": "Number of pings to send; defaults to 5.",
"format": "uint8",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Peer hostname or Tailscale IP.",
"type": "string"
},
"timeout_ms": {
"default": 5000,
"description": "Per-ping timeout in milliseconds; defaults to 5000.",
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"target"
],
"title": "PingInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"PingReply": {
"properties": {
"latency_ms": {
"description": "Round-trip time in milliseconds.",
"format": "double",
"type": [
"number",
"null"
]
},
"line": {
"description": "The CLI line for this reply.",
"type": "string"
},
"via": {
"description": "`direct` or `derp`.",
"type": "string"
}
},
"required": [
"line",
"via"
],
"type": "object"
}
},
"properties": {
"direct": {
"description": "True when at least one reply arrived over a direct path.",
"type": "boolean"
},
"raw": {
"description": "Raw CLI output.",
"type": "string"
},
"replies": {
"description": "One entry per reply, in order.",
"items": {
"$ref": "#/definitions/PingReply"
},
"type": "array"
},
"target": {
"description": "Target as given.",
"type": "string"
}
},
"required": [
"direct",
"raw",
"replies",
"target"
],
"title": "PingOutput",
"type": "object"
}
},
{
"description": "Read this node's Tailscale preferences: routes, DNS, exit node, SSH, shields-up, hostname, auto-update. Keys and login secrets are omitted.",
"metadata": {},
"name": "tailscale::prefs::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"accept_dns": {
"description": "Accept DNS configuration from the tailnet.",
"type": "boolean"
},
"accept_routes": {
"description": "Accept subnet routes advertised by other nodes.",
"type": "boolean"
},
"advertise_exit_node": {
"description": "Whether this node advertises itself as an exit node.",
"type": "boolean"
},
"advertise_routes": {
"description": "Subnet routes this node advertises.",
"items": {
"type": "string"
},
"type": "array"
},
"advertise_tags": {
"description": "ACL tags requested by this node.",
"items": {
"type": "string"
},
"type": "array"
},
"app_connector": {
"description": "Advertised as an app connector.",
"type": "boolean"
},
"auto_update_apply": {
"description": "Automatic updates applied.",
"type": "boolean"
},
"auto_update_check": {
"description": "Automatic update checks enabled.",
"type": "boolean"
},
"control_url": {
"description": "Control server URL.",
"type": [
"string",
"null"
]
},
"exit_node_allow_lan_access": {
"description": "LAN access allowed while using an exit node.",
"type": "boolean"
},
"exit_node_id": {
"description": "Exit node in use, by id.",
"type": [
"string",
"null"
]
},
"exit_node_ip": {
"description": "Exit node in use, by IP.",
"type": [
"string",
"null"
]
},
"hostname": {
"description": "Hostname override, empty when the OS name is used.",
"type": [
"string",
"null"
]
},
"logged_out": {
"description": "Whether the node is logged out.",
"type": "boolean"
},
"posture_checking": {
"description": "Device posture reporting enabled.",
"type": "boolean"
},
"shields_up": {
"description": "Incoming connections blocked.",
"type": "boolean"
},
"ssh": {
"description": "Tailscale SSH server enabled on this node.",
"type": "boolean"
},
"want_running": {
"description": "Whether the node wants to be connected.",
"type": "boolean"
},
"webclient": {
"description": "Web client exposed on port 5252.",
"type": "boolean"
}
},
"required": [
"accept_dns",
"accept_routes",
"advertise_exit_node",
"advertise_routes",
"advertise_tags",
"app_connector",
"auto_update_apply",
"auto_update_check",
"exit_node_allow_lan_access",
"logged_out",
"posture_checking",
"shields_up",
"ssh",
"want_running",
"webclient"
],
"title": "Prefs",
"type": "object"
}
},
{
"description": "Change only the given Tailscale preferences (`tailscale set`): accept routes or DNS, advertise routes or exit node, hostname, shields-up, SSH server, auto-update, LAN access with an exit node.",
"metadata": {},
"name": "tailscale::prefs::set",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"accept_dns": {
"description": "Accept DNS configuration from the tailnet.",
"type": [
"boolean",
"null"
]
},
"accept_routes": {
"description": "Accept subnet routes advertised by other nodes.",
"type": [
"boolean",
"null"
]
},
"advertise_connector": {
"description": "Offer this node as an app connector.",
"type": [
"boolean",
"null"
]
},
"advertise_exit_node": {
"description": "Offer this node as an exit node.",
"type": [
"boolean",
"null"
]
},
"advertise_routes": {
"description": "Subnet routes to advertise, CIDR notation; an empty list stops advertising.",
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"auto_update": {
"description": "Apply updates automatically.",
"type": [
"boolean",
"null"
]
},
"exit_node_allow_lan_access": {
"description": "Allow direct LAN access while using an exit node.",
"type": [
"boolean",
"null"
]
},
"hostname": {
"description": "Hostname to use instead of the OS name; empty restores the OS name.",
"type": [
"string",
"null"
]
},
"report_posture": {
"description": "Report device posture to the management plane.",
"type": [
"boolean",
"null"
]
},
"shields_up": {
"description": "Block incoming connections.",
"type": [
"boolean",
"null"
]
},
"ssh": {
"description": "Run the Tailscale SSH server.",
"type": [
"boolean",
"null"
]
},
"update_check": {
"description": "Notify about available updates.",
"type": [
"boolean",
"null"
]
},
"webclient": {
"description": "Expose the web client on port 5252.",
"type": [
"boolean",
"null"
]
}
},
"title": "PrefsSetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"accept_dns": {
"description": "Accept DNS configuration from the tailnet.",
"type": "boolean"
},
"accept_routes": {
"description": "Accept subnet routes advertised by other nodes.",
"type": "boolean"
},
"advertise_exit_node": {
"description": "Whether this node advertises itself as an exit node.",
"type": "boolean"
},
"advertise_routes": {
"description": "Subnet routes this node advertises.",
"items": {
"type": "string"
},
"type": "array"
},
"advertise_tags": {
"description": "ACL tags requested by this node.",
"items": {
"type": "string"
},
"type": "array"
},
"app_connector": {
"description": "Advertised as an app connector.",
"type": "boolean"
},
"auto_update_apply": {
"description": "Automatic updates applied.",
"type": "boolean"
},
"auto_update_check": {
"description": "Automatic update checks enabled.",
"type": "boolean"
},
"control_url": {
"description": "Control server URL.",
"type": [
"string",
"null"
]
},
"exit_node_allow_lan_access": {
"description": "LAN access allowed while using an exit node.",
"type": "boolean"
},
"exit_node_id": {
"description": "Exit node in use, by id.",
"type": [
"string",
"null"
]
},
"exit_node_ip": {
"description": "Exit node in use, by IP.",
"type": [
"string",
"null"
]
},
"hostname": {
"description": "Hostname override, empty when the OS name is used.",
"type": [
"string",
"null"
]
},
"logged_out": {
"description": "Whether the node is logged out.",
"type": "boolean"
},
"posture_checking": {
"description": "Device posture reporting enabled.",
"type": "boolean"
},
"shields_up": {
"description": "Incoming connections blocked.",
"type": "boolean"
},
"ssh": {
"description": "Tailscale SSH server enabled on this node.",
"type": "boolean"
},
"want_running": {
"description": "Whether the node wants to be connected.",
"type": "boolean"
},
"webclient": {
"description": "Web client exposed on port 5252.",
"type": "boolean"
}
},
"required": [
"accept_dns",
"accept_routes",
"advertise_exit_node",
"advertise_routes",
"advertise_tags",
"app_connector",
"auto_update_apply",
"auto_update_check",
"exit_node_allow_lan_access",
"logged_out",
"posture_checking",
"shields_up",
"ssh",
"want_running",
"webclient"
],
"title": "Prefs",
"type": "object"
}
},
{
"description": "Publish any local service, port, or directory on this node over Tailscale Serve (tailnet only) or Funnel (public; needs allow_funnel and confirm_public).",
"metadata": {},
"name": "tailscale::serve::add",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"confirm_public": {
"default": false,
"description": "Required `true` for Funnel: acknowledges that the target becomes reachable by anyone with the link.",
"type": "boolean"
},
"https_port": {
"description": "HTTPS port for the listener; defaults to the configured port. Funnel accepts 443, 8443, and 10000.",
"format": "uint16",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"default": "serve",
"description": "`serve` (tailnet only, default) or `funnel` (public internet)."
},
"path": {
"default": "/",
"description": "URL path prefix to publish under; defaults to `/`.",
"type": "string"
},
"target": {
"description": "Local port (`3000`), loopback URL (`http://127.0.0.1:3000`, `https+insecure://localhost:8443`), or absolute file/directory path to publish.",
"type": "string"
}
},
"required": [
"target"
],
"title": "ServeAddInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
},
"ShareStage": {
"enum": [
"authorization_required",
"ready"
],
"type": "string"
}
},
"properties": {
"authorization_url": {
"description": "Tailscale page that enables Funnel for this node, present only when authorization is required.",
"type": [
"string",
"null"
]
},
"https_port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode that was requested."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"public": {
"description": "True when the route is reachable from the public internet.",
"type": "boolean"
},
"qr_svg": {
"description": "QR code for `url` as inline SVG markup.",
"type": "string"
},
"stage": {
"allOf": [
{
"$ref": "#/definitions/ShareStage"
}
],
"description": "`ready` when the route is live; `authorization_required` when Funnel must first be enabled for this node."
},
"target": {
"description": "Local target the route proxies to.",
"type": "string"
},
"url": {
"description": "URL to open: the published route, or the Tailscale authorization page when `stage` is `authorization_required`.",
"type": "string"
}
},
"required": [
"https_port",
"mode",
"path",
"public",
"qr_svg",
"stage",
"target",
"url"
],
"title": "ShareOutput",
"type": "object"
}
},
{
"description": "List every Serve and Funnel route on this node with its URL, target, and visibility.",
"metadata": {},
"name": "tailscale::serve::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"routes": {
"description": "Active Serve and Funnel routes on this node.",
"items": {
"$ref": "#/definitions/Route"
},
"type": "array"
}
},
"required": [
"routes"
],
"title": "RoutesOutput",
"type": "object"
}
},
{
"description": "Remove one route by mode, HTTPS port, and path. mode=funnel removes public access and keeps the tailnet-only route with its original target; mode=serve removes the route entirely.",
"metadata": {},
"name": "tailscale::serve::remove",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"https_port": {
"description": "HTTPS port of the route to stop.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode of the route to stop."
},
"path": {
"default": "/",
"description": "URL path prefix of the route to stop; defaults to `/`.",
"type": "string"
}
},
"required": [
"https_port",
"mode"
],
"title": "StopInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"https_port": {
"description": "HTTPS port of the route.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode that was stopped."
},
"path": {
"description": "URL path prefix of the route.",
"type": "string"
},
"remaining": {
"anyOf": [
{
"$ref": "#/definitions/Route"
},
{
"type": "null"
}
],
"description": "Route that remains on that listener and path after the call, if any."
},
"stopped": {
"description": "True when the route was changed.",
"type": "boolean"
}
},
"required": [
"https_port",
"mode",
"path",
"stopped"
],
"title": "StopOutput",
"type": "object"
}
},
{
"description": "Remove every Serve and Funnel route on this node (`serve reset` and `funnel reset`). Requires confirm=true.",
"metadata": {},
"name": "tailscale::serve::reset",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"confirm": {
"default": false,
"description": "Must be `true`: every Serve and Funnel route on this node is removed.",
"type": "boolean"
}
},
"title": "ResetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"routes": {
"description": "Active Serve and Funnel routes on this node.",
"items": {
"$ref": "#/definitions/Route"
},
"type": "array"
}
},
"required": [
"routes"
],
"title": "RoutesOutput",
"type": "object"
}
},
{
"description": "Share the local iii Console. Serve is tailnet-only and the default; Funnel is public and requires allow_funnel in the configuration plus confirm_public in the request.",
"metadata": {},
"name": "tailscale::share",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"confirm_public": {
"default": false,
"description": "Required `true` for Funnel: acknowledges that the Console becomes reachable by anyone with the link.",
"type": "boolean"
},
"https_port": {
"description": "HTTPS port for the listener; defaults to the configured port. Funnel accepts 443, 8443, and 10000.",
"format": "uint16",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"default": "serve",
"description": "`serve` (tailnet only, default) or `funnel` (public internet)."
},
"path": {
"default": "/",
"description": "URL path prefix to serve the Console under; defaults to `/`.",
"type": "string"
}
},
"title": "ShareInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
},
"ShareStage": {
"enum": [
"authorization_required",
"ready"
],
"type": "string"
}
},
"properties": {
"authorization_url": {
"description": "Tailscale page that enables Funnel for this node, present only when authorization is required.",
"type": [
"string",
"null"
]
},
"https_port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode that was requested."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"public": {
"description": "True when the route is reachable from the public internet.",
"type": "boolean"
},
"qr_svg": {
"description": "QR code for `url` as inline SVG markup.",
"type": "string"
},
"stage": {
"allOf": [
{
"$ref": "#/definitions/ShareStage"
}
],
"description": "`ready` when the route is live; `authorization_required` when Funnel must first be enabled for this node."
},
"target": {
"description": "Local target the route proxies to.",
"type": "string"
},
"url": {
"description": "URL to open: the published route, or the Tailscale authorization page when `stage` is `authorization_required`.",
"type": "string"
}
},
"required": [
"https_port",
"mode",
"path",
"public",
"qr_svg",
"stage",
"target",
"url"
],
"title": "ShareOutput",
"type": "object"
}
},
{
"description": "Stop one Console share by mode, HTTPS port, and path. mode=funnel removes public access and keeps the tailnet-only route; mode=serve removes the route entirely. Other routes are never reset.",
"metadata": {},
"name": "tailscale::share::stop",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"https_port": {
"description": "HTTPS port of the route to stop.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode of the route to stop."
},
"path": {
"default": "/",
"description": "URL path prefix of the route to stop; defaults to `/`.",
"type": "string"
}
},
"required": [
"https_port",
"mode"
],
"title": "StopInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"https_port": {
"description": "HTTPS port of the route.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "Mode that was stopped."
},
"path": {
"description": "URL path prefix of the route.",
"type": "string"
},
"remaining": {
"anyOf": [
{
"$ref": "#/definitions/Route"
},
{
"type": "null"
}
],
"description": "Route that remains on that listener and path after the call, if any."
},
"stopped": {
"description": "True when the route was changed.",
"type": "boolean"
}
},
"required": [
"https_port",
"mode",
"path",
"stopped"
],
"title": "StopOutput",
"type": "object"
}
},
{
"description": "Check if Tailscale is connected on this node, plus identity, health notices, and Serve and Funnel routes. Keys, users, and capability maps are omitted.",
"metadata": {},
"name": "tailscale::status",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "EmptyInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Route": {
"properties": {
"host": {
"description": "MagicDNS host name the route answers on.",
"type": "string"
},
"mode": {
"allOf": [
{
"$ref": "#/definitions/ShareMode"
}
],
"description": "`serve` for a tailnet-only route, `funnel` when the same listener is also published to the internet."
},
"path": {
"description": "URL path prefix the route serves.",
"type": "string"
},
"port": {
"description": "HTTPS port of the listener.",
"format": "uint16",
"minimum": 0,
"type": "integer"
},
"target": {
"description": "Local target the route proxies to, or the file path it serves.",
"type": "string"
},
"url": {
"description": "Full HTTPS URL a device opens to reach the route.",
"type": "string"
}
},
"required": [
"host",
"mode",
"path",
"port",
"target",
"url"
],
"type": "object"
},
"ShareMode": {
"enum": [
"serve",
"funnel"
],
"type": "string"
}
},
"properties": {
"backend_state": {
"description": "Backend state reported by the client, `Running` when connected.",
"type": [
"string",
"null"
]
},
"dns_name": {
"description": "MagicDNS name of this node without the trailing dot.",
"type": [
"string",
"null"
]
},
"error": {
"description": "Error text when the client could not be queried.",
"type": [
"string",
"null"
]
},
"exit_node": {
"description": "Exit node this node currently routes through, if any.",
"type": [
"string",
"null"
]
},
"funnel_allowed": {
"description": "Whether the tailnet policy allows this node to use Funnel.",
"type": "boolean"
},
"health": {
"description": "Health notices reported by the client.",
"items": {
"type": "string"
},
"type": "array"
},
"hostname": {
"description": "Machine name of this node.",
"type": [
"string",
"null"
]
},
"ingress_node_count": {
"description": "Tailscale Funnel ingress relay nodes in the peer list; infrastructure, excluded from the peer counts.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"installed": {
"description": "Whether the Tailscale CLI could be started.",
"type": "boolean"
},
"magic_dns_suffix": {
"description": "MagicDNS suffix of the tailnet.",
"type": [
"string",
"null"
]
},
"online": {
"description": "True when the client is running and this node is online.",
"type": "boolean"
},
"online_peer_count": {
"description": "Number of peers currently online.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"peer_count": {
"description": "Number of peers visible on the tailnet.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"routes": {
"description": "Active Serve and Funnel routes on this node.",
"items": {
"$ref": "#/definitions/Route"
},
"type": "array"
},
"tailnet": {
"description": "Name of the tailnet this node belongs to.",
"type": [
"string",
"null"
]
},
"tailscale_ips": {
"description": "Tailscale IPv4 and IPv6 addresses of this node.",
"items": {
"type": "string"
},
"type": "array"
},
"version": {
"description": "Tailscale client version.",
"type": [
"string",
"null"
]
}
},
"required": [
"funnel_allowed",
"health",
"ingress_node_count",
"installed",
"online",
"online_peer_count",
"peer_count",
"routes",
"tailscale_ips"
],
"title": "StatusOutput",
"type": "object"
}
},
{
"description": "Serve the tailscale worker's injected console UI assets (content function for its console:script / console:style triggers).",
"metadata": {
"internal": true
},
"name": "tailscale::ui-content",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input of the content function: the console asks for one asset by path.",
"properties": {
"path": {
"description": "The asset path from the trigger config (e.g. `state/page.js`).",
"type": "string"
}
},
"required": [
"path"
],
"title": "UiContentInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Output of the content function.",
"properties": {
"content": {
"description": "The asset source, verbatim.",
"type": "string"
},
"content_type": {
"description": "MIME type the console should serve the asset with.",
"type": "string"
}
},
"required": [
"content",
"content_type"
],
"title": "UiContentResult",
"type": "object"
}
},
{
"description": "Update the Tailscale client to the latest release. With dry_run=true, only report what would change.",
"metadata": {},
"name": "tailscale::update",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"dry_run": {
"default": false,
"description": "Report what an update would do without applying it.",
"type": "boolean"
}
},
"title": "UpdateInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"output": {
"description": "The CLI's own output.",
"type": "string"
}
},
"required": [
"output"
],
"title": "TextOutput",
"type": "object"
}
},
{
"description": "Report the Tailscale client version, and the latest upstream release for the track.",
"metadata": {},
"name": "tailscale::version",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"check_upstream": {
"default": false,
"description": "Also fetch the latest upstream release for the current track.",
"type": "boolean"
}
},
"title": "VersionInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"long": {
"description": "Full version string with commit hashes.",
"type": [
"string",
"null"
]
},
"os_variant": {
"description": "Client variant, e.g. `macsys`.",
"type": [
"string",
"null"
]
},
"upstream": {
"description": "Latest upstream release when `check_upstream` was set.",
"type": [
"string",
"null"
]
},
"version": {
"description": "Installed client version, e.g. `1.98.8`.",
"type": "string"
}
},
"required": [
"version"
],
"title": "VersionOutput",
"type": "object"
}
},
{
"description": "Identify the machine and user behind a Tailscale IP. Keys and endpoints are omitted.",
"metadata": {},
"name": "tailscale::whois",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"ip": {
"description": "Tailscale IPv4 or IPv6 address, optionally with `:port`.",
"type": "string"
}
},
"required": [
"ip"
],
"title": "WhoisInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"addresses": {
"description": "Tailscale addresses of the node.",
"items": {
"type": "string"
},
"type": "array"
},
"node_id": {
"description": "Stable node id.",
"type": [
"string",
"null"
]
},
"node_name": {
"description": "MagicDNS name of the node.",
"type": [
"string",
"null"
]
},
"os": {
"description": "Operating system reported by the node.",
"type": [
"string",
"null"
]
},
"tags": {
"description": "ACL tags on the node.",
"items": {
"type": "string"
},
"type": "array"
},
"user_display_name": {
"description": "Display name of the user who owns the node.",
"type": [
"string",
"null"
]
},
"user_login": {
"description": "Login name of the user who owns the node.",
"type": [
"string",
"null"
]
}
},
"required": [
"addresses",
"tags"
],
"title": "WhoisOutput",
"type": "object"
}
}
],
"triggers": []
}