在上一篇文章中,我介绍了 Tailscale 的搭建方法,同时说明了选择 Tailscale 的原因。在这篇文章中,如标题所示,我将介绍两个 Tailscale 的进阶玩法。
Subnet routes(子网路由)
假设你有好几台设备,上边都部署了一些服务。这些设备在同一个局域网内,你希望你在外网时可以访问在这些设备上的服务。正常情况下,我们需要在每一台设备上都安装 Tailscale 客户端,才能实现这样的需求。我们注意到,这些设备都在同一局域网(网段)下,因此我们可以使用 Tailscale 自带的 subnet routes 来优化我们的组网。
Subnet routes 的官方文章 太长不看版:Subnet routes(子网路由)是通过 Tailscale 连接远程网络(子网)的方法。配置 subnet routes 后,设备可以通过 Tailscale VPN 访问其他设备所在的本地网络,无需直接连接。
假设我们的局域网配置如下图,局域网 IP 段为 192.168.1.0/24
,自己配置时请替换为实际 IP 段
我们可以将 Tailscale 安装在任意一个设备上,在成功加入 Tailscale 网络后,可以通过以下命令来添加子网
如果你用的路由器运行着 openwrt,那么可以参考 openwrt 的官方文章 来安装 Tailscale
sudo tailscale set --advertise-routes="192.168.1.0/24"
然后去 Tailscale 控制台,找到对应的设备,找到编辑路由设置
最后将刚刚添加的子网勾选并保存
现在 Tailscale 网络里的所有设备(配置为子网路由网关的设备除外)访问 192.168.1.0/24
这个网段的流量都会被路由到这个设备,这样便实现了子网路由
自建中转
前文说到,Tailscale 需要良好的 NAT 环境才能打洞成功并直连。但在部分情况下,Tailscale 无法成功打洞。在这种情况下,Tailscale 会选择使用 derp 来中转流量,也就是类似传统 VPN 的形式
你可以使用这个 python 工具来测试你所在的网络是什么 NAT 环境 基本上,我们需要在 P2P 连接中需要至少有一个客户端拥有 Full Cone NAT 或者更好的公网 IP 才能打洞成功
这并不是回退到 derp,Tailscale 会在一开始就使用 derp 来建立连接中转流量,并在打洞成功后使用 P2P 连接,这保证了 Tailscale 在各种网络环境下的可用性,同时加快了创建连接的速度
但是,Tailscale 在国内并没有并没有 derp 节点。而由于种种原因 我大清自有国情,这些在海外的节点的连接质量并不好。因此我们需要自建 derp 节点,来改善我们在两个客户端都没有良好 NAT 类型时的连接质量。
自建 derp 服务器有一个前提是拥有公网 IP 的服务器。准确的说,是拥有公网 IPv4 的服务器。并且需要暴露两个端口,分别用于提供 HTTPS 和 STUN 服务。
实际上,使用 NATv4 服务器来搭建 derp 服务器也是可行的,只不过需要修改所用的端口
按照官方的说明,derp 协议(全称 Detoured Encrypted Routing Protoco)是运行在 http 之上的,因此自建 derp 需要一个域名用于提供 https 服务。但不巧的是,在国内域名需要备案才能提供网站。所以我们可以采取 IP 直连的方式来建立和配置 derp 服务器,从而绕过域名备案。这个方法参考了这篇文章,并使用了文章作者构建的 docker 镜像。但请注意,IP 直连的部署方法并不不是官方推荐的方法
使用域名
由于我是懒人,不想申请并维护 SSL 证书,因此我使用 derp + caddy 反代来搭建 derp 服务器,这样的好处是可以在已经部署了 caddy 的服务器上快速搭建起 derp 服务,且可以使用标准 443 端口而无需修改端口
直接使用 docker compose 来部署:
services:
derper:
restart: always
ports:
- '3478:3478/udp' # STUN 端口
- '[derp-https-port]:[derp-https-port]/tcp' # https 端口
environment:
- DERP_DOMAIN=derp-us.wall-breaker-no4.xyz
- 'DERP_ADDR=:[derp-https-port]'
image: fredliang/derper
DERP_ADDR
环境变量中的:
不能去除
然后修改 Caddyfile,加入以下内容:
[your-domain] {
tls {
get_certificate Tailscale
}
reverse_proxy http://localhost:[derp-https-port]
}
请将
[derp-https-port]
和[your-domain]
替换为实际使用的端口和域名
访问你的域名,如果能访问以下页面则说明已经搭建成功了
访问 Tailscale 的 ACL 控制界面,这个控制文件实际上是个 json5 格式的文件。在 "derpMap"
块内添加以下内容:
// 前略
"derpMap": {
"OmitDefaultRegions": true, // 如果只想使用自建的 derp 结点的话,就启用这条配置
"Regions": {
"970": { // 区域 ID,在 900~999 之间选一个
"RegionID": 970, // 区域 ID,在 900~999 之间选一个
"RegionCode": "YourRegionCode", // 区域代码
"RegionName": "YourRegionName", // 区域名
"Nodes": [
{
"Name": "YourNodeName", // derp 节点名
"RegionID": 970, // 区域 ID,在 900~999 之间选一个
"HostName": "your-derp-domain", // 节点所用域名
"IPv4": "your-derp-ip" // 加快解析速度
}
]
}
// 如果有更多自建 derp 节点,在此添加,格式同上
}
}
在保存前建议将 ACL 控制文件用格式检查工具确认是否存在语法错误:在线 JSON5 验证
在任意安装了 Tailscale 的终端上执行以下命令:
Tailscale netcheck
如果配置正确,应该能看到类似以下的输出:
Report:
* Time: 2025-01-17T09:26:14.5408586Z
* UDP: true
* IPv4: yes, 114.xx.xx.xx:49768
* IPv6: no, but OS has support
* MappingVariesByDestIP: true
* PortMapping:
* CaptivePortal: false
* Nearest DERP: YourRegionName
* DERP latency:
- YourRegionCode: 38.7ms (YourRegionName)
IP 直连
由于官方的 derper 实现默认禁用了 IP 直连的方式,我们需要克隆官方仓库到本地,修改源代码并编译才能启用 IP 直连。具体方法可以参考这篇文章和 B 站上的这个视频。
同时,文章的作者已经编译好了修改后的 derper 并打包成了 docker 镜像,因此我们可以直接使用 docker compose 来部署:
services:
ip_derper:
restart: unless-stopped
ports:
- '[https-port]:443/tcp'
- '[STUN-port]:3478/udp'
container_name: derper
image: ghcr.io/yangchuansheng/ip_derper
请将
[https-port]
和[STUN-port]
替换为实际使用的端口
经测试,可以使用 NATv4 的服务器,只需要将
[https-port]
和[STUN-port]
这两个端口暴露到公网即可
同理,通过访问 https://[your-server's-ip]:[https-port]
,你也可以打开这个界面:
只不过由于 IP 直连的方式的证书是自签名的,打开时浏览器会提示不安全,无视即可
同样访问 Tailscale 的 ACL 控制界面并修改:
// 前略
"derpMap": {
"OmitDefaultRegions": true, // 如果只想使用自建的 derp 结点的话,就启用这条配置
"Regions": {
"970": { // 区域 ID,在 900~999 之间选一个
"RegionID": 970, // 区域 ID,在 900~999 之间选一个
"RegionCode": "YourRegionCode", // 区域代码
"RegionName": "YourRegionName", // 区域名
"Nodes": [
{
"Name": "YourNodeName", // derp 节点名
"RegionID": 970, // 区域 ID,在 900~999 之间选一个
"HostName": "your-derp-ip", // 节点所用 IP
"IPv4": "your-derp-ip", // 节点所用 IP
"DERPPort": [https-port], // 节点 Https 端口
"STUNPort": [STUN-port], // 节点 STUN 端口
"InsecureForTests": true // 必须启用这一条才能使用 IP 直连
}
]
}
// 如果有更多自建 derp 节点,在此添加,格式同上
}
}
在任意安装了 Tailscale 的终端上执行以下命令:
Tailscale netcheck
如果配置正确,应该能看到类似以下的输出:
Report:
* Time: 2025-01-17T09:26:14.5408586Z
* UDP: true
* IPv4: yes, 114.xx.xx.xx:49768
* IPv6: no, but OS has support
* MappingVariesByDestIP: true
* PortMapping:
* CaptivePortal: false
* Nearest DERP: YourRegionName
* DERP latency:
- YourRegionCode: 38.7ms (YourRegionName)
参考
- https://tailscale.com/kb/1019/subnets
- https://tailscale.com/kb/1118/custom-derp-servers
- https://openwrt.org/docs/guide-user/services/vpn/Tailscale/start
- https://pypi.org/project/yapystun/
- https://icloudnative.io/posts/custom-derp-servers/
- https://github.com/yangchuansheng/ip_derper
- https://www.bilibili.com/video/BV1WiWPeMErP