公网 IPv6 自建 Tailscale DERP 服务
警告
这不是一篇面向纯小白用户的文章,省略了一些细节,需要对网络运维知识有一定了解。
一年前写了篇 无需域名,自建 Tailscale DERP 节点, 缺点是需要一台公网服务器,且众所周知云服务器的带宽给的都很小,不适合做中转服务。 现在我家的网络环境有了公网 IPv6 地址,所以可以考虑在家里自建一个 DERP 服务(当然这个节点只推荐自己使用)。
- 网络环境:G7615v2 光猫 IPv6 入站开启, 下接路由器 AX82U 开启 IPv6 Pass-Through,家中网络设备都能获取到公网 IPv6 地址。 注意光猫没有改桥接,其自带的 Wi-Fi 和 IPTV 功能给家里人正常使用,我只折腾路由器下的有线子网(连接各个卧室)。
- 硬件设备:存算分离,NAS、PVE 机和 J1900 工控机都通过 AX82U 的 LAN 口连接到我卧室的交换机上。 这台 J1900 工控机是本文的主角, 刷了 DHDAXCW 的 x86 ImmortalWRT, 作为家中的旁路由器,负责跑一些 24 小时开机的 Docker 服务。
- 域名解析:阿里云买的 cn 域名,使用 Cloudflare 的 DNS 服务。
推荐工具:Lucky 大吉
家宽通常给动态公网 IPv6 地址,平均几天就会变一次,所以需要一个动态 DNS 服务, 将 IPv6 地址映射到指定的域名上,这里推荐使用 Lucky 大吉。 对于本文要提到的 DERP 节点,我还会使用 Lucky 自带的 SSL/TLS 证书功能为相应的域名生成证书。 在骷髅头 DHDAXCW 最新固件中已经预装了 Lucky,且可以通过 iStore 更新到最新版本。 基本上安装了 Lucky 大吉版本后,常见的网络服务都可以通过图形界面配置,非常适合小白用户使用。
动态域名:域名列表两行,分别是
openwrt.example.cn
和*.openwrt.example.cn
.SSL/TLS 证书:注意 Cloudflare 官方提供的证书仅限回源,无法在公网访问时使用, 所以我们需要手动申请免费的可信证书,我选择的证书颁发机构是 FreeSSL, 参考配置如下:
- 证书备注:
_.openwrt.example.cn
- 添加方式:ACME
- 证书颁发机构:FreeSSL(使用和 Cloudflare 账户一样的邮箱账号)
- EAB 认证:启用(在 FreeSSL 自动化的 管理 页面获取参数)
- 验证方式:Cloudflare(使用与动态域名配置一致的 Token 和域名列表)
- 证书映射:启用,路径设置成
/opt/cert
目录(可根据你的需求修改), 且添加证书更新后的触发脚本python3 /opt/cert/update.py
, 需添加的代码如下:
pythonimport os import shutil def update_certificates(source_dir, target_dir, old_prefix, new_prefix): """ 更新证书文件后 Hook 调用,将其复制到目标目录,同时重命名文件。 :param source_dir: 源目录,包含原始证书文件 :param target_dir: 目标目录,用于存放更新后的证书文件 :param old_prefix: 旧前缀,用于匹配需要更新的文件 :param new_prefix: 新前缀,用于替换旧前缀 """ if not os.path.exists(target_dir): os.makedirs(target_dir) for filename in os.listdir(source_dir): if old_prefix in filename: new_filename = filename.replace(old_prefix, new_prefix) source_file = os.path.join(source_dir, filename) target_file = os.path.join(target_dir, new_filename) shutil.copy(source_file, target_file) print(f"Copied and renamed {source_file} to {target_file}") def main(): SOURCE_DIR = "/opt/cert" domains = [ {"old_prefix": "_", "new_prefix": "derper"}, # {"old_prefix": "_", "new_prefix": "another_domain"}, ] for domain in domains: old_prefix = domain["old_prefix"] new_prefix = domain["new_prefix"] target_dir = os.path.join(SOURCE_DIR, new_prefix) update_certificates(SOURCE_DIR, target_dir, old_prefix, new_prefix) if __name__ == "__main__": main()
这个
update.py
脚本后续可进一步维护,毕竟内网可能不止有 DERP 一个服务需要用到本地证书路径。 我们完全借助 Lucky 来帮我们完成证书续签,这样就不用担心证书过期了。 你可以根据你的需要添加 WebHook 通知。- 证书备注:
Web 服务:这一步仅仅是借助 Lucky Web UI 来验证上面配置的 SSL 证书是否能正常使用
- 添加 Web 服务器规则:监听 tcp6 和 2333 端口,开启 TLS 和防火墙自动放行
- 添加子规则:名称为
lucky
, 类型选择 “反向代理”, 前端地址lucky.openwrt.example.cn
, 后端地址http://127.0.0.1:16601
, 其他不用动 - 使用任意浏览器访问
https://lucky.openwrt.example.cn:2333
进行测试 - 同理你还可以添加其他子规则来反向代理内网其它 WEB 服务。
到这里 Lucky 部分的配置就完成了,接下来我们开始搭建 DERP 服务。
自建 DERP 服务
我的 OpenWrt 固件支持 Docker, 我选择使用 fredliang44/derper-docker
来简化部署:
docker run \
-e DERP_DOMAIN=derper.openwrt.example.cn \
-e DERP_CERT_MODE=manual \
-v /opt/cert/derper:/app/certs \
-p 30080:80 \
-p 30443:443 \
-p 3478:3478/udp \
fredliang/derper
其中 80 是 HTTP 端口,443 是 HTTPS 端口(也是 DERP 端口),3478 是 STUN 端口。 开放 STUN 端口可以支持在运行 tailscale netcheck
命令时检测延迟, 也借此来确定 Tailscale 客户端的公共 IP 地址及其 NAT 类型,尝试进行 NAT 穿透直连。
部署后访问 https://derper.openwrt.example.cn:30443
看到 Web 界面即表示部署成功。
添加 DERP 节点
在 Tailscale 的 Access Controls 界面中,如下添加:
// Example/default ACLs for unrestricted connections.
{
// ...
"derpMap": {
"OmitDefaultRegions": true, // 禁用默认 DERP 节点,只使用自建 DERP 节点
"Regions": {
"900": {
"RegionID": 900,
"RegionCode": "HOME",
"RegionName": "Homehub Derper",
"Nodes": [
{
"Name": "OpenWrt",
"RegionID": 900,
"HostName": "derper.openwrt.example.cn",
"DERPPort": 30443,
"STUNPort": 3478,
},
],
},
},
},
// ...
}
Tailscale 客户端重新连接后,命令行输入 tailscale netcheck
检查 DERP 服务是否生效。
添加客户端验证(可选)
以上的配置是不验证客户端的,适合好朋友们共用你的 DERP 节点。如果需要对客户端进行验证防止滥用, 则在需要在运行 DERP 容器时额外添加环境变量 DERP_CLIENT_AUTH=true
:
docker run \
-e DERP_DOMAIN=derper.openwrt.example.cn \
-e DERP_CERT_MODE=manual \
-e DERP_CLIENT_AUTH=true \
-v /opt/cert/derper:/app/certs \
-v /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock \
-p 30080:80 \
-p 30443:443 \
-p 3478:3478/udp \
fredliang/derper
这就要求你在安装了 DERP 的节点上,另外安装并登录 tailscaled
实例进行验证。 我在自己的 OpenWrt 机器上没有开启这个功能,因为担心 Tailscale 会把 iptables 改得很乱。
根据 官网文档 的说明:
The Personal plan allows for 3 free users in a single Tailscale network, known as a tailnet. You can also share devices with other users with node sharing. For more information on what is included in the Personal plan, see the Pricing page.
开启验证后,免费套餐最多可以使用 3 个用户来共享你的 DERP 服务。
参考材料/推荐阅读
- Lucky: 家用软硬路由公网利器 [TG 群]
- Tailscale: How it works / NAT 穿透是如何工作的:技术原理及企业级实践
- Custom DERP Servers 官方自建文档,一手资料 👍
- derper-docker: Tailscale's selfhosted derp-server docker image