TSLinkTSLink Docs

Installation

Install TSLink on macOS, Linux and Windows, and verify release artifacts.

View as Markdown

Prerequisites

You need a Tailscale account with MagicDNS and HTTPS. Private receiving devices need Tailscale and policy permission. The app host uses TSLink's embedded Tailscale nodes and needs no separate Tailscale daemon. A stored API token or OAuth client is optional for the first private share. macOS hosts need macOS 13 Ventura or later: current releases are built with Go 1.27, which no longer supports macOS 12 Monterey or earlier (platform guide).

macOS (Homebrew)

bash
brew install --cask anydoor7/tap/tslink

The macOS binary is signed with a Developer ID certificate and notarized by Apple. The first run needs network access to look up its notarization ticket.

Linux

Homebrew on Linux uses the same command:

bash
brew install --cask anydoor7/tap/tslink

Alternatively, select a .deb, .rpm or tslink_0.1.1_linux_<arch>.tar.gz from the v0.1.1 release, for amd64 or arm64. Install the package with your system package manager, or extract the archive and place tslink in a directory on PATH.

Windows

Download tslink_0.1.1_windows_amd64.zip or tslink_0.1.1_windows_arm64.zip from the v0.1.1 release. Extract it, add the directory containing tslink.exe to your user PATH, and run:

powershell
tslink install

TSLink then starts when you sign in. The zip is not Authenticode-signed. Verify it through the signed checksums and attestations described below.

From source

Source builds need Git and Go 1.27.1+. Commands below use bash/zsh; the platform guide covers each shell.

bash
git clone https://github.com/anydoor7/tslink.git
cd tslink
go install .
export PATH="$PATH:$(go env GOPATH)/bin"

On PowerShell, add $(go env GOPATH)\bin to your user PATH in system settings.

Verify a release

Follow the release verification commands with version="v0.1.1" and the exact downloaded asset name. They require gh 2.49+ with gh attestation verify, cosign with verify-blob --bundle, and sha256sum or shasum.

Download the chosen artifact, checksums.txt and checksums.txt.sigstore.json. Check the artifact's SHA-256 against its entry in checksums.txt, verify that checksum file's Sigstore bundle, then verify the artifact's GitHub attestation. Verification pins these four values:

  • OIDC issuer: https://token.actions.githubusercontent.com
  • Workflow identity: https://github.com/anydoor7/tslink/.github/workflows/release.yml@refs/tags/v0.1.1
  • Source ref: refs/tags/v0.1.1
  • Signer workflow: github.com/anydoor7/tslink/.github/workflows/release.yml

Archive SBOM sidecars have their own checksums, bundles and attestations; verify them separately using the same guide.

Verify installation

bash
tslink --version
tslink --help

The first command prints the installed version; the second lists commands.

Upgrade

For Homebrew, upgrade the cask:

bash
brew upgrade --cask tslink

If TSLink runs as a background service:

bash
tslink install

This updates the service's executable path to the upgraded binary. For an archive, Windows zip or Linux package, replace or upgrade the binary first, then run tslink install again if you use the background service. Check tslink --version and tslink status --json afterwards.

Authentication

TSLink has two credential tiers. Tier 1 is the default and needs no stored API credential; enrollment and approval still follow tailnet policy.

Tier 1 — interactive enrollment (default)

Start a share without the stored-credential tslink login command; first-node browser login remains part of enrollment.

bash
tslink share ./build

The first time a node needs to join your tailnet, TSLink prints one Tailscale authorization URL and exits. Open it, approve the node, then run tslink url <name> --wait for the live URL. In --json mode the same information comes back as one structured record, so a script or an agent reads a field rather than parsing prose:

json
{"type":"tslink.result","ok":true,"schema_version":1,"command":"share","code":0,"data":{"status":"needs_login","auth_url":"https://login.tailscale.com/a/..."}}

Nodes enrolled this way are user-owned and untagged. Enrollment, approval, access, and node-key expiry follow your tailnet policy; re-authorization may be required when that policy expires the key. See Quick Start for the handoff and readiness sequence.

Tier 2 — stored credential (optional)

Stored credentials support tagged node authentication. Tag ownership and policy permissions still apply; ordinary ACL automation needs explicit --manage-acl. Remote stale-device cleanup requires exact ownership proof and device permissions. A tagged identity's node-key expiry behavior is separate from API-token expiry. See Tag Configuration rather than treating credential storage alone as successful provisioning.

bash
tslink login

This presents a menu — choose [1] for an API access token or [2] for an OAuth client secret, with step-by-step guidance for each.

