---
title: "管理服务"
description: "如何添加、移除和管理代理、文件和 TCP 服务"
url: "https://tslink.md/zh/docs/services"
locale: "zh"
product_version: "0.1.1"
source: "https://github.com/anydoor7/tslink/blob/v0.1.1/docs/getting-started.md"
---

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

## 概述

TSLink 中的"服务"是一个命名条目，将 Tailscale 网络上的主机名映射到本地目标。TSLink 支持三种服务类型：

| 类型      | 标志        | 用途                   |
| ------- | --------- | -------------------- |
| **代理**  | `--proxy` | 反向代理到 Web 服务器        |
| **文件**  | `--dir`   | 通过 HTTPS 提供目录服务      |
| **TCP** | `--tcp`   | 原始 TCP 转发（数据库、自定义协议） |

每个服务使用独立 tsnet 节点，拥有自己的 tailnet 身份和主机名，可由 tailnet 策略按服务控制访问。代理和文件服务使用带 TLS 证书的 HTTPS，例如 `https://<名称>.<tailnet>.ts.net`；原始 TCP 使用主机名和端口，例如 `<名称>.<tailnet>.ts.net:5432`，没有 TSLink HTTP/TLS 监听器。请读取实际运行时端点，不要自行拼接主机名。

## 代理服务

使用 `--proxy` 通过反向代理暴露本地 Web 服务：

```bash
tslink add <名称> --proxy <host:port>
```

**示例：**

```bash
# 暴露 Next.js 开发服务器
tslink add frontend --proxy localhost:3000

# 暴露运行在自定义端口的 API
tslink add api --proxy 127.0.0.1:8080

# 简写形式 — 省略 host 表示 localhost
tslink add myapp --proxy :3000
```

代理身份传递是 best-effort：TSLink 先移除客户端提交的 `X-Tailscale-*` 头，只有 Tailscale WhoIs 解析出用户资料时才添加身份头。未配置 `--allow` 时，查询失败仍可能转发请求且不带身份头；配置 `--allow` 后，缺少身份或未获授权的请求会在到达后端前被拒绝。

