Headscale实现点对点直连异地组网

Headscale实现点对点直连异地组网

来源  https://luotianyi.vc/8480.html

 

Tailscale是一个与ZeroTier、Netbird等工具类似的异地组网工具,支持通过STUN打洞实现客户端点对点直连,互联协议基于go实现的WireGuard,兼具高效与安全的特性。

简单而言,Tailscale可以不受限于服务器带宽,使位于不同的网络环境下的设备获得类似于同一局域网下的体验。

Headscale是Tailscale的一个开源服务端,通过go语言完整地支持了绝大多数Tailscale的基础功能,使Tailscale能够完全工作于独立自建的服务端之上。近期恰逢Parsec受到干扰,对未来ZeroTier官方服务在大陆的稳定性有了一些担忧,于是研究了一下自建Headscale服务器的流程。整个过程都是手动安装,在此做一些简单的记录。

小提示:无论上述哪一种异地组网工具,官方均有商业化的服务器提供,并且有25设备的免费额度。官方服务器除国际链路导致的中继不够稳定外其他功能均可正常使用,因此轻度的使用博主并不推荐盲目自建服务器,请根据个人需求进行权衡,毕竟官方服务器+自建转发也是一种很好的选择。


原理概述

Tailscale服务器端分为两部分,包括负责通信与认证的Headscale服务器和负责打洞和转发的DERP服务器,其工作模式细节可以参考官方博客(点击前往)。以两台计算机为例,它们首先分别通过Tailscale客户端注册至Headscale服务器,在建立通信时先通过Headscale服务器交换握手信息,随后分配到合适的DERP服务器进行中继连接和STUN打洞。若打洞成功,两端将在Headscale服务器引导下绕过服务器建立点对点的直连隧道;若打洞失败,两端将保持通过DERP服务器中继的互联模式。

Tailscale、ZeroTier和Netbird都是功能相似的优秀异地组网工具,且均支持自建服务器。与ZeroTier相比,Tailscale功能更丰富、自建更为简便,同时WireGuard效率更高;缺点是Tailscale客户端资源占用略高(要求RAM>512M)。与Netbird相比,Tailscale起步较早实践资料和可用插件更多(如OpenWRT Luci-UI,点击前往),并且不强制要求独占80与443端口;缺点是WireGuard在go下性能略逊于内核态,同时Headscale并非Netbird一样由官方支持。权衡之下,博主认为Headscale是目前自建比较简单、易用的选择。


环境准备

Tailscale在端对端通信中会通过STUN打洞建立基于UDP的WireGuard通讯链路,虽然并不需要公网IP,但需要上级路由器开启upnp以允许UDP隧道建立和维持,流量穿透原理可以参考官方博客(点击前往)。在国内的家庭网络中,NAT类型主要为Full Cone(NAT1)、Port Restricted Cone(NAT3)和Symmetric(NAT4),打洞难度从依次递增,可以通过NatTypeTester这个工具(点击前往)进行测试。在博主实测中,办公室校园网(NAT3)与中国电信5G(NAT3)能够正常打洞直连,而办公室校园网(NAT3)与某园区网(NAT4)无法打洞直连,完全通过中继连接,只有对端为中国移动(NAT1)时成功打洞直连。

综合目前博主自己的测试结果,只要两端NAT类型在NAT3及以上,打洞直连对Tailscale而言并不困难;但若一端为NAT4,则除对端为NAT1外Tailscale均无法打通直连。NAT4即对称型NAT,是NAT四种类型中最为严格的一种,其从原理上阻止了打洞的可能性,因此Tailscale在这类网络下只能提供基于服务器中转的连接。在部署Tailscale前,应提前评估在个人使用场景中的可行性,并且尽量改善网络NAT类型(如开启upnp、设置DMZ主机、开启IPv6等)。因为博主对打洞的原理了解浅薄,这段文字可能并不严谨,欢迎补充和指正~

在优化点对点互联质量的方法中最为触手可得的就是IPv6,虽然部分地区的IPv4环境较为恶劣,但目前政府主导以去NAT化为目标部署的IPv6(点击前往)大大改善了这一现状。Headscale能够完整地支持IPv6服务,但需要DERP节点同样具有IPv6地址。如果自建的DERP节点不配置IPv6,只能通过官方的海外节点进行IPv6 STUN打洞。

