TSLinkTSLink 文档

配置

TSLink 配置文件、全局设置、当前字段和状态管理

查看 Markdown

全局配置

TSLink 将全局设置存储在 ~/.config/tslink/config.json 中。使用 tslink config 命令管理:

bash
# 设置值
tslink config set control-url https://headscale.example.com

# 获取值
tslink config get control-url

# 列出所有设置
tslink config list

# 清除值(恢复默认)
tslink config set control-url ""

可用设置

键描述默认值
control-url自定义 Tailscale 控制服务器 URL(如 Headscale)Tailscale 默认

TSLink 不会将 Tailscale API 派生的节点 auth key 发给非 Tailscale control server,会以 credential_control_url_mismatch 拒绝。选择 Headscale URL 不证明入网或 HTTPS 兼容,端到端 Headscale 验证仍待完成。

control-url 也可以在 registry.json 中按服务覆盖,或在明确选择手动运行时通过 tslink serve --control-url <url> 按会话覆盖。受管理守护进程应优先使用持久化配置,并遵循配置变更后重启;再启动一个 serve 不是重启,后台进程重启也可能不保留一次性标志。

远程 MCP 控制面配置键

可选的 mcp 块用于开启由 tslink serve --mcp 提供的 tailnet-only 远程 MCP 控制面。它需要手工编辑:tslink config set 管理受支持的 control-url/access-log keys;MCP bindings 需直接编辑。

键描述默认值
mcp.enabled不传 --mcp 也提供控制面;flag 与该键任一为真即开启false
mcp.allow允许调用该 endpoint 的登录邮箱和/或 tag: 条目。旧 owner 条目;启用需这些条目或有效明确 bindings无
mcp.allow_elevated_invitesOwner 显式允许 MCP 发送非 member role 的用户邀请或允许 exit-node use 的设备邀请;否则以 mcp_elevated_invite_refused 拒绝false
mcp.node_name专用控制面 tsnet 节点的主机名tslink-mcp
mcp.events_keepalive/events 具名 SSE keepalive 间隔,Go duration,范围 5s 到 5m20s
json
{
  "mcp": {
    "enabled": true,
    "allow": ["you@example.com", "tag:ops"],
    "node_name": "tslink-mcp"
  }
}

mcp.allow 中的每个 principal 都会获得高权限服务控制;提权邀请还要求 owner 通过 mcp.allow_elevated_invites 显式允许。请把它当作高权限访问列表对待。边界、client 可达性以及 stdio 的 tslink mcp 替代方案见远程 MCP 控制面。

优先级顺序

设置按以下顺序解析(从高到低):

  1. 服务级 — registry.json 中服务条目的 control_url 字段
  2. CLI 标志 — tslink serve --control-url
  3. 全局配置 — tslink config set control-url
  4. 默认值 — Tailscale 托管控制服务器

标签配置

默认零凭据(Tier 1)流程注册的是用户拥有的无标签节点。有存储凭据时可以使用配置的节点标签;远端 ACL 策略管理有独立的显式选择与权限要求。

默认标签

有存储凭据时,添加服务未指定 --tags 就会选择默认标签。默认值未修改时,以下是两种替代注册方式:

bash
# 有存储凭据、默认 tag:tsmain 时的替代写法,执行其中一个
tslink add webapp --proxy localhost:3000
tslink add webapp --proxy localhost:3000 --tags tag:tsmain

默认标签为 tag:tsmain。有存储凭据时可应用默认标签;即使 registry 存储了标签,零凭据节点也保持用户拥有、无标签。修改 Tier 1 标签会保留已有用户注册状态。普通 tag-owner ensure 仅在 login / serve 显式传入 --manage-acl 时开启。API token 或 OAuth client secret 的可用操作取决于相应 scopes;否则手工管理远端 tags。

更改默认标签

使用 tslink tags set-default 更改默认标签。该值存储在 ~/.config/tslink/config.json 的 GlobalConfig.DefaultTag 中。

bash
# 设置自定义默认标签
tslink tags set-default tag:myteam

# 验证
tslink tags list

