Skip to content

Commit f278504

Browse files
committed
feat(tailscale): add dedicated derp template
1 parent fff1676 commit f278504

13 files changed

Lines changed: 745 additions & 57 deletions

File tree

config/dockerfiles/compose/docker-compose.yml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -411,24 +411,6 @@ services:
411411
max-file: "3"
412412
profiles: ["gotify"]
413413

414-
derper:
415-
image: fredliang/derper
416-
restart: ${RESTART_POLICY:-unless-stopped}
417-
environment:
418-
# 保持与现有 docker run 用法一致,便于复用现有 DERP/STUN 部署参数。
419-
DERP_ADDR: ":8443"
420-
DERP_STUN_PORT: "3478"
421-
DERP_VERIFY_CLIENTS: "false"
422-
ports:
423-
- "8443:8443"
424-
- "3478:3478/udp"
425-
logging:
426-
driver: "json-file"
427-
options:
428-
max-size: "10m"
429-
max-file: "3"
430-
profiles: ["derper"]
431-
432414
sillytavern:
433415
image: ghcr.io/sillytavern/sillytavern:latest
434416
restart: ${RESTART_POLICY:-unless-stopped}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 构建与镜像版本。启用 --verify-clients 时,建议这里和 tailscaled 使用同一版本线。
2+
TAILSCALE_VERSION=latest
3+
4+
# 必填:DERP 对外公布的公网 IP。manual cert 模式会以它作为证书主机名与 certdir 文件名。
5+
DERP_PUBLIC_IP=
6+
7+
# 必填:让 tailscaled-auth 加入 tailnet 的 auth key。建议使用可复用或带标签的服务端 key。
8+
TS_AUTHKEY=
9+
10+
# 可选:tailscaled 在 tailnet 中显示的节点名。
11+
TS_HOSTNAME=derp-auth
12+
13+
# 可选:自定义 tailscaled 附加参数;默认不接受路由和 DNS,避免这个辅助节点承担额外职责。
14+
TS_EXTRA_ARGS=--accept-routes=false --accept-dns=false
15+
16+
# DERP / STUN 监听端口。derper 使用 host network,因此这些端口需要直接在宿主机防火墙放行。
17+
DERP_PORT=443
18+
DERP_HTTP_PORT=80
19+
DERP_STUN_PORT=3478
20+
21+
# 可选:证书目录。若目录中不存在 <DERP_PUBLIC_IP>.crt/.key,derper 会自动生成自签 IP 证书。
22+
DERP_CERTS_DIR=./certs
23+
24+
# 可选:连接接入速率限制,用于减轻突发滥用;它是补强,不替代 --verify-clients。
25+
DERP_ACCEPT_CONNECTION_LIMIT=32
26+
DERP_ACCEPT_CONNECTION_BURST=64
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# 通过构建时版本参数把 derper 固定到明确的 Tailscale 版本,方便和 tailscaled 对齐。
2+
FROM golang:1.24-alpine AS build
3+
4+
ARG TAILSCALE_VERSION=latest
5+
6+
RUN apk add --no-cache git
7+
RUN go install tailscale.com/cmd/derper@${TAILSCALE_VERSION}
8+
9+
FROM alpine:3.22
10+
11+
RUN apk add --no-cache ca-certificates
12+
COPY --from=build /go/bin/derper /usr/local/bin/derper
13+
14+
ENTRYPOINT ["/usr/local/bin/derper"]
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Tailscale DERP Template
2+
3+
这个目录提供仓库内默认的自建 DERP 入口,替代共享 `docker-compose.yml` 里的旧 `derper` 服务。
4+
5+
目录职责:
6+
7+
- `compose.yaml`
8+
作用:定义 `tailscaled-auth``derper` 两个服务。
9+
- `Dockerfile.derper`
10+
作用:构建并运行 `cmd/derper`,避免继续依赖外部第三方 `derper` 镜像。
11+
- `.env.example`
12+
作用:给出推荐默认值;你通常只需要额外补公网 IP 与 `TS_AUTHKEY`
13+
- `tailnet-policy.derp.example.hujson`
14+
作用:提供可直接改 IP 和端口后合并进 tailnet policy 的 `derpMap` 模板。
15+
- `start.ps1`
16+
作用:统一封装常用 `docker compose` 操作,避免每次手写长命令。
17+
18+
## 设计说明
19+
20+
- `tailscaled-auth` 只负责登录 tailnet、维护 state 和暴露 `tailscaled.sock`
21+
- `derper` 通过 `--verify-clients` + `tailscaled.sock` 把访问范围限制在当前 tailnet
22+
- `derper` 使用 `network_mode: host`
23+
原因:官方不建议把 DERP 放在 NAT 后面,而 Docker bridge 的 `ports:` 发布本质上就是一层 NAT
24+
- `derper` 使用 `--certmode=manual --certdir=/var/lib/derper/certs`
25+
`DERP_PUBLIC_IP` 是 IP 且 `certdir` 里没有对应 `<IP>.crt/.key` 时,当前 `cmd/derper` 会自动生成自签 IP 证书
26+
27+
## 启动前准备
28+
29+
1. 复制环境变量模板:
30+
31+
```bash
32+
cp config/network/tailscale/derp/.env.example config/network/tailscale/derp/.env.local
33+
```
34+
35+
2. 编辑 `config/network/tailscale/derp/.env.local`
36+
37+
至少填写:
38+
39+
- `DERP_PUBLIC_IP`
40+
- `TS_AUTHKEY`
41+
42+
3. 确认宿主机防火墙已放行:
43+
44+
- `TCP 80`
45+
- `TCP 443`
46+
- `UDP 3478`
47+
48+
## 启动
49+
50+
推荐命令:
51+
52+
```bash
53+
docker compose --env-file config/network/tailscale/derp/.env.local -f config/network/tailscale/derp/compose.yaml --project-directory config/network/tailscale/derp up -d --build
54+
```
55+
56+
如果你习惯 PowerShell,也可以直接用:
57+
58+
```powershell
59+
./config/network/tailscale/derp/start.ps1
60+
```
61+
62+
常用命令:
63+
64+
```bash
65+
docker compose --env-file config/network/tailscale/derp/.env.local -f config/network/tailscale/derp/compose.yaml --project-directory config/network/tailscale/derp logs -f derper
66+
docker compose --env-file config/network/tailscale/derp/.env.local -f config/network/tailscale/derp/compose.yaml --project-directory config/network/tailscale/derp ps
67+
docker compose --env-file config/network/tailscale/derp/.env.local -f config/network/tailscale/derp/compose.yaml --project-directory config/network/tailscale/derp down
68+
```
69+
70+
对应的 `start.ps1` 用法:
71+
72+
```powershell
73+
./config/network/tailscale/derp/start.ps1
74+
./config/network/tailscale/derp/start.ps1 logs --tail 100
75+
./config/network/tailscale/derp/start.ps1 ps
76+
./config/network/tailscale/derp/start.ps1 pull
77+
./config/network/tailscale/derp/start.ps1 config
78+
./config/network/tailscale/derp/start.ps1 -DryRun
79+
```
80+
81+
## 证书行为
82+
83+
默认 `DERP_CERTS_DIR=./certs`。第一轮启动时:
84+
85+
- 如果目录里已经有 `${DERP_PUBLIC_IP}.crt``${DERP_PUBLIC_IP}.key``derper` 会直接使用它们
86+
- 如果目录为空,且 `DERP_PUBLIC_IP` 是 IP,`derper` 会自动生成一对自签 IP 证书
87+
88+
这也是当前仓库里 `Set-TailscaleDerp.ps1` 仍然输出 `InsecureForTests = true` 的原因之一:第一版模板默认走
89+
IP-only + 自签证书路线。
90+
91+
## 写入 tailnet policy
92+
93+
容器启动后,再用仓库脚本把同一个公网 IP 写进 tailnet policy:
94+
95+
```powershell
96+
./scripts/pwsh/network/tailscale/Set-TailscaleDerp.ps1 `
97+
-ServerIp 203.0.113.10 `
98+
-DerpPort 443 `
99+
-StunPort 3478 `
100+
-PolicyPath ./tailnet-policy.hujson
101+
```
102+
103+
如果你是直接在 Admin Console 的 JSON editor 里改,可以只生成片段:
104+
105+
```powershell
106+
./scripts/pwsh/network/tailscale/Set-TailscaleDerp.ps1 `
107+
-ServerIp 203.0.113.10 `
108+
-DerpPort 443 `
109+
-StunPort 3478 `
110+
-PrintSnippet
111+
```
112+
113+
如果你更喜欢先改现成模板,再手动合并到 tailnet policy,也可以从这里开始:
114+
115+
`config/network/tailscale/derp/tailnet-policy.derp.example.hujson`
116+
117+
## 验证
118+
119+
模板检查:
120+
121+
```bash
122+
DERP_PUBLIC_IP=203.0.113.10 TS_AUTHKEY=tskey-example docker compose -f config/network/tailscale/derp/compose.yaml --project-directory config/network/tailscale/derp config
123+
```
124+
125+
客户端侧排查:
126+
127+
- `tailscale netcheck`
128+
- `tailscale ping <另一台设备>`
129+
- `tailscale debug derp`
130+
131+
## 注意事项
132+
133+
- `--verify-clients` 只能限制到 tailnet 级,不能进一步细分“同 tailnet 内哪些设备允许走这个 DERP”
134+
- 如果你把 `derper``tailscaled-auth` 固定到不同 Tailscale 版本,官方当前不保证 `--verify-clients` 路径稳定可用
135+
- 如果你后续有稳定域名,可以继续沿用这个目录结构,再把 manual cert 路线切换到域名证书方案
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
services:
2+
tailscaled-auth:
3+
image: tailscale/tailscale:${TAILSCALE_VERSION:-latest}
4+
restart: unless-stopped
5+
environment:
6+
# 使用一次性 auth key 初始化 state;后续重启优先复用持久化 state,避免重复登录。
7+
TS_AUTHKEY: ${TS_AUTHKEY:?set TS_AUTHKEY in .env.local}
8+
TS_AUTH_ONCE: "true"
9+
# derper 只需要本地 LocalAPI socket,不需要把 tailscaled 暴露到宿主机。
10+
TS_STATE_DIR: /var/lib/tailscale
11+
TS_SOCKET: /var/run/tailscale/tailscaled.sock
12+
TS_HOSTNAME: ${TS_HOSTNAME:-derp-auth}
13+
# 这里只承担控制面校验职责,用 userspace 模式避免额外 TUN / NET_ADMIN 依赖。
14+
TS_USERSPACE: "true"
15+
# 该节点只用于 DERP 客户端准入校验,不接受额外路由或 DNS 配置。
16+
TS_EXTRA_ARGS: ${TS_EXTRA_ARGS:---accept-routes=false --accept-dns=false}
17+
volumes:
18+
- tailscale-state:/var/lib/tailscale
19+
- tailscale-socket:/var/run/tailscale
20+
21+
derper:
22+
build:
23+
context: .
24+
dockerfile: Dockerfile.derper
25+
args:
26+
TAILSCALE_VERSION: ${TAILSCALE_VERSION:-latest}
27+
restart: unless-stopped
28+
depends_on:
29+
- tailscaled-auth
30+
# 官方不建议把 DERP 放在 NAT 后面;host network 能避免 Docker bridge 额外的一层转发。
31+
network_mode: host
32+
volumes:
33+
- tailscale-socket:/var/run/tailscale:ro
34+
# manual cert 模式会在 certdir 中查找 <hostname>.crt/.key;IP-only 且文件缺失时会自动生成自签证书。
35+
- ${DERP_CERTS_DIR:-./certs}:/var/lib/derper/certs
36+
command:
37+
- --hostname=${DERP_PUBLIC_IP:?set DERP_PUBLIC_IP in .env.local}
38+
- --a=:${DERP_PORT:-443}
39+
- --http-port=${DERP_HTTP_PORT:-80}
40+
- --stun-port=${DERP_STUN_PORT:-3478}
41+
- --verify-clients
42+
- --socket=/var/run/tailscale/tailscaled.sock
43+
- --certmode=manual
44+
- --certdir=/var/lib/derper/certs
45+
- --accept-connection-limit=${DERP_ACCEPT_CONNECTION_LIMIT:-32}
46+
- --accept-connection-burst=${DERP_ACCEPT_CONNECTION_BURST:-64}
47+
48+
volumes:
49+
tailscale-state:
50+
tailscale-socket:

0 commit comments

Comments
 (0)