腾讯云轻量应用服务器目前成都地域已全量开放IPv6支持,北京、上海已在国庆前开放内测,非常符合博主的需要。腾讯轻量IPv6无需额外付费,点击开启、简单易用(可以戳图片从博主之前的文章了解),并且工程师们也在积极地为目前诟病的IPv4-IPv6带宽包合并努力。博主此次就是将Headscale和其DERP搭建在了腾讯云双栈的轻量应用服务器上,国内的互联互通效果非常不错。若大家有类似的需求,可以随时到腾讯云官网选购轻量应用服务器,即开即用、方便快捷。


程序准备

我们用到的项目主要为本体Headscale(点击前往)和其WebUI之一的Headscale-admin(点击前往)。其中Headscale是一个go的二进制可执行文件,Headscale-admin是一个静态的网页程序,所以从博主的角度觉得直接配合NGINX本地运行比docker更为轻量简便。如果倾向于使用docker,可以按照它们的文档中提供的流程进行部署。

在此分享一个博主验证过自用的包,其内容与本文一致,供大家参考:

下载地址:蓝奏云

因为Headscale-admin本质上只是个静态站点,所有的请求均通过浏览器发起,所以在实际使用中只需要注意Headscale-admin页面与Headscale API之间跨域的问题即可。有一点需要注意,Headscale 0.23.0版本中将增加设备的nodekey字段改为了mkey,导致Headscale-admin中无法新建设备(详见issue),在分享的版本中博主对此进行了修改。


配置文件

标准化的安装和具体的参数解释请参考Headscale官网(点击前往)和Github(点击前往),在此不再赘述。以下是一个带有注释的完整headscale 0.23.0版本配置文件,从个人用户手动维护的角度出发,博主建议不遵循Linux社区的配置规范,将所有相关的文件安放于同一目录下(如配置中的/home/headscale目录),以便备份和迁移。

而在单机部署中,需要修改的内容主要如下:

① 第02行:Headscale服务域名
② 第15行、36行、69行:密钥和数据库路径
③ 第17行:虚拟局域网IP段
④ 第33行:DERP STUN服务端口
⑤ 第38行:DERP服务器IP
⑥ 第82行:虚拟局域网MagicDNS域名


用于引入其他自建DERP服务器的derp.yaml示例如下,请根据实际修改并在上方Headscale配置文件对应位置引入。

 


自启动配置

如下将文件路径修改正确后,在systemd目录下创建headscale.service,即可通过service headscale start|stop|restart管理进程状态,确认无误后使用systemctl enable headscale允许开机自启。因为是自用,博主直接使用root用户启动进程,若对安全有额外的需求请新建一个headscale用户进行运行。

 


NGINX配置

Headscale仅从/key/ts2021/derp/api四个路径进行数据交换,但鉴于官方并未明确说明,博主还是推荐对Headscale全局/路径进行反向代理。其中,要单独为headscale-admin静态站点进行排除和指向,若全局反向代理影响证书签发可使用相同的方法。

 


防火墙配置

在以上的配置中,Headscale进程启用了HTTP协议监听本地的主服务(8080)、Mertics(9090)和grpc(50443)三个端口,在需要时均可以通过NGINX转发至标准端口并绑定域名,无需单独对外放通。唯一需要额外放通的是转发服务DERP STUN的UDP端口3478端口(或设定的端口号),基本满足了简单、安全和与其他服务共存的需要。


若使用云服务器搭建,则要额外注意在安全组中放通IPv4和IPv6的端口(图中为腾讯云控制台)


客户端配置

按照博主的方法自建Headscale完成后,在运行命令时要先cd /home/headscale进入Headscale目录下,再通过./headscale执行命令,比如通过./headscale apikeys create --expiration 9999d创建一个9999天的密钥(默认为30天)。然后进入https://xxx.web/admin进入headscale管理页面,取消勾选Legacy API并填入API密钥即可登陆管理页面。注意,管理页面Headscale-admin所有信息均储存在本地浏览器中,且仅通过本地浏览器与API通讯,请在可信的设备上进行操作。

登陆成功后可以在Users中新建一个用户,随后即可向用户添加设备。在认证之前先可以通过Deploy页面勾选需要的功能生成指令,用于引导客户端登陆Headscale服务器并开启相应的功能。

