---
title: "FAQ"
description: "Frequently asked questions about TSLink"
url: "https://tslink.md/docs/faq"
locale: "en"
product_version: "0.1.1"
source: "https://github.com/anydoor7/tslink/blob/v0.1.1/README.md"
---

> Documentation index: https://tslink.md/llms.txt · Installed binary is authoritative: `tslink manifest`.

## General

### Why not just use `tailscale serve` or Tailscale Services?

[Tailscale Serve](https://tailscale.com/docs/features/tailscale-serve) publishes endpoints through the host's Tailscale client. [Tailscale Services](https://tailscale.com/docs/features/tailscale-services) provides named services with separate MagicDNS names. Its setup requires the documented administrative role and a tagged host; host approval can be automatic when the tailnet has a matching auto-approval policy.

TSLink adds a local multi-app registry, private HTTP/file people grants with deadlines, invitation bundles, recipes, health checks, and CLI/MCP lifecycle operations. Each service uses an embedded [tsnet](https://tailscale.com/docs/features/tsnet) node, so the TSLink host does not need a system Tailscale daemon.

Default `tslink add myapp --proxy localhost:3000 --json` ensures the gateway is running. Without stored credentials, its node enrolls as a user-owned, untagged node. First enrollment can return `needs_login` and `auth_url`: hand that URL to the human to complete browser login and any approval required by tailnet policy. Then use `tslink url myapp --wait --json` and use the exact address it returns. See [Quick Start](https://tslink.md/docs/quickstart.md) for this handoff; registration alone does not prove readiness.

### Is TSLink free to use?

TSLink is licensed under Apache-2.0 and is free for commercial use. Install with Homebrew on macOS or Linux, release archives, Linux packages or a Windows zip. The macOS binary is signed and notarized; the Windows zip is not Authenticode-signed. See [Installation](https://tslink.md/docs/installation.md) for verification and source builds. Tailscale account terms apply separately.

### What platforms does TSLink support?

TSLink is written in Go and supports **macOS**, **Linux**, and **Windows**. Platform-specific autostart is available on all three: LaunchAgent (macOS), systemd user service (Linux), and Task Scheduler with a built-in supervisor (Windows); `--startup` selects a fallback without crash recovery.

### Does TSLink require the Tailscale app to be installed?

**On the machine running TSLink:** No. TSLink embeds its own Tailscale node (via tsnet), so it operates independently of the system Tailscale daemon.

**On devices accessing your services:** Yes for private tailnet access. Those devices need Tailscale and network permission: either membership in your tailnet or an accepted app-device share for an outside account. The exception is proxy services exposed via Funnel (`--funnel --public`), which are intentionally reachable from the public internet and are not covered by TSLink identity enforcement.

### What are ephemeral nodes?

The `--ephemeral` flag requests an ephemeral tsnet node for a temporary service. Tailscale's control plane removes [ephemeral nodes after a period of inactivity](https://tailscale.com/docs/features/ephemeral-nodes); disconnecting does not prove immediate remote removal. The local service registration remains until you remove it with `tslink remove`.

```bash
tslink add temp-service --proxy localhost:3000 --ephemeral
```

## Authentication

### What's the difference between API access tokens and OAuth client secrets?

|                    | API Access Token                                                                                 | OAuth Client Secret                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| **Prefix**         | `tskey-api-*`                                                                                    | `tskey-client-*`                                                                        |
| **Expiration**     | Expires periodically                                                                             | Never expires                                                                           |
| **How auth works** | Current most complete path for Tailscale REST tag/device automation and auth material derivation | Used directly by tsnet for authentication; REST tag/device automation is narrower today |
| **Best for**       | Automation and tag/device management                                                             | Long-running setups after validating required operations                                |

Both are entered during `tslink login`. Either one can authenticate services, but do not treat OAuth client secrets as universally recommended for full automation until your required tag/device operations are validated.

### Where are my credentials stored?

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.

Auth keys used internally by tsnet are not stored on disk. In API-token mode, TSLink derives fresh auth material as each service starts, scoped to that service's tags, ephemeral setting, and service-specific description.

### Can I use TSLink with Headscale?

TSLink accepts a custom control URL, but Headscale end-to-end enrollment and HTTPS validation remain pending. Use it without stored Tailscale credentials, or with a user-supplied auth key issued by the selected server. TSLink refuses auth material derived from stored Tailscale credentials for another control server with `credential_control_url_mismatch`. See [Configuration: Available Settings](https://tslink.md/docs/configuration.md#available-settings) before changing the URL.

Set the custom control URL globally:

```bash
tslink config set control-url https://headscale.example.com
```

You can also set it per-service in `registry.json`. A deliberately manual gateway can use `tslink serve --control-url <url>` for one session. For a running managed gateway, follow [Restarting After Configuration Changes](https://tslink.md/docs/daemon.md#restarting-after-configuration-changes) rather than starting a second `serve` process.

### What config settings does `tslink config` support?

Currently `tslink config` supports `control-url` for pointing TSLink at a custom coordination server (e.g., Headscale). Use `tslink config set`, `tslink config get`, and `tslink config list` to manage global settings. Global config is stored in `~/.config/tslink/config.json`.

## Security

### Is my traffic encrypted?

Partly. The tailnet leg — traffic between devices on your tailnet and the TSLink node — is WireGuard-encrypted, so it stays protected even if the underlying network is compromised. TSLink also provisions HTTPS certificates for the tailnet listener of HTTP proxy and file services. Two boundaries to be aware of: the short backend hop from the TSLink node to your local service is whatever you configured (often plain HTTP or plain TCP, and may be plaintext), and raw TCP services have no TSLink TLS termination. So the tailnet transport is encrypted, but the path is not encrypted end-to-end across the whole chain.

### Can people outside my Tailscale network access my services?

By default, services listen on the private tailnet and are subject to its access policy.

The exception is **Tailscale Funnel** (`--funnel --public`). When enabled on a proxy service, it makes that service accessible from the public internet. Only enable Funnel when you intentionally want public access; public Funnel traffic is not covered by TSLink identity enforcement.

### Can I restrict access to specific people?

Yes. For proxy/file HTTP services, use `--allow` to limit access to specific Tailscale identities:

```bash
tslink add internal --proxy localhost:9090 --allow user@example.com,tag:admin
```

This works in addition to standard Tailscale ACLs.

### What are ACL tags and how do I use them?

ACL tags (e.g., `tag:admin`) identify tagged Tailscale devices. Proxy/file HTTP `--allow` can match a caller's device tags. Service `--tags` configures the TSLink node's tags in credential-backed mode; default zero-credential (Tier 1) nodes remain user-owned and untagged, even if the registry contains tags.

Ordinary remote tag-owner provisioning requires explicit `--manage-acl` on `login` or `serve` and credentials with the required policy permissions. API-token mode currently supports the broadest REST tag/device automation; client-secret-only operations are narrower. Explicitly acknowledged public Funnel has a separate provisioning flow. See [Tag Configuration](https://tslink.md/docs/configuration.md#tag-configuration).

### Do I need to configure tags before using TSLink?

Default zero-credential enrollment does not require tags. Credential-backed services use the configured tags, or the default `tag:tsmain` when `--tags` is omitted. Setting a local tag does not create remote policy: configure tag ownership yourself, or explicitly opt into ordinary `--manage-acl` provisioning with sufficient permissions. Editing tags on a Tier 1 service retains its existing user enrollment.

To customize tags, use the `tslink tags` command group:

```bash
# See current tags
tslink tags list

# Change the default tag for future credential-backed services
tslink tags set-default tag:myteam

# Add custom tags to a specific service
tslink add api --proxy localhost:8080 --tags tag:api,tag:prod
```

## Technical boundaries

### Can an agent use TSLink?

Yes. CLI `--json` provides a versioned envelope, and owner sessions expose 44 MCP tools for app/access management; reduced roles see fewer tools. `tslink mcp` reserves stdout for protocol frames and rejects `--json`. See the [MCP reference](https://tslink.md/docs/mcp-server.md) for transport, parameter, cancellation, and log-redaction boundaries.

### Can I share an MCP or local LLM server?

Register an existing HTTP endpoint with `tslink add llm --proxy localhost:11434 --allow you@example.com`. Receiving clients must be able to reach the tailnet address. Keep application authorization where the application needs it; TSLink does not convert stdio to HTTP or replace MCP OAuth. Raw TCP has no HTTP identity headers or TSLink `--allow` check.

### What does the standards mapping cover?

TSLink is not certified against a security standard. The [Standards Alignment](https://tslink.md/docs/standards-alignment.md) page is an educational, partial mapping to NIST SP 800-207 concepts. Separate nodes give services network identities, not process or host isolation. WireGuard protects the tailnet leg; the backend hop may be plaintext. HTTP identity resolution is best-effort, cached for 60 seconds, and enforced by TSLink only when `--allow` is configured.

## Services

### How many services can I run?

There is no hard limit in TSLink itself. Each service creates a hostname on your tailnet. Practical limits depend on your Tailscale plan and system resources.

### What service types are supported?

| Type      | Flag      | Use Case                               |
| --------- | --------- | -------------------------------------- |
| **Proxy** | `--proxy` | Web apps, APIs, any HTTP service       |
| **File**  | `--dir`   | Serve a directory over HTTPS           |
| **TCP**   | `--tcp`   | Databases, Redis, any raw TCP protocol |

### How do TCP services work?

TCP services forward raw TCP connections byte-for-byte. This is useful for exposing databases (PostgreSQL, MySQL), Redis, message brokers, or any TCP-based protocol to your tailnet. Unlike proxy services, TCP services do not perform HTTP processing, HTTP `--allow`, middleware, TLS termination, or header injection.

```bash
tslink add mydb --tcp localhost:5432
```

After enrollment and readiness, obtain the actual address with `tslink url mydb --wait`. Use its hostname and recorded TCP port from a device permitted by tailnet policy. Keep the database's own authentication and any required application TLS:

```bash
psql -h <hostname-returned-by-tslink-url> -p 5432
```

### Can I expose services on remote machines?

TSLink proxies to a `host:port`, so the target service must be reachable from the machine running TSLink. If you can reach it via `curl http://host:port`, TSLink can proxy it.

### Can I expose a service on a non-standard port?

TSLink proxy and file services are accessed over HTTPS on port 443. TCP services created by the CLI are accessed on the port recorded from `--tcp host:port`; if a manually edited registry omits `port`, runtime falls back to 443.

### Do I need to restart the gateway when adding services?

No. TSLink supports hot-reload. When you run `tslink add` or `tslink remove`, the gateway detects changes automatically and updates without restarting.

### What changes are hot-reloaded vs. require a node restart?

Registry changes to a service's type, target/path, port, tags, HTTP access list, ephemeral setting, Funnel settings, or effective control URL restart the affected runtime through hot reload. A Tier 1 tag edit retains user enrollment; effective credential-backed tag changes can reset node identity. Credential mode swaps and legacy `authkey` file changes require a gateway process restart; follow [daemon management](https://tslink.md/docs/daemon.md#restarting-after-configuration-changes) for your platform. Configurable middleware is roadmap/experimental; the removed `middleware` registry key is rejected even when empty.

### What are identity headers?

For proxy services, TSLink injects Tailscale identity headers when Tailscale WhoIs resolves the caller for a request forwarded to your local service:

* `X-Tailscale-User-Login` — the authenticated user's login name
* `X-Tailscale-User-Name` — the user's display name
* `X-Tailscale-User-Picture` — profile picture URL, when available
* `X-Tailscale-Node` — requesting node's computed name, when available

TSLink strips incoming `X-Tailscale-*` headers before injecting WhoIs-derived values. Resolution is best-effort: without `--allow`, a failed lookup can forward a request with no identity headers; with `--allow`, missing identity is denied before the backend.

Trust these headers only across a controlled TSLink-to-backend path that prevents callers from bypassing the proxy and forging them. If your application requires an identified user, reject missing identity and retain its required authentication and authorization. The headers alone do not authenticate every request.

### Are identity headers available for file and TCP services?

No. Identity headers are only injected for proxy services, since they rely on HTTP request processing. File services serve static files directly, and TCP services forward raw bytes without HTTP awareness.

## Funnel

### What is Tailscale Funnel?

Tailscale Funnel allows you to expose a service publicly on the internet, without requiring the accessing device to be on your tailnet. The service remains available at the same `https://<service-name>.<tailnet-name>.ts.net` URL.

### Which service types support Funnel?

Only **proxy** services support Funnel (`--funnel --public`). File services and TCP services do not support Funnel.

```bash
tslink add myapp --proxy localhost:3000 --funnel --public
```

### Is Funnel safe to use?

Funnel exposes your service to the public internet. Only enable it when you intentionally want public access. Do not rely on the roadmap/experimental middleware package for Funnel protection in the launch candidate. Note that identity headers (`X-Tailscale-User-*`) are not available for public Funnel requests.

For questions about middleware, Docker auto-discovery, and other experimental features, see [Experimental & Roadmap](https://tslink.md/docs/experimental-roadmap.md).

## Monitoring

### Does TSLink expose Prometheus metrics?

Prometheus `/metrics` is [roadmap/experimental](https://tslink.md/docs/experimental-roadmap.md#prometheus-metrics). See the Experimental & Roadmap page for details on available metrics.

### Where are access logs stored?

Use `tslink access log --app photos --since 24h` for retained local HTTP/file/TCP/guest events and authority-change receipts. Daemon JSONL history is in `~/.config/tslink/access-log/`; the mutation journal is `mcp-audit.json`. `tslink logs` reads daemon diagnostics under `logs/`. See [access history](https://tslink.md/docs/access-history.md) for path privacy, independent bounds and gaps.

### What log format does TSLink use?

History uses typed schema-version-1 events: time, kind, app/service, decision, optional WhoIs-attested identity, and HTTP/TCP metadata or typed guest/MCP/lifecycle details. It stores no headers, cookies, bodies or secrets. Default path mode records a sanitized prefix. Events and intent/completion receipts are not unique visits or proof of successful completion. Missing identity, dropped events and crash gaps remain possible; `status` and `doctor` report current history health. There is no complete-audit or compliance guarantee. Prometheus, flow analysis and cluster telemetry remain planned.

### Can someone visit without Tailscale?

[Guest links](https://tslink.md/docs/guest-links.md) support one HTTP proxy app through explicitly public Funnel with a mandatory gate, optional PIN and finite expiry. Link/PIN is forwardable and does not verify a person. File/raw TCP are unsupported. Open Funnel is a separate public publication; keep the app's own authentication.

### Is there a home page for my apps?

The [private portal](https://tslink.md/docs/portal-requests.md) lists permitted apps on one host and offers opt-in requests for private HTTP/file apps. Visitors still need the right Tailscale login, network policy and node shares. QR onboarding does not install apps or grant access automatically. Multi-host inventory and an admin management dashboard/REST API remain planned.

## Networking

### Does TSLink need port forwarding?

You normally do not need an inbound router port-forwarding rule. The TSLink host still needs working Tailscale connectivity, and receiving devices need a reachable tailnet path and permission under its access policy.

### What happens if my machine goes to sleep?

The gateway cannot serve while its host sleeps. After wake, availability depends on the gateway process, network connectivity, and node authentication still being ready; check `tslink status --json` and `tslink url <name> --wait`. For persistent availability, use an awake host or an always-on server.

### Can I use TSLink with Tailscale ACLs?

Yes. Tailscale Access Control Lists (ACLs) apply to TSLink services just like any other device on your tailnet. You can restrict which users or devices can access specific services.

For questions about custom domains and ACME certificates, see [Experimental & Roadmap](https://tslink.md/docs/experimental-roadmap.md#custom-domains--acme).

## Automation

### Can I manage services programmatically?

Yes. You have two shipped options, plus one roadmap item:

**1. `--json` on published manifest commands** — every command in the published manifest except the stdio `tslink mcp` server accepts `--json` and returns one versioned envelope. Cobra's `help` and `completion` commands are not in the manifest and print plain text:

```bash
tslink list --json
tslink add myapp --proxy localhost:3000 --json
tslink remove myapp --json
tslink status --json
```

**2. MCP** — `tslink mcp` serves the same operations as MCP tools over stdio for a client on this machine, and `tslink serve --mcp` serves them over HTTPS on a dedicated tailnet-only node for clients on other tailnet machines. See [TSLink as an MCP Server](https://tslink.md/docs/mcp-server.md).

**3. Admin REST API** — roadmap/experimental; not launched by the current runtime.

Use the CLI with `--json` for local scripting and CI/CD pipelines, MCP for agents, and treat REST management as roadmap/experimental.

## Configuration

### Where does TSLink store its data?

By default, TSLink stores local configuration and runtime files under `~/.config/tslink/` (keychain credentials remain in the system keychain):

| Path            | Description                                |
| --------------- | ------------------------------------------ |
| `registry.json` | Service registry (all registered services) |
| `config.json`   | Global configuration (control URL, etc.)   |
| `tslink.pid`    | Daemon PID file                            |
| `apikey`        | API access token (file fallback)           |
| `clientsecret`  | OAuth client secret (file fallback)        |
| `authkey`       | Legacy auth key (backward compatibility)   |
| `nodes/`        | Per-service tsnet node state               |
| `logs/`         | Daemon and access logs                     |

### Can I change the config directory?

Set `TSLINK_CONFIG_DIR` to select another directory. CLI and gateway must use the same value; an installed supervisor also needs the matching environment. Follow [daemon management](https://tslink.md/docs/daemon.md#restarting-after-configuration-changes) when changing an existing setup, and do not operate on one directory while another gateway serves from a different one.

## Troubleshooting

### My service was working but suddenly stopped

Check if the local service (the `host:port` target) is still running. TSLink proxies traffic but doesn't manage the lifecycle of your local services.

### I see "address already in use" errors

Another gateway or process may be using the same resources. Inspect `tslink status --json`, including `data.daemon_running` and `data.supervision`, before changing anything. A macOS managed gateway can restart after `stop`; manual and managed gateways need different handling. Follow [verified shutdown](https://tslink.md/docs/daemon.md#verified-shutdown) or the applicable [restart procedure](https://tslink.md/docs/daemon.md#restarting-after-configuration-changes), and identify the actual conflicting process before retrying.

For more detailed troubleshooting, see the [Troubleshooting](https://tslink.md/docs/troubleshooting.md) guide.
