无需域名,自建 Tailscale Derp 节点
信息
如果你家有公网 IPv6 网络环境,推荐参考 公网 IPv6 自建 Tailscale Derp 服务 一文。 使用一台低功耗设备,比如 x86 路由器、树莓派等,可以在家里搭建一个 Derp 服务,结合域名 DDNS 使用。 该文章使用的 Lucky 方案支持自动续签 SSL/TLS 证书,无需担心证书过期问题。
云服务器性价比太低,用不到 1000 元在家里搞了个服务器,采用的是 X99 寨板 + E5 2666v3 至强 CPU(功耗相对来说确实大,但可以接受)。 装了个 PVE 虚拟机,用来跑旁路由、黑群晖、容器应用和做一些奇奇怪怪的事情。 考虑到大部分时候都不在家,为了方便无公网环境下的服务器远程运维,所以需要用到虚拟专用网络(VPN)服务。 我选择了 Tailscale,因为它的配置简单,支持多平台,而且是基于 WireGuard 协议的。
实际上我还用了 Cloudflare Zero Trust 作为双保险,这里就不展开了。
Tailscale 是什么
说的简单点就是:一个虚拟局域网用的工具,无需像 frp 那样配置复杂的端口映射,非常适合个人使用。 另外还提供了开源版本的 Headscale,可以自建 Tailscale 服务。
使用情境:SSH 远程开发、家庭 NAS 远程访问、远程桌面、远程监控等。
设置群晖的 Tailscle 套件
我家的网络拓扑很简单,主从光猫只负责提供 Wi-Fi 和 IPTV 信号,其它网络统一由路由器 AX82U 负责。 这样不论我怎么折腾路由器下的子网,都不会影响家人的网络使用。 我原本在 AX82U 路由器上安装了 Tailscale, 负责宣告家中子网的路由,但 AX82U 经常因此宕机出现 Tailscale 进程挂掉的情况(估计硬件性能不够)。 现在宣告子路由任务由黑群晖的 Tailscale 社区套件完成,只需要在群晖的 /etc/sysctl.conf
配置文件添加如下两行:
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
Root 权限执下面的命令,开启 Tailscale 宣告子路由和作为出口节点的功能:
sysctl -p /etc/sysctl.conf
/var/packages/Tailscale/target/bin/tailscale configure-host
synosystemctl restart pkgctl-Tailscale.service
/var/packages/Tailscale/target/bin/tailscale up --advertise-routes=192.168.50.0/24 --advertise-exit-node --reset
上面的 192.168.50.0/24
即是家中的子网网段,你可以根据自己的网络环境进行修改。
在满足一定条件(比如双方都拥有公网 IPV6 地址)的情况下, Tailscale 负责打洞实现 P2P 直连,否则将走官方提供的中转节点(称为 Derp 服务器)。 但是大部分情况下,官方的 Derp 服务延迟很高(最近的是 HongKong 和 Tokyo 节点), 实际体验下来,除最简单的 SSH 基本处于不可用状态,此时就需要一个自建 Derp 中转服务。
自建 Derp 节点服务
通常自建 Derp 服务需要一个公网服务器,并配置好域名和 SSL 证书。 这里我们对 Derp 官方的 GO 源码稍做改动,实现无需域名,直接通过公网服务器的 IP 地址来访问 Derp 服务。
安装 GO 环境(步骤略),然后获取 Derper 源码:
git clone https://github.com/tailscale/tailscale.git --depth=1
绕过 ServerName 域名检查
进入到刚刚获取的 tailscale/cmd/derper
目录。
Hack 源码,修改 cert.go
文件中的 getCertificate
函数:
func (m *manualCertManager) getCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
if hi.ServerName != m.hostname {
return nil, fmt.Errorf("cert mismatch with hostname: %q", hi.ServerName)
}
// Return a shallow copy of the cert so the caller can append to its
// Certificate field.
certCopy := new(tls.Certificate)
*certCopy = *m.cert
certCopy.Certificate = certCopy.Certificate[:len(certCopy.Certificate):len(certCopy.Certificate)]
return certCopy, nil
}
编译这个改动过的 Derper, 并将二进制文件放到 /usr/local/bin/derper
:
go build -o /usr/local/bin/derper .
配置 SSL 证书
使用 OpenSSL 配置 SSL 证书:
mkdir /usr/local/.ssl
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-keyout /usr/local/.ssl/derp.test.com.key \
-out /usr/local/.ssl/derp.test.com.crt \
-subj "/CN=derp.test.com" \
-addext "subjectAltName=DNS:derp.test.com"
其中的 derp.test.com
是你的 Derp 服务域名,可以自行替换成任意域名。
配置 Derp 服务
编辑 /etc/systemd/system/derp.service
文件:
[Unit]
Description=TS Derper
After=network.target
Wants=network.target
[Service]
User=root
Restart=always
ExecStart=/usr/local/bin/derper -hostname derp.test.com -a :12345 -certmode manual -certdir /usr/local/.ssl
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target
注意检查自建 Derp 服务器上的防火墙设置,放行相关端口(在上面的例子中是 12345
)。
启用并启动 Derp 服务:
systemctl enable derp
systemctl start derp
systemctl status derp
访问 IP:12345 这个地址看是否生效,会看到一个 Derp 相关的网页。
配置 Tailscale
在 Tailscale 控制台管理界面 Access Control 中配置 Derp 服务的地址:
"derpMap": {
//"OmitDefaultRegions": true,
"Regions": {
"912": {
"RegionID": 912,
"RegionCode": "AliYun",
"RegionName": "AliYun Derper",
"Nodes": [
{
"Name": "AliYun",
"RegionID": 912,
"DERPPort": 12345, // 更换为自己的端口号
"IPv4": "127.0.0.1", // 更换为自己的 IP 地址
"InsecureForTests": true, // 允许非 SSL 连接
},
],
},
"1": null,
"2": null,
"3": null,
"4": null,
"5": null,
"6": null,
"7": null,
"8": null,
"9": null,
"10": null,
"11": null,
"12": null,
"13": null,
"14": null,
"15": null,
"16": null,
"17": null,
"18": null,
"19": null,
//"20": null,
"21": null,
"22": null,
"23": null,
"24": null,
"25": null,
},
},
其中强制覆盖了 Tailscale 官方的 25 个 默认 Derp 节点 (除了 20 号代表的香港节点,这样自建 Derp 服务不可用的时候可以救急)。
使用 Tailscale 客户端连接,命令行输入 tailscale netcheck
检查 Derp 服务是否生效:
Report:
* UDP: true
* IPv4: yes,
* IPv6: yes,
* MappingVariesByDestIP: false
* HairPinning: false
* PortMapping: UPnP, NAT-PMP, PCP
* CaptivePortal: false
* Nearest DERP: AliYun Derper
* DERP latency:
- AliYun: 13.5ms (AliYun Derper)
- hkg: 151.9ms (Hong Kong)