电脑端可以从官网下载(点击前往),安装完成后使用配置好的命令直接cmd运行进行认证登陆即可,弹出的mkey则需要从Nodes页面Create设备,若使用PreAuthkey进行无交互认证则需先从Users下创建再进行选择。此外内网Advertise Routes网段在路由后,需要从Headscale-Admin的Routes页面进行放通以开放内网广播。以下是几个简单的实例:


手机端同样可以从Google Play或官网下载(点击前往),随后可以从右上角设置Accounts右上角菜单Alternate Server进入设置,其余操作大同小异。路由器端需要从OpenWRT源(点击前往)下载对应架构较新的最小化构建.ipk包,同时下载Luci App及语言包(点击前往)两个.ipk包,将三个文件置于路由器同一个文件夹下使用opkg install *安装即可。如果内存不宽裕,可以添加go的GOMEMLIMIT=100MiB环境变量,以约束Tailscale使用的内存。客户端的使用这部分网络上有大量的资料可供参考,三言两语很难说得清楚,在此不再过多赘述。

 

 

 

===================

使用 Headscale 的简单教程

来源 https://www.posase.im/posts/27c7162f/

 

讲在前面

Headscale 是 Tailscale 的开源版本,前者的免费使用有一定的限制,当然也能满足一般的需求
如果你不想折腾,也没有太多的需求,Tailscale 或许是更好的选择
另外这也是一篇基础教程,更多的使用请阅读官方文档

服务端

首先肯定需要把服务跑起来,只有一个要求,就是有公网 IP
另外推荐使用 Linux部署服务,Windows 的话可以试试 Docker 部署
文章服务端环境:Debian 11 腾讯云轻量应用服务器

一些准备工作

准备好一个域名,SSL 证书(可选)

BASH
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1. 下载二进制文件
# 注意替换版本号 和 硬件架构
wget --output-document=/usr/local/bin/headscale \
https://github.com/juanfont/headscale/releases/download/v0/headscale_0_linux_amd64
# 这里其实就是下载文件到 /usr/local/bin/headscale 目录
# 所以你也可以自己下载好文件,自己上传上去,比如你的服务器连接 github 困难的话

# 2. 添加执行权限
chmod +x /usr/local/bin/headscale

# 3. 准备一个目录放配置文件
mkdir -p /etc/headscale

# 4. 准备一个目录放数据库和其他文件
mkdir -p /var/lib/headscale

# 5. 创建数据库文件
touch /var/lib/headscale/db.sqlite

# 6. 创建配置文件
touch /etc/headscale/config.yaml
# 因为强烈建议使用示例文件进行修改,我们也可以直接下载改文件到 /etc/headscale
wget --output-document=/etc/headscale/config.yaml \
https://github.com/juanfont/headscale/raw/main/config-example.yaml
# 当然也可以复制我下面的配置修改后上传

修改配置文件

YAML
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# From: www.posase.im
# Author: Posase
# headscale 会查看 /etc/headscale/ 或者 ~/.headscale/ 下的 config.yaml 或 config.json
# 建议/必须修改的地方加* 端口都可以自行修改 部分内容来自机翻
# 移动了官方配置的部分位置,带问好的可能存疑,仅供参考,善用搜索

# Headscale Config
server_url: http://test.domain.com:8080 # *客户端连接地址 替换为自己域名
listen_addr: 0.0.0.0:8080 # 监听地址
metrics_listen_addr: 127.0.0.1:9090 # 监听 /metrics 的地址,希望将此端点保密到内部网络
grpc_listen_addr: 0.0.0.0:50443 # 监听 gRPC 地址 gRPC 用于 远程控制 headscale
grpc_allow_insecure: false # 允许在 INSECURE 模式下使用 gRPC 后台 不建议开启
private_key_path: /var/lib/headscale/private.key # 加密流量的私钥文件,会自动生成
ip_prefixes: # 用来分配 IP 地址的前缀
- fd7a:115c:a1e0::/48
- 100.64.0.0/10

# 其他设置
disable_check_updates: false # 开启时自动检查更新
ephemeral_node_inactivity_timeout: 30m # 离线节点过多久删除
log_level: info # 日志等级
acl_policy_path: "" # ACL 策略路径 https://tailscale.com/kb/1018/acls/

