> 适用于阿里云 ECS / 静态公网 IP / 无域名场景
> 基于茗泽实战经验总结(2026-04-15)——解决了"设备之间无法互通"的根本问题
InsecureForTests: true,跳过静态 IP 自签名证书校验tailscale debug derp、tailscale netcheck、journalctl 三件套# 使用 paramiko 连接 ECS
client.connect(host=ecs_ip, port=22, username='root', password=ecs_password)
# 1. 解锁 DNS 配置(阿里云镜像常带不可修改属性,导致 Tailscale 无法配置 DNS)
chattr -i /etc/resolv.conf
# 2. 如果 Tailscale 日志报错 operation not permitted,执行上面这步后重启:
systemctl restart tailscaled
# 1. 开启 IP 转发(解决"无法访问其他 Tailscale 设备"的核心)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
sysctl -p
# 2. 关闭反向路径过滤(阿里云镜像常因这个设置导致 tailscale0 丢包)
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.default.rp_filter=0
sysctl -p
# 使用阿里云镜像(国内服务器必用)
wget https://mirrors.aliyun.com/go/go1.22.5.linux-amd64.tar.gz -O /tmp/go.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
export PATH=$PATH:/usr/local/go/bin && go version
mkdir -p /opt/derper
git clone --depth=1 https://github.com/tailscale/tailscale.git /opt/derper/tailscale
cd /opt/derper/tailscale/cmd/derper
export PATH=$PATH:/usr/local/go/bin
export GOPROXY=https://goproxy.cn,direct
go build -o /opt/derper/derper .
> ⚠️ Go 1.26+ 要求证书必须包含 SAN(Subject Alternative Name),CN 或 SAN 中必须有客户端连接的 IP 地址。
mkdir -p /opt/derper/certs
# 生成 OpenSSL 配置文件
cat > /tmp/derper.cnf << 'EOF'
[req]
default_bits = 4096
prompt = no
default_md = sha256
x509_extensions = v3_ca
distinguished_name = req_dn
[req_dn]
CN = <ECS公网IP>
[v3_ca]
subjectAltName = @alt_names
[alt_names]
DNS.1 = <ECS公网IP>
IP.1 = <ECS公网IP>
EOF
# 生成证书(CN = IP,SAN 含 IP)
openssl req -x509 -newkey rsa:4096 \
-keyout /opt/derper/certs/<ECS公网IP>.key \
-out /opt/derper/certs/<ECS公网IP>.crt \
-days 3650 -nodes -config /tmp/derper.cnf
chmod 600 /opt/derper/certs/<ECS公网IP>.key
chmod 644 /opt/derper/certs/<ECS公网IP>.crt
cat > /etc/systemd/system/derper.service << 'EOF'
[Unit]
Description=Tailscale DERP Relay Server
After=network.target
[Service]
Type=simple
ExecStart=/opt/derper/derper \
-hostname <ECS公网IP> \
-a :443 \
-http-port -1 \
-stun \
-certmode manual \
-certdir /opt/derper/certs
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable derper
systemctl start derper
> ⚠️ 三个核心参数:
> - -http-port -1:禁用 HTTP(80端口),防止无域名环境下启动冲突
> - -certmode manual:手动证书模式
> - -hostname 必须设为 ECS 公网 IP
这是茗泽实战发现的最关键修复:阿里云服务器访问自身公网 IP 时,流量被网关拦截,需要用 iptables DNAT 将流量强制转发到本地回环。
# 将发往公网IP:443的流量拦截并转发到本地 127.0.0.1
# 请将 <Your_Public_IP> 替换为你的真实阿里云公网 IP
iptables -t nat -A OUTPUT -d <Your_Public_IP> -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:443
> 💡 如果没有这步,服务器作为 Tailscale 节点尝试连接自己的 DERP 时会一直 Timeout
登录 admin.tailscale.com → Access Control,在 JSON 中加入自定义 DERP 区域。
"derpMap": {
"OmitDefaultRegions": false,
"Regions": {
"900": {
"RegionID": 900,
"RegionCode": "aliyun-ip",
"RegionName": "Aliyun ECS(青岛)",
"Nodes": [
{
"Name": "1a",
"RegionID": 900,
"HostName": "<ECS公网IP>",
"IPv4": "<ECS公网IP>",
"DERPPort": 443,
"STUNPort": 3478,
"STUNOnly": false,
"InsecureForTests": true
}
]
}
}
}
> ⚠️ InsecureForTests: true 是必须项,告诉 Tailscale 客户端信任静态 IP 的自签名证书
Tailscale 默认使用自定义路由表 52(不写在 main 表里),如果路由丢失,peer 之间会完全不通。
# 检查 Tailscale 专用路由表
ip route show table 52
# 如果为空,手动注入路由(最暴力的正确解法)
ip route add 100.64.0.0/10 dev tailscale0
# 检查 ip rule 规则(正常应包含 "from all lookup 52")
ip rule show
# 如果规则丢失,手动添加
ip rule add from all lookup 52
# 强制 Tailscale 重新接管路由
tailscale up --accept-routes --snat-subnet-routes=false --reset
systemctl restart tailscaled
sleep 5
tailscale status
> 任何 Tailscale DERP 问题,先执行这三个命令,按顺序层层缩小范围:
# ① 查看节点状态——判断服务器与 peer 的连通性
tailscale status
# ② 查看 derper 启动参数——确认进程是否以正确参数运行
ps -ef | grep derper
# ③ DERP 连接日志——判断 TLS 握手 / 证书校验是否通过
tailscale debug derp 900
三命令结果判断:
| 结果 | 指向问题 | |
|---|---|---|
| --- | --- | |
tailscale status 看不到 peer 或显示 offline | Tailscale 节点未注册 / 路由丢失 | |
| `ps -ef | grep derper 没有输出或参数缺少 -http-port -1` | derper 启动参数错误 |
tailscale debug derp 900 报 x509 / certificate 错误 | 证书校验失败 → 检查 ACL 的 InsecureForTests: true | |
tailscale debug derp 900 报 timeout | Hairpin NAT 未解决 或 安全组未开放 | |
| 三条全部 pass | 问题在上层路由 → 检查 ip route show table 52 |
| 检查项 | 命令 | 期望结果 | |
|---|---|---|---|
| --- | --- | --- | |
| derper 进程运行中 | pgrep -f derper | 有 PID | |
| 443 端口监听 | `ss -tlnp \ | grep ':443'` | LISTEN |
| STUN 3478 监听 | `ss -ulnp \ | grep ':3478'` | 有 UDP |
| systemd enabled | systemctl is-enabled derper | enabled | |
| 本地 DERP 可达 | curl -k https://127.0.0.1:443 | 返回 DERP 页面 | |
| TLS 握手成功 | tailscale debug derp 900 | HTTP 200 / pong | |
| DERP 延迟正常 | tailscale netcheck | aliyun 有延迟值(非 offline) | |
| peer 互通 | tailscale ping | 有响应 |
# 1. DERP TLS 握手诊断——看证书校验是否通过
tailscale debug derp 900
# 2. 网络连通性诊断——看 UDP 和 DERP 延迟
tailscale netcheck
# 3. Tailscale 日志——看具体报错
journalctl -u tailscaled --no-pager -n 30 | tail -20
| 错误现象 | 根因 | 解决方法 |
|---|---|---|
| --- | --- | --- |
x509: certificate is valid for ali-ecs, | ACL 里 CertName 与 derper 实际证书不匹配 | InsecureForTests: true 加到 ACL |
tailscale ping timeout,但 tailscale status 能看到 peer | 内核路由丢失 | ip route add 100.64.0.0/10 dev tailscale0 |
| 服务器自己 curl -k 公网IP 失败 | Hairpin NAT | iptables DNAT 规则 |
tailscale debug derp 报 certificate signed by unknown authority | InsecureForTests: true 未生效 | 重启 tailscaled + tailscale up --reset |
ping timeout,但 tailscale ping 正常 | 内核转发问题 | 开启 net.ipv4.ip_forward |
启动报错 bind: address already in use | 端口 443 被占用或 derper 重启循环 | pkill -9 derper && systemctl restart derper |
operation not permitted(resolv.conf) | 文件被加上了不可修改属性 | chattr -i /etc/resolv.conf |
| 阿里云安全组规则全开了但 UDP 不通 | 云平台 UDP 防护 | 确认阿里云 UDP 41641/3478 入站规则 |
| 端口 | 协议 | 用途 |
|---|---|---|
| --- | --- | --- |
| 443 | TCP | DERP 主端口(必须) |
| 3478 | UDP | STUN 端口(必须) |
| 41641 | UDP | Tailscale WireGuard 端口(建议) |
部署完成后,汇报:
✅ DERP 中继服务器部署完成
服务器:<公网IP>:443
DERP Region:900
STUN:<公网IP>:3478/UDP
验证结果:
- [✅] derper 进程运行中
- [✅] 端口 443/TCP 监听
- [✅] 端口 3478/UDP 监听
- [✅] 证书含 SAN(CN = IP)
- [✅] Hairpin NAT DNAT 规则已添加
- [✅] Tailscale 路由表 52 已验证
- [✅] 开机自启 enabled
- [✅] tailscale debug derp 900 → HTTP 200
ACL 待生效:
- InsecureForTests: true(保存后重启 tailscaled 使其生效)
<类型> 替代<真实IP> → 共 1 个版本