A regular tskey-api-* API access token grants full Tailscale API permission; trust credentials, including OAuth clients, provide scoped access. Verified October 6, 2026 against the Tailscale API documentation. Prefer Tier 1 unless you need what Tier 2 provides.

Which key type to use?

Key TypePrefixExpiryHow It WorksBest For
API access tokentskey-api-*Expires periodicallyTSLink derives short-lived, single-use auth keys; node ephemerality follows the service's --ephemeral flagRequired REST automation after validating permissions
OAuth client secrettskey-client-*Does not expireUsed directly by tsnet; REST tag/device automation is narrower todayLong-running setups after validating required operations

Generate API access tokens at Admin → Keys. Generate OAuth client secrets at Admin → OAuth — click "+ credential" → "OAuth client" → configure the scopes required by your intended API operations → copy the client secret (not the shorter client ID above it).

Credential storage

TSLink stores credentials in the system keychain when it is available, relying on the OS protection model:

PlatformBackend
macOSKeychain
LinuxSecret Service (GNOME Keyring / KWallet)
WindowsCredential Manager

Credentials prefer the system keychain (macOS Keychain, Linux Secret Service, Windows Credential Manager). Plaintext 0600 file fallback is allowed only on macOS/Linux after TSLink proves an old keychain value is absent or has been deleted. An unreachable or uncertain keychain fails closed; restore access and retry. Windows does not allow credential file fallback. Headless operation alone does not guarantee fallback.

FileContent
apikeyAPI access token
clientsecretOAuth client secret
authkeyLegacy auth key

Non-interactive setup

If you can't open a browser (e.g., headless servers), inject credentials from a secret manager into stdin or the environment:

bash
printf %s "$TSLINK_API_KEY" | tslink login --api-key-stdin
printf %s "$TSLINK_CLIENT_SECRET" | tslink login --client-secret-stdin

Environment variables are also accepted when they are supplied by your secret manager:

bash
TSLINK_API_KEY="$TSLINK_API_KEY" tslink login
TSLINK_CLIENT_SECRET="$TSLINK_CLIENT_SECRET" tslink login

Compatibility argv flags and legacy credential files may still be read by TSLink, but official automation should not place secrets in argv, shell history, or manually written credential files.

Autostart on Login

Default add/share handle background setup. To explicitly register or update login autostart, use:

bash
tslink install

Creates a LaunchAgent at ~/Library/LaunchAgents/com.tslink.daemon.plist with KeepAlive enabled. TSLink starts on login, not at the boot login window, and restarts after a crash or a manual stop while the agent remains installed.

Check tslink status --json and its data.supervision.autostart_scope for the observed login/boot scope; an unknown scope does not establish unattended boot availability. Enrollment/approval and service readiness are separate from autostart.

To remove the auto-start:

bash
tslink uninstall

Windows uninstall disables and stops its owned task/supervisor before deleting the task; Startup-only fallback leaves a current process for a separate tslink stop. macOS/Linux attempt managed shutdown, but errors or unverified-removal warnings require attention. To stop serving or perform maintenance, follow verified shutdown and inspect status before continuing.

Custom Control Server (Headscale)

Tailscale API-derived node auth keys are refused for a non-Tailscale control server with credential_control_url_mismatch. Custom-control enrollment and HTTPS support need separate validation; end-to-end Headscale validation remains pending.

If you're using Headscale or another custom control server instead of Tailscale's hosted service:

bash
# Set globally for all services
tslink config set control-url https://headscale.example.com

This setting persists in ~/.config/tslink/config.json and applies to all services. If the gateway is already running, follow the restart sequence to apply a changed global setting.

You can also override the control server for individual services:

bash
# Per-service override
tslink add my-service --proxy localhost:3000 --control-url https://headscale.example.com

Docker Integration

Docker label discovery is roadmap/experimental. Register container-backed services explicitly with tslink add.

Configuration Directory

By default, local configuration and runtime files live in ~/.config/tslink/; primary stored credentials live in the system keychain. TSLINK_CONFIG_DIR can select another local directory and must match the gateway/supervisor environment.

Code
~/.config/tslink/
  ├── registry.json       # Service registry
  ├── config.json          # Global config (control-url)
  ├── tslink.pid           # Daemon PID
  ├── apikey               # API key (file fallback)
  ├── clientsecret         # OAuth secret (file fallback)
  ├── authkey              # Legacy auth key
  ├── nodes/               # Per-service tsnet state
  └── logs/                # Daemon and access logs

Next Steps

With the TSLink binary available, follow Quick Start to register your first service, complete any enrollment handoff, and wait for readiness. A stored credential is optional.

Table of Contents