windows 本地服务加证书

流量路径

┌──────────────────────────────────────────────────────────┐
│              tailscale serve HTTPS 流量路径               │
│          TLS 在 max2 本机终结 · 不经过云端转发               │
├──────────────────────────────────────────────────────────┤
│                     arm Hermes Agent                     │
│        opencode --attach https://max2-at...:4096         │
│                            │                             │
│                            ▼                             │
├──────────────────────────────────────────────────────────┤
│               ① WireGuard 隧道(P2P 直连)                │
│           端到端加密 · 同局域网直连 · 不经云端                │
│                            │                             │
│                            ▼                             │
├──────────────────────────────────────────────────────────┤
│               ② max2 本机 tailscale serve                │
│┌────────────────────────────────────────────────────────┐│
││                HTTPS :4096(TLS 卸载)                  ││
││             Let's Encrypt 证书 · 本地终结                ││
││                 解密后转发到 localhost                   ││
│└────────────────────────────────────────────────────────┘│
│                            │                             │
│                            ▼                             │
├──────────────────────────────────────────────────────────┤
│              ③ opencode serve :4096(HTTP)              │
│               localhost 本地服务 · 纯 HTTP                │
│          收到的是 tailscale serve 解密后的请求              │
│                            │                             │
│                            ▼                             │
├──────────────────────────────────────────────────────────┤
│             结果:Hermes 通过 HTTPS 安全连接                │
│            WireGuard 不可窃听 + TLS 不可篡改               │
│                    双层加密,纵深防御                       │
└──────────────────────────────────────────────────────────┘

背景

opencode serve 默认只提供 HTTP 服务。在 tailnet 内通过 WireGuard 传输已经加密,HTTP 裸连在现有架构下是安全的。但如果出于纵深防御、策略合规或工具兼容性需要 HTTPS,有以下方案。

核心约束:域名 max2-at.tail9e6317.ts.net 只对 tailnet 内节点可解析,公开 ACME 挑战不可用。Tailscale 通过自己的 ACME DNS 挑战协议签发 Let's Encrypt 证书。

方案 A:tailscale serve(推荐)

Tailscale 内置 serve 命令,自动绑 Let's Encrypt 证书,一行完成 TLS 卸载。

流量路径:
Hermes ──[Tailscale HTTPS :4096]── tailscale serve ──[HTTP localhost]── opencode

操作步骤(max2 PowerShell):

# 1. 先注册 tailscale serve,--bg 不阻塞,立即返回
tailscale serve --bg --https 4096 http://127.0.0.1:4096

# 2. 同一个窗口继续启动 opencode serve(阻塞打印日志)
opencode serve --print-logs --hostname 127.0.0.1 --port 4096

验证:

tailscale serve status

清理:

tailscale serve --https 4096 off
tailscale serve reset

之后 Hermes 连接 https://max2-at.tail9e6317.ts.net:4096/,Tailscale 自动处理 TLS 证书。

注意: --https 4096 指定的是对外暴露的 HTTPS 端口,http://127.0.0.1:4096 是实际提供服务的地址,两者端口一致即可。老版命令 tailscale serve --https 4096 / http://127.0.0.1:PORT 中用 / 分隔的语法已被新版移除。

特性说明
证书管理全自动,Tailscale 处理续期
配置量一行命令,零维护
依赖仅 Tailscale(已安装)

方案 B:Caddy + tailscale cert

如果 tailscale serve 的行为不满足需求,Caddy 是备用方案。

# 1. 安装 Caddy
scoop install caddy

# 2. 获取 Tailscale 证书(Tailscale 内部处理 ACME DNS-01 挑战)
tailscale cert max2-at.tail9e6317.ts.net
# 在当前目录生成 cert.pem + key.pem
# 3 个月有效期,Tailscale 会自动续期

# 3. 写 Caddyfile
https://max2-at.tail9e6317.ts.net:4096 {
    tls /path/to/cert.pem /path/to/key.pem
    reverse_proxy 127.0.0.1:58407
}

# 4. 启动 Caddy
caddy run
特性说明
证书管理半自动,需手动 cert 命令,Tailscale 自动续期文件
配置量一个 Caddyfile,适合高级场景
依赖需装 Caddy
适用场景需要额外中间件、路径重写、请求过滤等

方案 C:stunnel + tailscale cert

stunnel 是经典的 TLS 隧道工具。

# 1. 获取证书
tailscale cert max2-at.tail9e6317.ts.net

# 2. 写 stunnel.conf
[https-service]
accept = 4096
connect = 127.0.0.1:58407
cert = cert.pem
key = key.pem

# 3. 启动 stunnel
stunnel stunnel.conf
特性说明
证书管理需手动 cert,Tailscale 自动续期文件
配置量一个 .conf 文件
依赖需装 stunnel
适用场景最小化依赖,仅做 TLS 隧道

方案选型建议

场景推荐理由
日常 opencode 开发不配 HTTPSWireGuard 传输加密已够用,设好 PASSWORD + ACL 即可
纵深防御 / 合规要求tailscale serve一行命令,零维护,TLS 卸载
需要中间件处理Caddy反向代理 + TLS 一体,灵活
纯隧道,最小依赖stunnel仅做 TLS,不改应用层

常见疑问

打开 Serve 后流量会走 Tailscale 云端转发吗?

不会。 Tailscale Serve 的 TLS 证书在 max2 本机上终止,流量路径不变:

arm Hermes
  │
  ▼
┌──────────────────────────────────┐
│  WireGuard 隧道                   │
│  (P2P 直连 / 不经过 Tailscale 云) │  ← 与不开 Serve 完全一致
└──────────────────────────────────┘
  │
  ▼
max2 本机
  ├── tailscale serve(TLS 卸载) ← 本地完成
  │     HTTPS → HTTP 解密转发
  │
  └── opencode serve :4096(HTTP)
 不开 Serve (HTTP)开 Serve (HTTPS)
传输层WireGuard 加密WireGuard + TLS
网络路径P2P 直连 / DERP 中继P2P 直连 / DERP 中继(不变)
TLS 终结位置max2 本机
云端处理业务流量

HTTPS 的密钥交换和卸载都在 max2 本地完成,相当于在 WireGuard 隧道上面加了一层 TLS,两层的加解密都是本地节点之间的事。证书拉取和续期通过 Tailscale 控制面走 ACME DNS-01,不与业务流量路径重叠。

需要先在管理后台开启

首次使用 tailscale serve 会提示:

Serve is not enabled on your tailnet.
To enable, visit:
  https://login.tailscale.com/f/serve?node=xxxx

点链接到 Tailscale 管理后台开启 Serve 开关即可,一次开启,后续不再提示。

注意

  • HTTPS 解决的是传输通道加密和身份验证,不代替应用层认证。无论用哪个方案,OPENCODE_SERVER_PASSWORD 必须设置
  • tailscale cert 签发的 Let's Encrypt 证书 90 天有效期,Tailscale 会自动在到期前重新拉取到 %ProgramData%\Tailscale\certs\
  • tailscale serve 本质是本地代理 + TLS 卸载,opencode serve 本身仍以 HTTP 绑定 localhost,外界通过 HTTPS 端口访问时,Tailscale 解密转发到本地 HTTP 端口
  • 新版 tailscale serve 的 --https 语法不带 / 分隔:tailscale serve --bg --https 4096 http://127.0.0.1:PORT
  • 先跑 tailscale serve --bg 注册转发(不阻塞),再跑 opencode serve 阻塞看日志,同一个窗口完成