ACL 变更(默认关闭,--manage-acl)#

普通 tag-owner ensure 默认关闭;tslink login --manage-acl 仅确保配置的默认标签;tslink serve --manage-acl 确保有效 registry 服务实际使用的普通标签,只有服务使用默认标签时才包含该默认标签。空 registry 或仅使用自定义标签的服务不会隐含追加默认标签。凭据必须拥有所需 policy scopes。更新使用 ETag,不在冲突时盲目重试。

显式公开 Funnel 是另一条流程。 对已通过 --funnel --public 确认的 proxy,TSLink 默认可以自动配置共享 tagOwners / nodeAttrs Funnel grant;这不要求额外传 --manage-acl,但仍须合适的凭据和策略权限。服务的 --no-auto-provision / no_auto_provision 关闭该服务自动配置;tslink serve --no-auto-provision 关闭该进程全部服务的自动配置。要让安装的后台服务保留该选择,使用 tslink install --no-auto-provision。

tslink cleanup --manage-acl 只报告本机是否仍使用共享 Funnel grant,永不删除共享 grant,也不据本机 registry 推断其它机器的使用情况。

tslink tags 命令组提供完整的标签生命周期管理:

bash
# 列出服务及其配置的标签(Tier 1 不会广播这些标签)
tslink tags list

# 从 Tailscale API 打印标签
tslink tags pull

# 为特定服务添加标签
tslink tags add webapp tag:staging

# 用一个标签替换特定服务的标签
tslink tags set webapp tag:web

# 更改默认标签
tslink tags set-default tag:myteam

# 通过本地安全检查后全局移除 ACL 标签所有者规则
tslink tags delete-remote tag:deprecated --force --manage-acl

注册表文件

TSLink 将所有服务定义存储在:

代码
~/.config/tslink/registry.json

这个文件是已注册服务的唯一真实来源。使用 tslink add 和 tslink remove 管理,或者手动编辑以进行高级配置。

完整注册表格式

只有服务的普通写入保留 schema version 1。启用人员授权的 registry 使用 version 2,包含顶层 people 和逐服务 people_scoped。旧 binary 会拒绝不支持的字段,不能静默丢弃授权;只有明确决定放弃人员授权时,才停止新 daemon 并恢复单独备份的 version 1 registry。以下仅含服务的示例仍有效。

json
{
  "schema_version": 1,
  "services": [
    {
      "name": "webapp",
      "type": "proxy",
      "target": "http://localhost:3000",
      "path": "",
      "port": 0,
      "ephemeral": false,
      "tags": ["tag:web"],
      "allowed_users": ["user@example.com"],
      "funnel": false,
      "public_ack": false,
      "control_url": "",
      "created_at": "2026-03-01T00:00:00Z"
    },
    {
      "name": "shared-files",
      "type": "file",
      "path": "/Users/you/Documents/shared",
      "created_at": "2026-03-01T00:01:00Z"
    },
    {
      "name": "mydb",
      "type": "tcp",
      "target": "localhost:5432",
      "port": 5432,
      "created_at": "2026-03-01T00:02:00Z"
    }
  ]
}

服务字段

