Installation
Install TSLink on macOS, Linux and Windows, and verify release artifacts.
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)
brew install --cask anydoor7/tap/tslinkThe 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:
brew install --cask anydoor7/tap/tslinkAlternatively, 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:
tslink installTSLink 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.
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
tslink --version
tslink --helpThe first command prints the installed version; the second lists commands.
Upgrade
For Homebrew, upgrade the cask:
brew upgrade --cask tslinkIf TSLink runs as a background service:
tslink installThis 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.
tslink share ./buildThe 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:
{"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.
tslink loginThis 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 Type | Prefix | Expiry | How It Works | Best For |
|---|---|---|---|---|
| API access token | tskey-api-* | Expires periodically | TSLink derives short-lived, single-use auth keys; node ephemerality follows the service's --ephemeral flag | Required REST automation after validating permissions |
| OAuth client secret | tskey-client-* | Does not expire | Used directly by tsnet; REST tag/device automation is narrower today | Long-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:
| Platform | Backend |
|---|---|
| macOS | Keychain |
| Linux | Secret Service (GNOME Keyring / KWallet) |
| Windows | Credential 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.
| File | Content |
|---|---|
apikey | API access token |
clientsecret | OAuth client secret |
authkey | Legacy 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:
printf %s "$TSLINK_API_KEY" | tslink login --api-key-stdin
printf %s "$TSLINK_CLIENT_SECRET" | tslink login --client-secret-stdinEnvironment variables are also accepted when they are supplied by your secret manager:
TSLINK_API_KEY="$TSLINK_API_KEY" tslink login
TSLINK_CLIENT_SECRET="$TSLINK_CLIENT_SECRET" tslink loginCompatibility 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:
tslink installCreates 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:
tslink uninstallWindows 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:
# Set globally for all services
tslink config set control-url https://headscale.example.comThis 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:
# Per-service override
tslink add my-service --proxy localhost:3000 --control-url https://headscale.example.comDocker 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.
~/.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 logsNext 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.