unix_socket: /var/run/headscale.sock # 用于 CLI 连接, 无需验证的 socket
unix_socket_permission: "0770"

# DERP Config
# DERP 中继服务器配置,当无法直接进行打洞,可以通过 中继服务器 转发流量连接
# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp
derp:
# 本地 DERP 配置
server:
enabled: true # *本机 DERP 开关,server_url 必须是 https 且 有 ssl 证书
region_id: 999 # 本机 DERP 服务的 地区id, 这个对于每一个 DERP 服务器来说是唯一的
region_code: "headscale" # 区域代码 这两个参数可以自定义
region_name: "Headscale Embedded DERP" # 区域名字
stun_listen_addr: "0.0.0.0:3478" # 监听需要转发的 UDP

# 外部 DERP 服务器配置 yaml 的列表形式
# key
# - xxxxx
# key: [xxx, xxx] 这样应该也可以把?
urls: []
# - https://controlplane.tailscale.com/derpmap/default # *不建议使用,国外节点很卡
paths: []
# - /etc/headscale/derp-example.yaml

# DERP 其他配置
auto_update_enabled: true # 定时更新中继服务器
update_frequency: 24h # 更新间隔

# 数据库配置
# SQLite config
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite

# # Postgres config
# db_type: postgres
# db_host: localhost
# db_port: 5432
# db_name: headscale
# db_user: foo
# db_pass: bar

# TLS configuration
# 会自动使用 Let's Encrypt 申请证书
acme_url: https://acme-v02.api.letsencrypt.org/directory # 申请脚本目录
acme_email: "xxx@mail.com" # 注册邮箱
tls_letsencrypt_hostname: "test.domain.com" # 申请的域名
# 客户端认证模式 disabled:不需要认证,relaxed:需要证书但不验证,enforced:需要证书且认证
tls_client_auth_mode: disabled
tls_letsencrypt_cache_dir: /var/lib/headscale/cache # 证书存放目录
# ACME 类型 More: https://github.com/juanfont/headscale/blob/main/docs/tls.md
tls_letsencrypt_challenge_type: HTTP-01
# 如果选择 HTTP-01 需要一个验证端口 :http=port 80
tls_letsencrypt_listen: ":http"

# 已经有证书了 添加自定义证书路径
tls_key_path: "/var/lib/headscale/cache/key.pem"
tls_cert_path: "/var/lib/headscale/cache/cert.pem"

## DNS Config
# 查看知识库以更好的理解这个功能
# - https://tailscale.com/kb/1054/dns/
# - https://tailscale.com/kb/1081/magicdns/
# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/
dns_config:
nameservers: # 向客户端公开的 DNS 列表 https://tailscale.com/kb/1054/dns/
- 1.1.1.1

# 每个域名使用不同的 DNS
# restricted_nameservers:
# foo.bar.com:
# - 1.1.1.1
# darp.headscale.net:
# - 1.1.1.1
# - 8.8.8.8

domains: [] # 需要使用 DNS 的域名?
magic_dns: false # *使用 MagicDns https://tailscale.com/kb/1081/magicdns/
base_domain: example.com # 定义基础域名以创建 MagicDns 主机名

启动

BASH
1
2
3
4
5
6
7
8
9

# 启动 服务
headscale serve

# 本地检测 需要另一个窗口
curl http://127.0.0.1:9090/metrics

# 成功的话 创建一个命名空间
headscale namespaces create myfirstnamespace

注意需要将服务器端口加入防火墙规则

连接服务器

需要先下载 Tailscale 下载地址

BASH
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Windows 需要添加环境变量 或者到安装目录下使用
# 有两种注册连接方式

# 1. 正常注册
# 客户端:替换为服务器的 server_url
# 这里推荐关闭 dns,有需求可以自己研究
tailscale up --login-server YOUR_HEADSCALE_URL --accept-dns=false

# 服务器:将返回的 key 在服务器中注册
headscale --namespace myfirstnamespace nodes register --key <YOU_+MACHINE_KEY>

# 2. 预注册
# 服务器:生成一个指定命名空间下可重复使用 24H 过期的 key
headscale --namespace myfirstnamespace \
preauthkeys create --reusable --expiration 24h