字段类型描述
namestring服务主机名(小写字母、连字符、字母数字)
typestringproxy、file 或 tcp
targetstring代理/TCP 目标(如 http://localhost:3000)
pathstring文件服务的绝对路径
portintTCP 端口号
ephemeralbool请求临时节点;控制面在不活跃后清理,而非断开即移除;本地注册保留至主动移除
tagsstring[]有存储凭据时配置的 Tailscale 节点标签;Tier 1 保持无标签
allowed_usersstring[]代理/文件 HTTP 允许身份(邮箱或 tag:xxx);TCP 拒绝非空值
funnelbool启用 Tailscale Funnel(仅代理,公共暴露)
public_ackboolfunnel 为 true 时必需的公共暴露确认
funnel_expires_atstringFunnel 必填:RFC3339 截止时间;保留旧持久 never,但拒绝新的公开 never;缺失时以 funnel_expiry_required 拒绝
no_auto_provisionbool禁用该服务的 Funnel policy 自动配置
filestring文件服务 path 内可选的单个文件名
control_urlstring服务级控制服务器覆盖
created_atstringISO 8601 创建时间戳
people_scopedbool私有 HTTP/文件应用需要人员授权或明确的旧 allow 规则;移除授权后标记保留
healthobject后端路径/状态/正文断言、超时和间隔,见健康检查
request_limitsobject上传大小、header/body-read/idle 窗口,不是请求限流
preserve_hostboolProxy 转发 canonical 外部 Host,Origin 保持不变

Roadmap / Experimental 配置

middleware、domain、acme_email registry 键已移除,旧键即使为空也会以 unknown_config_key 拒绝。严格的修改命令拒绝这些条目;daemon 跳过无效服务条目并继续运行健康服务。热重载使公开 Funnel 条目无效时会关闭其公开 listener。Docker discovery 和 Prometheus instrumentation 尚未实现。详情请参阅实验性与路线图。

凭证存储

默认 Tier 1 通过浏览器登录,无需存储 API 凭据。有存储凭据的运行模式支持以下两种类型:

凭证前缀行为
API 访问令牌tskey-api-*会定期过期。当前最完整支持 Tailscale REST 标签/设备操作和认证材料派生。
OAuth 客户端密钥tskey-client-*不会周期性过期。由 tsnet 直接用于认证,但当前 REST 标签/设备自动化路径更窄。无人值守前请验证。

存储优先级

凭证按以下顺序存储和解析:

  1. 系统钥匙串(首选) — macOS Keychain、Linux secret service、Windows Credential Manager。钥匙串服务名为 "tslink"。
  2. 有条件的文件回退 — ~/.config/tslink/apikey 或 ~/.config/tslink/clientsecret,权限 0600。仅 macOS/Linux 在证明旧钥匙串值不存在或已删除后允许;不可达或不确定时拒绝,Windows 禁用。

旧版支持

为了向后兼容,TSLink 还会检查 ~/.config/tslink/authkey。此文件仅在不存在 API 密钥或 OAuth 客户端密钥时使用。不推荐用于新安装。

凭证迁移

如果存在文件存储的 API 访问令牌且系统钥匙串可用,tslink serve 会将该 API token 迁移到钥匙串,并在钥匙串写入成功后删除文件。OAuth client-secret 回退文件不会由 serve 自动迁移;如需走正常的钥匙串优先路径,请把 secret 通过 stdin 传给 tslink login --client-secret-stdin。

认证密钥派生

使用 API 访问令牌(tskey-api-*)时,TSLink 会在每个服务启动时派生新的认证材料。该请求按该服务配置的标签、临时节点设置和服务级描述限定范围。认证密钥不会持久化到磁盘。

热重载

TSLink 使用 fsnotify 监控注册表文件的变化。当文件被修改时:

  1. 监控器检测到文件系统事件。
  2. 获取文件锁(mutex)以防止并发写入导致的竞态条件。
  3. 加载并验证新的注册表。
  4. 将新状态与运行状态进行差异比较。
  5. 新增的服务被启动;移除的服务被停止。
  6. 现有未更改的服务继续运行,不受影响。

需要节点重启

以下字段的更改会通过热重载重新创建受影响的服务 runtime,短暂中断该服务:

  • 服务 type(proxy、file、tcp)
  • 服务 target、path 或选定的 file
  • 服务 port
  • 服务 tags、allowed_users、ephemeral、funnel、public_ack 或 no_auto_provision
  • 实际生效的 control_url

Runtime 重建与注册状态重置不同。修改标签保留 Tier 1 注册;有存储凭据时实际节点标签变化、临时节点设置变化或实际控制服务器变化可能重置节点身份。daemon 跳过无效服务条目,其他健康条目继续运行;热重载使公开 Funnel 条目无效时会关闭其 listener,不会保留公开暴露。

状态目录

TSLink 将运行时状态存储在 ~/.config/tslink/:

路径用途
config.json全局设置(控制服务器 URL 等)
registry.json服务定义
tslink.pid守护进程 ID 跟踪
apikeyAPI 密钥文件(macOS/Linux 有条件回退)
clientsecretOAuth 客户端密钥文件(macOS/Linux 有条件回退)
authkey旧版认证密钥(向后兼容)
nodes/每个服务的 tsnet 状态(WireGuard 密钥、节点状态)
logs/守护进程和访问日志

状态目录在首次使用时自动创建。nodes/ 目录由嵌入的 tsnet 库管理。Roadmap/experimental 自定义域名 ACME 工作不属于已交付的状态目录契约。

重置状态

重置状态前先移除受管理的自动启动。macOS 上仅停止 LaunchAgent 会被 KeepAlive 重新启动;uninstall 失败时必须终止重置,包括无法检查 launchd 域的情况,不要用 --force 绕过该证明。停止任何剩余的手动网关,确认进程已停止且没有自动启动/重启注册后,才清除凭据和状态。

以下 Bash 示例重置默认 macOS/Linux 目录,用 Python 3 验证状态 JSON。它在子 shell 中运行,任何命令失败、状态字段缺失/格式错误、网关仍运行或监督仍有效时都会终止。自定义配置目录须使用匹配的服务注册与状态路径;此示例拒绝不同的 TSLINK_CONFIG_DIR。重置期间不要启动另一网关。

bash
(
  set -euo pipefail
  [ -z "${TSLINK_CONFIG_DIR:-}" ] || [ "$TSLINK_CONFIG_DIR" = "$HOME/.config/tslink" ]

  # 1. 移除受管理的启动注册,再停止任何剩余的手动网关
  tslink uninstall
  tslink stop

  # 2. 必须确认网关停止、监督无效后才能继续
  tslink status --json | python3 -c '
import json, sys
result = json.load(sys.stdin)
data = result.get("data", {})
supervision = data.get("supervision", {})
if not (result.get("ok") is True and data.get("daemon_running") is False
        and all(supervision.get(key) is False
                for key in ("installed", "autostart", "restart_on_exit"))):
    sys.exit("Reset halted: gateway or supervision is active or unverified")
'

  # 3. 清除凭据,再移除本地注册表、节点状态和日志
  tslink logout
  rm -rf -- "$HOME/.config/tslink"
)

Windows 上也必须先完成 uninstall → stop → status --json 的前提,才能登出或删除本地状态;stop 使用进程终止而非正常关闭。以上 Bash/Python 示例面向 macOS/Linux。

成功重置后,重新分享并批准节点;存储凭据的 tslink login 仍是可选项。验证并清理远程设备。 本地重置不会自动删除 tailnet 中的远程节点。打开 Tailscale 管理控制台,检查并手动删除任何遗留的 TSLink 设备。

tslink logout 会清除凭据但保留目录;最后的删除会额外移除注册表和节点状态。仅执行 rm -rf 不能清除钥匙串凭据,也不能证明远程已清理。

访问管理设置

mcp.bindings 增加 viewer/app-operator/people-manager/owner principal,明确 apps 或 viewer inventory,operator/manager 正的 max_duration,以及可选的固定 binding 期限。旧 mcp.allow 保留 owner 权限,重复 principal fail closed。修改 MCP 配置后重启,见 MCP scopes。

用 tslink portal enable --owner you@example.com 设置独立私有 portal;可选 admins 能打开所有私有 HTTP/文件应用,请用 status 的实际 URL。服务 requestable 默认 false,明确披露私有应用名供请求;见 portal 与请求。人员/访客/请求/portal 共用原子 registry,需兼容 TSLink reader,降级前保留备份。

durations.public_max 设置 guest/公网上限(默认 7d,至少 1h 的相对值)。新人员/Funnel 默认 24h,改策略不重写已有截止时间,见期限例外。

access_log 管理 enabled/path_mode/retention_days/max_bytes/queue_size;服务 access_log_path_mode 覆盖继承路径模式,全局 off 是硬退出。支持 tslink config set access-log-path-mode prefix 等 access-log keys,默认与缺口见访问历史。全局变更需重启,应用路径设置热重载。

目录