只有在受控的 TSLink 到后端路径中、防止直接绕过代理时，才能信任身份头。应用若要求用户身份，就应拒绝缺失值，并保留所需认证与授权。文件服务不注入代理身份头。头字段、后端 `Host` 重写及转发头重建见[反向代理](https://tslink.md/zh/docs/architecture.md#%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86)。

**后端错误：** 非超时的上游失败返回 `502 Bad Gateway`，超时返回 `504 Gateway Timeout`。错误正文中的 “Service unavailable” 不表示 HTTP 状态为 503。

## 文件服务

使用 `--dir` 通过 HTTPS 共享目录：

```bash
tslink add docs --dir ~/Documents/shared
```

目录以只读方式通过内置文件浏览器提供服务，并启用目录列表。支持绝对路径和相对路径；相对路径在注册时解析。

目录在该服务主机名的根路径提供；用 `tslink url docs --wait` 获取实际地址。已配置的 `--allow` 和 HTTP 访问日志可以使用 WhoIs，但文件处理器不注入代理身份头。

## TCP 服务

使用 `--tcp` 暴露原始 TCP 连接（数据库、Redis、自定义协议）：

```bash
# 暴露 PostgreSQL 数据库
tslink add mydb --tcp localhost:5432

# 暴露 Redis
tslink add cache --tcp localhost:6379
```

TCP 服务执行双向字节转发，并正确处理 TCP 半关闭 — 任何基于 TCP 的协议都可以使用。CLI 会从 `--tcp host:port` 记录目标端口，tailnet listener 使用该端口。如果手工编辑 registry 且省略 `port`，runtime 会回退到 `443`。

TCP 服务不经过 HTTP middleware、身份头或 HTTP `--allow`。CLI 注册及 registry 验证均拒绝 TCP 非空 `allowed_users` / `--allow`。用 tailnet 策略和目标服务自身认证保护 TCP。

Tailnet 流量由 WireGuard 加密，但 TSLink 不为原始 TCP 添加应用 TLS。认证及需要的应用/后端 TLS，应在目标服务和客户端中配置。

**常见用途：**

* **数据库：** PostgreSQL、MySQL、MongoDB
* **缓存：** Redis、Memcached
* **SSH 隧道：** 通过 tailnet 转发 SSH 连接

注册并就绪后，从 tailnet 策略允许的设备访问 `tslink url <name> --wait` 返回的实际主机名和端口。以下客户端示例使用主机名占位值：

```bash
# PostgreSQL
psql -h <mydb-实际返回的主机名> -p 5432

# SSH
ssh -p 22 <已注册-SSH-服务返回的主机名>
```

## 高级标志

这些标志可以与任何服务类型组合使用（除非另有说明）：

### 临时节点

为临时服务请求临时节点：

```bash
tslink add devserver --proxy :8080 --ephemeral
```

Tailscale 控制面在不活跃后清理节点；短暂断连不证明设备已移除。本地服务注册保留至显式移除，见[临时节点行为](https://tslink.md/zh/docs/faq.md#%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%B4%E6%97%B6%E8%8A%82%E7%82%B9)。

### ACL 标签

有存储凭据时配置服务的节点标签，前提是已有标签所有权，或显式授权普通 ACL 配置：

```bash
tslink add api --proxy :8080 --tags tag:api,tag:prod
```

即使命令将标签存进 registry，默认无存储凭据（Tier 1）节点仍归用户所有且无标签。保存标签不会改变远端策略。API-token 模式按服务实际标签派生认证材料；client-secret 操作更窄。普通 tag-owner ensure 要求在 `login` / `serve` 上显式传 `--manage-acl`，并拥有足够策略权限。默认标签、Tier 1 保留注册状态及独立的已确认 Funnel 配置流程见[标签配置](https://tslink.md/zh/docs/configuration.md#%E6%A0%87%E7%AD%BE%E9%85%8D%E7%BD%AE)。

### 访问控制

将代理/文件 HTTP 服务限制为 Tailscale 登录邮箱或设备标签：

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

配置 `--allow` 后，缺少或不匹配的 WhoIs 身份会在到达代理后端或文件内容前收到 `403 Forbidden`。解析按源 IP 缓存 60 秒，不是每次请求都重新查询控制面。文件服务通过 WhoIs 授权/记录日志，不注入身份头；保留应用自身所需授权。

这是 HTTP 请求过滤，不适用于原始 TCP 服务。

人员授权为私有 HTTP/文件添加逐请求 WhoIs 检查与期限。已管理账户的人员授权优先于旧 allow，撤销保留拒绝记录。仅旧 allow 检查及身份头使用上面的缓存行为；人员授权不缓存。见[分享给指定的人](https://tslink.md/zh/docs/people-sharing.md)。

### Tailscale Funnel

通过 [Tailscale Funnel](https://tailscale.com/kb/1223/funnel) 将代理服务公开暴露到互联网：

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

此处的开放 Funnel 发布仅适用于代理服务。它必须显式传 `--public` 确认，会让服务 URL 公开可访问，客户端无需安装 Tailscale，且不受 TSLink 身份执行保护。允许节点公开服务不等于授权互联网访客；所需访客认证与授权应由后端应用负责。

### 自定义域名（Roadmap / experimental）

自定义域名 TLS 和 ACME 尚未实现。`--domain` / `--acme-email` 标志及 `domain` / `acme_email` registry 字段已移除；旧 registry 键即使为空也会以 `unknown_config_key` 拒绝。已交付流程请使用默认 `<service>.<tailnet>.ts.net` 主机名。

### 服务级控制服务器

覆盖全局控制服务器（适用于混合使用 Tailscale 和 Headscale 节点的场景）：

```bash
tslink add headscale-app --proxy localhost:3000 --control-url https://headscale.example.com
```

或直接在 `registry.json` 中设置：

```json
{
  "name": "headscale-app",
  "type": "proxy",
  "target": "http://localhost:3000",
  "control_url": "https://headscale.example.com"
}
```

**配置优先级：** 服务级标志/配置 > `serve` 的 CLI 标志 > 全局配置（`tslink config`）> Tailscale 默认值。

### 中间件（Roadmap / experimental）

可配置 rate limiting、Basic Auth、IP allow list 和 CORS 尚不可用，已移除的 `middleware` 键即使为空也会在 registry 加载时以 `unknown_config_key` 拒绝，见[实验性与路线图](https://tslink.md/zh/docs/experimental-roadmap.md#%E4%B8%AD%E9%97%B4%E4%BB%B6)。它不是运行中分享的保护层。

## Docker 自动发现（Roadmap / experimental）

Docker discovery 尚未实现，当前 TSLink 没有 discovery 包或可用标签。该功能接入并完成集成测试前，请用 `tslink add` 显式注册服务。

## 命名约定

服务名称是 URL 的一部分：

```
https://<服务名>.<tailnet名>.ts.net
```

**规则：**

* 仅限小写字母、数字和连字符
* 必须以字母或数字开头和结尾
* 在 TSLink 实例中必须唯一

**好的名称示例：** `webapp`、`api-v2`、`staging-server`、`docs`

## 列出服务

查看所有已注册的服务：

```bash
tslink list
```

显示每个条目的服务名称、类型、目标和已配置的标志。

## 移除服务

按名称移除服务：

```bash
tslink remove frontend
```

本地移除会删除 registry 条目；运行中的网关通过热重载检测到变化后停止服务。远端 tailnet 清理只有在 TSLink 能证明匹配设备的精确所有权时才会尝试；否则匹配候选会报告为 protected，并跳过清理。本地成功不证明远端设备已删除。

## 热重载

TSLink 使用 [fsnotify](https://github.com/fsnotify/fsnotify) 监控 `registry.json` 的变化。当你在网关运行时添加或移除服务：

1. 注册表文件自动更新。
2. 文件监控器检测到变化。
3. 新服务完成入网、审批并就绪后开始接收流量；移除的服务停止。

这意味着你可以在不中断其他活动服务的情况下管理服务。

**通过热重载生效：**

* 添加新服务（`tslink add`）
* 移除服务（`tslink remove`）
* runtime 能检测到的结构性变化，例如 target/path/port、标签、临时节点模式或服务级控制服务器 URL 更新，会重启受影响节点

Runtime 重启不同于注册状态重置：标签修改会保留 Tier 1 用户注册。字段及身份契约见[热重载](https://tslink.md/zh/docs/configuration.md#%E7%83%AD%E9%87%8D%E8%BD%BD)。

**需要重启网关：**

* 修改全局配置（如 `control-url`）
* 更新认证凭证或切换凭证模式（`tslink login`）
* 修改旧版 `authkey` 文件

这些变更请使用[按平台恢复运行的重启流程](https://tslink.md/zh/docs/daemon.md#%E9%85%8D%E7%BD%AE%E5%8F%98%E6%9B%B4%E5%90%8E%E9%87%8D%E5%90%AF)。受管理安装需先确认停机，再通过对应管理器恢复运行；手动 `stop` / `serve` 仅适用于未登记自启动的环境。

启动时，TSLink 还会尝试对上次运行遗留的过期 tailnet 节点做所有权安全的清理。缺少精确所有权证明的候选会报告为 protected/skipped。

## 多服务

注册任意数量的服务。每个服务获得自己的主机名：

```bash
tslink add app --proxy localhost:3000
tslink add api --proxy localhost:8080
tslink add docs --dir ~/docs
tslink add mydb --tcp localhost:5432
```

默认 add 已会确保后台网关运行。检查每次结果，如返回 `needs_login`，打开它的 `auth_url` 并完成 tailnet 要求的注册/审批。随后对每个服务运行 `tslink url <name> --wait`，并检查 `tslink status --json`。同一网关会同时运行所有已就绪服务；默认 add 后不要再执行 `serve`。

明确选择手动运行时，注册使用 `--no-daemon-install`，且只有在没有网关或受管理安装时才启动 `serve`。该流程及确认停机的前提见[守护进程模式](https://tslink.md/zh/docs/daemon.md#%E4%BD%9C%E4%B8%BA%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%E8%BF%90%E8%A1%8C)。

## 访客与私有管理流程

上面的 Funnel 注册是**开放发布**。[访客链接](https://tslink.md/zh/docs/guest-links.md)则从私有 HTTP proxy 应用开始，明确启用有强制 gate 和可选 PIN 的公网 Funnel。链接分别到期，私有人员/allow 检查保持独立。新公开期限至少 1h，默认 24h，默认上限 7d，拒绝 never。[期限](https://tslink.md/zh/docs/durations.md)说明主人上限与明确 regrant。

[每台主机的私有 portal 与请求](https://tslink.md/zh/docs/portal-requests.md)帮助符合条件的 tailnet 成员发现或申请私有 HTTP/文件应用。[访问历史](https://tslink.md/zh/docs/access-history.md)检查保留的访问，不保证完整记录。