# 客户端: 使用生成的 key 可以直接注册连接
tailscale up --login-server <YOUR_HEADSCALE_URL> \
--authkey <YOUR_AUTH_KEY> --accept-dns=false

将 Headscale 注册为服务

创建 headscale 用户

BASH
1
2
useradd headscale -d /home/headscale -m         # 创建 headscale 用户
chown headscale:headscale /var/lib/headscale # 修改 /var/lib/headscale 拥有者

修改 config.yaml

YAML
1
unix_socket: /var/run/headscale/headscale.sock

添加 service

BASH
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# /etc/systemd/system/headscale.service
[Unit]
Description=headscale controller
After=syslog.target
After=network.target

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
Restart=always
RestartSec=5

# Optional security enhancements
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/headscale /var/run/headscale
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=headscale

[Install]
WantedBy=multi-user.target

启动服务

BASH
1
2
3
systemctl daemon-reload             # 重新加载 service
systemctl enable --now headscale # 设置开机自启并启动 headscale
systemctl status headscale # 查看状态

其他

一些简单的命令

BASH
1
2
3
4
5
6
headscale namespaces list   # 查看命名空间
headscale nodes list # 查看节点信息
headscale routes list -i 6 # 查看指定节点的路由

tailscale status # 查看节点状态
tailscale ping xx.xx.xx.xx # ping 指定内网地址 可以看是 p2p 还是 中转

子网路由

可能存在将整个局域网连接进去,需要添加子网路由

BASH
1
2
3
4
5
6
7
8
9
10
11
12
13
# 服务器设置 IPv4/Ipv6 路由转发
echo 'net.ipv4.ip_forward = 1' | tee /etc/sysctl.d/ipforwarding.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/ipforwarding.conf
sysctl -p /etc/sysctl.d/ipforwarding.conf

# 注册时候加入子网路由 注意改成自己的子网前缀
tailscale up --login-server YOUR_HEADSCALE_URL \
--accept-dns=false --advertise-routes=192.168.100.0/24

headscale nodes list # 查看节点 id
headscale routes list -i x # 查看指定节点的路由
headscale routes enable -i x -r "192.168.100.0/24" # 开启路由
headscale routes list -i x # 再次查看是 true

之后就可以 ping 到另一个子网的所有主机了

Docker 方式

BASH
1
2
3
4
5
6
7
8
9
docker run \
--name headscale \
--detach \
--rm \
--volume $(pwd):/etc/headscale/ \
--publish 0.0.0.0:8080:8080 \
--publish 127.0.0.1:9090:9090 \
headscale/headscale:0.15.0 \
headscale serve

参考

 

 

Tailscale按照默认配置的使用过程中很容易出现高延迟的问题,有时是节点与节点之间延迟很高,有时是节点与子网设备之间延迟很高,本文主要描述节点与子网设备之间的延迟问题。

节点:我们暂且把安装了Tailscale的机器称之为节点。

 

Tailscale安装配置此处不做赘述,按照官方文档配置即可,此处仅记录一些组网过程中的注意点,以提高网络访问速度,降低延迟。

1.首先按照官方文档配置子网路由 【Subnet routers】https://tailscale.com/kb/1019/subnets

2.在任意一台配置了Tailscale的机器上开放防火墙的41641端口,41641端口可用于Tailscale设备间直连,大幅降低延迟。(443端口和3478端口也需要开放,此处暂时不开放也可以,后面会有其他说明)

【Tailscale防火墙端口】https://tailscale.com/kb/1082/firewall-port

此时,在命令行中运行 tailscale status 或者 tailscale.exe status 可以看到有一台设备信息中有direct,代表直连。

此时,ping一下Tailscale提供的ip,延迟为个位数,已经很低了。但如果ping局域网内的其他设备,延迟应该在2000~3000ms,这个是比较难以接受的。

3.【重点来了】在安装了Tailscale并且做为子网路由的机器上,打开“高级安全 Windows Defender防火墙” 中的“出站规则”,添加Tailscale的出站端口,协议和端口中的协议类型选择“任何”,也就是说将Tailscale的所有端口全部放行。此时,再去ping Tailscale的子网设备就会发现,延迟是很低的,子网中的服务也是能够正常访问的。

 

========= End

 

posted @ 2024-11-20 18:21  lsgxeva  阅读(69)  评论(0编辑  收藏  举报