Headscale 部署和 DERP 服务器配置
如何连接公司、家里服务器、公网服务器是一个经常被讨论的问题。一直通过 WireGuard 组网作为核心方式、ZeroTier 作为备用方式。WireGuard 的配置和使用比较复杂但是网络链路清晰,而 ZeroTier 可以保证 WireGuard 链路异常的时候作为备用方式连接网络,通过自定义 Moon 服务器可以提高速度和稳定性。
基于 WireGuard 的 Tailscale 很好的解决了 WireGuard 的配置问题,但是需要依赖 Tailscale 的控制和中继服务器。Headscale 是开源的 Tailscale 控制服务器,摆脱了 Tailscale 的控制,而且相比 ZeroTier 可以更简单的自定义控制服务器和中继服务器,所以使用 Headscale 配置另一个备用网络。
使用 Docker 部署 Headscale
因为控制节点和中继节点都在国内,不打算备案所以无法使用域名,所以无论控制节点还是中继节点都使用 IP 地址的方式。
参考文档 https://github.com/juanfont/headscale/blob/main/docs/running-headscale-container.md
cd /home/ubuntu
mkdir -p ./headscale/config
cd ./headscale
touch ./config/db.sqlite
wget -O ./config/config.yaml https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml
# vim config/config.yaml 修改里面的 server_url 为服务器的 IP 地址和端口,需要在服务器上开放对应端口
# 假设配置的 server_url 为 http://11.22.33.44:8030/ ,后面会继续用到
# 启动容器
docker run \
--name headscale \
--detach \
--restart always \
--volume /home/ubuntu/headscale/config:/etc/headscale/ \
--publish 0.0.0.0:8030:8030 \
--publish 127.0.0.1:9090:9090 \
headscale/headscale:0.21 \
headscale serve
# 查看统计信息
curl http://127.0.0.1:9090/metrics
# 创建用户
docker exec headscale \
headscale users create phyng
macOS 配置
Tailscale 的客户端配置比 WireGuard 简单,Headscale 稍微麻烦一点,总之就是找到自定义服务端地址的方法,然后生成 nodekey 到服务端注册即可,或者服务端预先生成 authkey,然后直接使用 authkey 登录。
# 安装
brew install --cask tailscale
# 客户端登录
tailscale up --login-server http://11.22.33.44:8030 --force-reauth
# 前往服务器确认登录
docker exec headscale \
headscale nodes register --user phyng --key nodekey:******
Linux/Ubuntu 配置
# https://tailscale.com/download/linux
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --login-server http://11.22.33.44:8030 --force-reauth
# 前往服务器确认登录
docker exec headscale \
headscale nodes register --user phyng --key nodekey:******
Windows 配置
参考文档 https://github.com/juanfont/headscale/blob/main/docs/windows-client.md 修改注册表配置
# 以管理员身份打开 PowerShell 执行注册表修改,或者通过注册表编辑器修改
New-ItemProperty -Path 'HKLM:\Software\Tailscale IPN' -Name UnattendedMode -PropertyType String -Value always
New-ItemProperty -Path 'HKLM:\Software\Tailscale IPN' -Name LoginURL -PropertyType String -Value http://11.22.33.44:8030
修改后启动 Tailscale,会显示登录页面,找到 nodekey:xxxxx,然后在服务器上执行
# 前往服务器确认登录
docker exec headscale \
headscale nodes register --user phyng --key nodekey:******
群晖 Synology 配置
群晖可以通过 authkey 登录,不需要 nodekey
# 应用中心安装 Tailscale
# 服务端生成 authkey
docker exec headscale \
headscale --user phyng preauthkeys create --reusable --expiration 24h
# 进入群晖终端,使用 authkey 登录
tailscale up --reset --login-server http://11.22.33.44:8030 --authkey ****** --force-reauth
iPhone 配置
新版 Tailscale 已经支持自定义服务器地址了,用非国区账号下载 Tailscale,在系统设置找到 Tailscale,输入服务器地址,打开 App 会弹出登录页面显示 nodekey:xxxxx,然后在服务器上执行命令即可。
docker exec headscale \
headscale nodes register --user phyng --key nodekey:******
DERP 中继服务器配置
因为备案的问题,这里使用纯 IP 实现,参考文档 https://icloudnative.io/posts/custom-derp-servers/#使用纯-ip
docker run --restart always --net host --name derper -d ghcr.io/yangchuansheng/ip_derper
创建一个 DERP 配置的 JSON 文件,可以上传到任意可以公开访问的地方,然后在 config.yaml
中填写对应的 URL 即可。中继服务器可以和控制节点在同一台服务器上,也可以是不同的服务器。
{
"Regions": {
"901": {
"RegionID": 901,
"RegionCode": "sh2",
"RegionName": "Shanghai-2",
"Nodes": [
{
"Name": "901a",
"RegionID": 901,
"DERPPort": 443,
"HostName": "11.22.33.44",
"IPv4": "11.22.33.44",
"InsecureForTests": true
}
]
}
}
}
下面是一个修改后的 config.yaml
,不完整版本,但是显示了全部相比默认配置修改的地方,仅供参考。
---
# 填写自己的 IP 地址和端口,自定义端口为 8030,可以换成别的
server_url: http://11.22.33.44:8030
listen_addr: 0.0.0.0:8030
metrics_listen_addr: 0.0.0.0:9090
# IPV4 在前
ip_prefixes:
- 100.64.0.0/10
- fd7a:115c:a1e0::/48
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
urls:
# 填写自己的 DERP 配置文件地址
- https://***.aliyuncs.com/derp.json
paths: []
auto_update_enabled: true
update_frequency: 24h
IP 显示优化
Headscale 默认配置文件 ip_prefixes 默认是 IPV6 在前,这样导致添加机器后运行 tailscale status
默认显示 IPV6 地址,而不是 IPV4 地址,不是很方便。
➜ tailscale status
fd7a:115c:a1e0::1 x*** phyng macOS -
fd7a:115c:a1e0::4 xx*** phyng linux active; relay "***", tx 97124 rx 79692
100.64.0.5 xxx*** phyng iOS offline
100.64.0.2 xxxx*** phyng linux idle, tx 195700 rx 419468
这是因为前述 config.yaml
中的配置默认 IPV6 在前:
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
如果刚配置还没有添加机器。可以修改这个配置,把 IPV4 放在前面即可。
ip_prefixes:
- 100.64.0.0/10
- fd7a:115c:a1e0::/48
但是如果已经添加过机器,修改配置之后只能保证新的机器默认显示 IPV4 地址,已经添加的机器还是会显示 IPV6 地址,这样 tailscale status
输出的结果无法对齐。这种情况可以直接修改 sqlite3 数据库文件。
# Ubuntu/Debian 安装 sqlite3
sudo apt install sqlite3
# 进入 sqlite3 数据库
sqlite3 config/db.sqlite
进入之后通过分析发现机器数据存储在 machines
表里面,ip_addresses 字段存储的是 IP 地址,以逗号分隔,根据分析结果可以直接修改。
-- 设置显示模式
.mode column
.headers on
-- 查看全部机器配置
select * from machines;
-- 查看 machines 表里面的 IP 配置
select id, ip_addresses from machines;
-- 调换 ip_addresses 的顺序让 IPV4 靠前
update machines set ip_addresses = '100.64.0.2,fd7a:115c:a1e0::2' where ip_addresses = 'fd7a:115c:a1e0::2,100.64.0.2';
update machines set ip_addresses = '100.64.0.3,fd7a:115c:a1e0::3' where ip_addresses = 'fd7a:115c:a1e0::3,100.64.0.3';
update machines set ip_addresses = '100.64.0.4,fd7a:115c:a1e0::4' where ip_addresses = 'fd7a:115c:a1e0::4,100.64.0.4';
update machines set ip_addresses = '100.64.0.1,fd7a:115c:a1e0::1' where ip_addresses = 'fd7a:115c:a1e0::1,100.64.0.1';
-- 退出数据库编辑
.quit
实际测试发现,Headscale 应该会从 sqlite3 刷新数据同步到机器,要快速生效的话可以直接重启 headscale 让它从数据库读取最新的数据,这样所有客户端运行 tailscale status 的时候默认看到的就是最新的 IPV4 了。
docker restart headscale