Tailscale SSH隧道打洞

概述

  • tailscale官方服务
    • 中心点:官方节点发现服务器(后台: https://login.tailscale.com/admin/machines
      • 3个登录账号,100个端点 auth key (free和pro用户)
    • 客户端:每个设备包括本地服务器也是一个端点,google登录每个节点,同一个账号下形成互通
      • windows有安装包或scoop install
      • linux可以上docker
    • 官方子域名/公网IP,无损直接ssh使用
    • 非常流畅,无需代理
  • headscale私有化
    • 中心点:headscale申请端口,headscale-admin管理后台

〇、架构总览(Control Plane / Data Plane / Relay Plane 三面分离)

Tailscale 私有化部署(Headscale)后,体系拆解为三个独立平面和一个传输层:

┌─────────────────────────────────────────────────────────────────────────┐
│                       协 调 面 (Control Plane)                            │
│                        Headscale 服务端                                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐              │
│  │  身份认证     │  │  节点发现     │  │  ACL 策略引擎    │              │
│  │  auth key    │  │  交换打洞信息  │  │  grants 权限规则  │              │
│  │  Google OAuth │  │  分配 IP      │  │  tag/group 管理  │              │
│  └──────────────┘  └──────────────┘  └──────────────────┘              │
│  ⚠ 不碰任何用户数据流 — 只负责"牵线"                                       │
├─────────────────────────────────────────────────────────────────────────┤
│                       转 发 面 (Relay Plane) — DERP                       │
│  ┌──────────────────────────────────────────────────────────┐           │
│  │  角色:P2P 打洞失败时的保底转发通道                          │           │
│  │  触发条件:两端均为对称型 NAT / 企业防火墙 / 移动宽带          │           │
│  │  安全:即使走中继,数据已被 WireGuard 端到端加密                │           │
│  │        中继服务器(官方/自建 derper)只搬运密文,无法解密       │           │
│  │  部署方案:                                                      │           │
│  │    ① Tailscale 官方全球 DERP(默认,无需配置)                  │           │
│  │    ② Headscale Embedded DERP(自建内置中继)                   │           │
│  │    ③ 独立 derper 服务(完全私有、不限速)                        │           │
│  └──────────────────────────────────────────────────────────┘           │
└─────────────────────────────────────────────────────────────────────────┘
        ↑ WireGuard 协议 — 端到端加密
        │ P2P 直连 ↔ DERP 中继 自动切换(对上层透明)
        ↓ 每个节点一个 100.64.0.0/10 虚拟 IP
┌─────────────────────────────────────────────────────────────────────────┐
│                       数 据 面 (Data Plane)                               │
│               WireGuard 加密隧道 — 实际业务流量通道                        │
│                                                                         │
│        ┌──────────────┐                   ┌──────────────┐             │
│        │  节点 A       │  ═══ P2P 直连 ═══ ▶  节点 B       │             │
│        │  100.64.x.1  │   (打洞成功)      │  100.64.x.2  │             │
│        └──────┬───────┘                   └──────┬───────┘             │
│               │                                   │                      │
│               │     ┌──────────────┐              │                      │
│               └─────│  DERP 中继    │─────────────┘                      │
│                     │  (打洞失败时)  │                                    │
│                     └──────────────┘                                     │
└─────────────────────────────────────────────────────────────────────────┘

端点 (Endpoints) 与分组 (Groups)

端点分组Tag职责访问权限
管理节点group:admin拥有打 tag 权限,管理整个 tailnet 的 ACL 策略*:* 全通
服务器tag:server提供 SSH/HTTP/数据库等业务服务可主动连所有 member 的任意端口
成员设备tag:member个人笔记本/工作站/手机等消费端只能连 server 的指定端口(如 22,80,443)
临时设备EphemeralCI/CD 构建机、一次性容器等,每次启动需重新认证受 ACL 约束,不持久化状态

三种协议与传输关系

协议层面用途加密
WireGuard (L3 tunnel over UDP)数据面P2P 加密隧道,承载 SSH/HTTP/任意 TCP/UDP 业务流量端到端 Curve25519 + ChaCha20Poly1305
DERP (HTTP over TLS)转发面P2P 打洞失败时的中继转发,对 WireGuard 包做二次封装传输层 TLS + WireGuard 双层加密
Headscale API (HTTPS)控制面节点注册、auth key 验证、打洞信息交换、ACL 下发HTTPS(不承载业务数据)

连接状态判断

$ tailscale status
100.64.x.1  node-a  linux   active; tx 1024 rx 2048; direct    ← P2P 直连(数据不过任何服务器)
100.64.x.2  node-b  linux   active; tx 512  rx 768;  relay     ← 中继转发(打洞失败,走 DERP)

架构设计原则

  1. 控制面不碰数据:Headscale 只做认证、发现、策略下发,绝对不转发业务流量。类比电话交换机的"接通即挂断"。
  2. 数据面端到端加密:WireGuard 隧道在客户端之间直接建立,密钥仅存在于两端,Headscale 和 DERP 都无法解密。
  3. 透明回退:P2P 直连失败自动切换到 DERP 中继,过程中 TCP 连接不中断,上层应用无感知。
  4. 最小暴露:member 只能访问 server 的指定端口(如 SSH 22 / Web 80/443),member 之间默认不通,server 可自由出站。
  5. 状态持久化:TS_STATE_DIR 保存设备证书和 WireGuard 密钥,避免重启后变成新设备导致 ACL 失效。

协议栈叠放 (Protocol Stack) — 常见协议在架构中的位置

WireGuard 工作在 Layer 3(网络层),创建一个虚拟网卡(tun0),分配 100.64.0.0/10 虚拟 IP。所有上层协议(HTTP/HTTPS/SSH/任意 TCP/UDP)都跑在 WireGuard 隧道内部,对外表现为 UDP 包或 DERP TLS 流。

┌────────────────────────────────────────────────────────────────────┐
│                    实 际 业 务 流 量                                  │
│                                                                    │
│        SSH               HTTP              HTTPS                   │
│   (TCP/22)          (TCP/80)          (TCP/443)                    │
│        │                 │                 │                        │
│        └─────────────────┴─────────────────┘                        │
│                        │                                            │
│                    TCP / UDP                                        │
│                 (传输层 — Transport Layer)                           │
│                        │                                            │
│              ┌─────────▼─────────┐                                   │
│              │  WireGuard Tunnel  │  ← 虚拟网卡 tun0                  │
│              │  100.64.x.x 虚拟IP │  ← 每个节点一个                    │
│              │  Layer 3 加密隧道  │  ← Curve25519 + ChaCha20Poly1305 │
│              └─────────┬─────────┘                                   │
│                        │                                            │
├────────────────────────┼────────────────────────────────────────────┤
│          P2P 直连路径   │            DERP 中继路径                    │
│                        │                                            │
│     ┌────────▼──────┐  │  ┌───────────▼───────────┐                 │
│     │  WireGuard     │  │  │  DERP (HTTP over TLS) │                 │
│     │  UDP 包        │  │  │  将 WireGuard 包封装   │                 │
│     │  明文 dst:41641│  │  │  为 HTTPS 请求        │                 │
│     │  (内容加密)   │  │  │  dst:443 → derper    │                 │
│     └───────┬───────┘  │  └───────────┬───────────┘                 │
│             │          │              │                              │
│             ▼          │              ▼                              │
│         Internet       │          Internet                           │
└────────────────────────────────────────────────────────────────────┘

实际场景示例:SSH 到 100.64.x.2

# 你执行
$ ssh user@100.64.x.2

# 背后实际发生的协议栈(从内到外):
┌─────────────────────────────────────────────────────┐
│  ① SSH 握手 (TCP/22)                                 │
│     ↓ 这是你要传输的数据                                │
│  ② TCP 分段 → IP 包 (src:100.64.x.1 → dst:100.64.x.2)│
│     ↓ WireGuard 虚拟网卡拦截这个 IP 包                 │
│  ③ WireGuard 加密整个 IP 包                            │
│     ↓ 结果是一个密文 UDP 包                             │
│  ④ 封装为 UDP 包 (src:公网IP:41641 → dst:公网IP:41641) │
│     ↓ 或者封装为 HTTPS 请求发往 DERP (打洞失败时)       │
│  ⑤ 真正的物理网卡发送                                   │
└─────────────────────────────────────────────────────┘

# 协议栈全景:从 wire 到应用
┌─────────────────────────────────────────────┐
│  应用层  │  SSH / HTTP / HTTPS  (明文在本地) │
│  传输层  │  TCP / UDP                       │
│  网络层  │  IP (100.64.x.x)                 │
│  ── WireGuard 加密隧道(对 OS 透明)──────── │
│  传输层  │  UDP (端口 41641)                 │
│  网络层  │  IP (公网 IP)                     │
│  链路层  │  以太网 / Wi-Fi                   │
└─────────────────────────────────────────────┘

ACL 端口控制的真实含义

ACL 规则: {"src": ["tag:member"], "dst": ["tag:server"], "ip": ["22", "80", "443"]}

这句的意思是:在 WireGuard 隧道内部的 IP 包层面,
member 发向 server (100.64.x.2) 的 TCP 包,目标端口只允许 22/80/443。
端口 3306 (MySQL)、5432 (PostgreSQL)、8080 等默认被拒绝。

这不是防火墙规则(不是 iptables),而是 WireGuard 节点间 ACL,
由每个节点的 tailscale 守护进程在本地 enforce:
出站包在进入 WireGuard 隧道前被拦截检查,不符合 grants 的不予通过。

各协议在不同层面的角色汇总

协议OSI 层面在 Tailscale 架构中的角色
SSH应用层 (TCP/22)跑在 WireGuard 隧道内部,是你要传输的"数据"本身。Tailscale SSH 模式甚至可免密钥管理直接登录。
HTTP应用层 (TCP/80)同样跑在 WireGuard 内部。访问 100.64.x.2:80 就像访问局域网 IP。
HTTPS应用层 (TCP/443)WireGuard 隧道内部再加一层 TLS,双层加密(隧道级 + 应用级)。
TCP传输层WireGuard 隧道内承载的主流传输协议。隧道内的 TCP 包被 WireGuard 整体加密,外部不可见。
UDP传输层双重角色:既是隧道内载荷(DNS/QUIC/VoIP),也是隧道本身的传输载体(WireGuard 使用 UDP 41641)。
WireGuard隧道层 (L3 over UDP)在 UDP 之上建立虚拟 Layer 3 网络,对 OS 呈现为 tun0 网卡。所有业务流量经它加密进入物理网络。
DERP中继层 (HTTP/TLS)HTTPS (TCP/443) 封装 WireGuard 包,当 P2P UDP 打洞失败时回退使用。双层加密(TLS + WireGuard)。

常用命令

net start tailscale
tailscale up
tailscale login --authkey xxxxxxxx

tailscale down
tailscale status
tailscale metrics
tailscale appc-routes
tailscale drive
tailscale logout
tailscale switch

单人多机

  • 每个端点都登录google账号即可
  • 这里google即是账号权限,也是端点权限

多人局域

  • 架构

    Google 账号 → 仅控制台管理(不认证设备)
             ├─ tag:server (Server A) ← auth key for server
             └─ tag:member (用户组)   ← 每人一个 auth key
    
    ┌────────────── groups ──────────────────┐
    │  group:admin = ["xxx@gmail.com]        │ ← 唯一能打 tag 的人
    ├───────────── tags(成员)───────────────┤
    
    │  tag:server → Server A                 │ ← 管理员打 tag
    │  tag:member → 用户甲                    │ ← auth key 自带
    │  tag:member → 用户乙                    │ ← auth key 自带
    └────────────────────────────────────────┘
    
    ┌────────────────────────────────────────────┐
    │  tag:server → *:*                          │
    │  ✅ server 可以主动连 member 的任意端口       │
    ├────────────────────────────────────────────┤
    │  tag:member → tag:server:22,80,443,4180    │
    │  ✅ member 可以主动连 server 的指定端口       │  ← member到member的访问没有配置
    └────────────────────────────────────────────┘
  • 权限配置: https://login.tailscale.com/admin/acls/file 

    {
      // 定义管理员和你自己的组
      "groups": {
        "group:kc217": ["your-google-email@gmail.com"]
      },
    
      // 定义 tag 及谁能打
      "tagOwners": {
        "tag:server": ["group:kc217"],
        "tag:member": ["group:kc217"]
      },
    
      // 权限规则
      "grants": [
        // 管理员全通
        {"src": ["group:kc217"], "dst": ["*"], "ip": ["*"]},
    
        // tag:member 只能访问 server 的指定端口
        {"src": ["tag:member"], "dst": ["tag:server"], "ip": ["22", "80", "443", "2222", "4180"]},
    
        // server 可以自由出站
        {"src": ["tag:server"], "dst": ["*"], "ip": ["*"]},
      ],
    }
  • 添加成员auth key: https://login.tailscale.com/admin/settings/keys 

    Description:密钥名称
    Reusable:认证单次或多次,如果是单次则客户端用一次则直接失效,但认证状态可以永久有效
    Expiration:失效期1-90天,认证行为有效期,而非认证后的认证状态有效期
    Ephemeral:临时权限,每次登录都需要认证
    Tags:关联tag

docker-compose.yml

services:
  tailscale:
    image: tailscale/tailscale:stable # 使用官方长期维护的稳定版标签
    container_name: tailscale
    restart: always
    privileged: true                  # 必须:给予网络管理特权以创建 tun 虚拟网卡
    network_mode: "host"              # 必须:使用 host 模式实现最优的 P2P 穿透打洞性能

    # 👇 新增下面两个环境变量,彻底关掉临时节点模式
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxxxxxxxxxxxx
      - TS_EPHEMERAL=false
      - TS_STATE_DIR=/var/lib/tailscale
      # 👇 强行清空容器内的代理环境变量,让它走原生非代理网络(国内大部分时间可以直接握手)
      - HTTP_PROXY=
      - HTTPS_PROXY=
      - http_proxy=
      - https_proxy=

    volumes:
      - ./data/tailscale:/var/lib/tailscale  # 核心持久化:保存设备证书和状态,防止重启后重连/变成新设备
      - /dev/net/tun:/dev/net/tun             # 必须:映射宿主机的网络隧道设备
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro       # 严格统一时区,防止证书因时间错乱失效

    # 资源约束:防止由于网络风暴、DDoS或异常流量压垮公司服务器
    deploy:
      resources:
        limits:
          cpus: '0.50'       # 限制最多使用 50% 的单核 CPU
          memory: 256M       # 限制最多使用 512MB 内存