headscale私有部署

需求

  • 办公需求:
    设备:
    1、synology DS918+
    2、macbook pro m1
    3、mac mini
    问题:访问家里nas慢的问题,及工作效率能快速访问的问题

  • 公司跨机房需求:
    1、erp金蝶系统-sqlServer服务-公司内部机房
    2、采购系统-mongodb服务-阿里云服务器
    问题:采购系统上访问ERP速度慢的问题,及双流cdc的需求

设想这样一个问题:在北京和上海各有一台局域网的机器(例如一台是家里的台式机,一 台是连接到星巴克 WiFi 的笔记本),二者都是私网 IP 地址,但可以访问公网, 如何让这两台机器通信呢

既然二者都能访问公网,那最简单的方式当然是在公网上架设一个中继服务器: 两台机器分别连接到中继服务,后者完成双向转发。这种方式显然有很大的性能开销,而 且中继服务器很容易成为瓶颈。

有没有办法不用中继,让两台机器直接通信呢

那就是:跨过公网(互联网)实现端到端直连。

TailScale 是什么, Headscale又是什么

TailScale

TailScale 你可以理解为 VPN,或者说 Wireguard 外面包了一层壳子。它可以将一些设备连接起来,形成一个虚拟局域网。一个很简单的例子,你可以在星巴克里,读取家里任意电脑上的文件。

比如最常见的需求就是,公司有一个内网办公环境,当你外出办公时,也希望你的电脑能够接入办公网络。 因为外网的机器和内网的机器不能互联,所以一般会有一个中心服务器, 所有的子节点都和中心服务器相连,然后中心服务器转发所有的流量。
5Z0qxl

这样做的缺点显而易见,首先是中心服务器(hub)会成为瓶颈。 其次,某种极端情况下,如果节点 A 和 节点 B 距离非常近,但是都离 hub 很远, 这样就会导致非常高的延迟。
Rje9yw

那么我们就会想,能不能让节点间直接互联呢? 这就是 mesh VPN,其实现就是 wireguard。
pQ8X8e
wireguard 的每一个节点都会存储其他所有节点的信息,并且和其他所有的节点都建立 tls 连接。 如果涉及到内网穿透的话,那么你需要找到一台处于网关位置的节点(内外网都可达),将其设置为 coordinator, 扮演类似于 hub 的角色, 分发穿透内外网的流量。

wireguard 的缺点在于:

  • 配置比较繁琐
  • 维护也比较困难,增删节点都需要改动所有节点的配置

基于上述这些痛点,TailScale 做了一些改进:

1、在原有的 ICE、STUN 等 UDP 协议外,实现了 DERP TCP 协议来实现 NAT 穿透
2、基于公网的 coordinator 服务器下发 ACL 和配置,实现节点动态更新
3、通过第三方(如 Google) SSO 服务生成用户和私钥,实现身份认证

对我来说 Tailscale 相对于 Wireguard 最大的优势有 3 点:
1、配置简单
2、支持 P2P 和中继自动切换
3、支持自建中继节点

作为一种搭建虚拟局域网的工具,相比于传统VPN而言,所有节点之间都可以进行P2P连接,也就是全互联模式,效率更高。

为了基于wireguard实现更完美的VPN工具,现在已经出现了很多项目,如Netmaker,通过可视化界面来配置全互联模式,并支持UDP打洞、多租户等高端功能,几乎适配所有平台。然而现实世界是复杂的,无法保证所有的NAT都能打洞成功,而且Netmaker目前不支持fallback机制,如打洞失败,无法fallback中继节点。而Tailscale支持fallback,可以尽最大努力实现全互联模式,部分节点即使打洞不成功,也可通过中继节点在虚拟局域网内畅通无阻。

简而言之,我们可以认为 TailScale 是更为易用版的、功能封装更为完善的 wireguard。

Headscale

Headscale看名字就知道是和 Tailscale 对着干的,Tailscale 的客户端是不收费的,服务端是不开源的,超过 20 个设备就需要付费了,并且Tailscale的服务不在国内,我们不可能把服务端安全的交给Tailscale,私有自建才是出入。Headscale 是个第三方开源版本的 Tailscale 的服务端,除了「网站界面」之外该有的功能都有,因此我们使用Headscale自建私有服务。

解决方案

所以本次的方案:
1、阿里云服务器 部署 Headscale 服务端
2、自己的 Mac 和 Nas 上,使用 Tailscale 作为客户端

或公司,mongodb所在的服务器与sqlServer所在的服务器组网

服务端

Docker 部署

1
2
3
4
5
6
7
8
9
10
11
12
version: '3.5'
services:
headscale:
image: headscale/headscale:latest-alpine
container_name: headscale
volumes:
- ./config:/etc/headscale
- ./data/data:/var/lib/headscale
ports:
- 8080:8080
command: headscale serve
restart: unless-stopped

手动新建一下配置文件,放入./config

1
wget https://github.com/juanfont/headscale/raw/main/config-example.yaml -O config.yaml

编辑一下它:

  • server_url 这个东西是一个简单的「HTTP 设备认证页面」,后面需要暴露在公网上,其他设备如果想加入到你的网络里面,需要访问这个地址,拿到一个 Token。有域名的话推荐用域名+nginx/caddy 反向代理没域名的话用 ip+端口。
  • ip_prefixes 可以根据自己喜好来改,留默认的当然也行

docker-compose up -d启动 docker
下一步,创建一个「租户」,你可以理解为一个用户。进到 headscale 的 docker 里面,执行

1
headscale namespaces create SOME_NAME

SOME_NAME随意替换

客户端

并非全部客户端都支持(或全部支持)将 Headscale 作为后端,目前适配情况如下:

操作系统 支持情况 解决方案
Linux 原生支持
Windows 修改注册表
macOS 需要添加描述文件
Android
iOS 目前不支持

Mac 端:AppStore 版客户端

由于是使用的「非官方版控制器」,所以我们需要稍微 hack 一下,将软件里面默认的「tailscale 官方控制服务器地址」改为我们自己搭建的 Headscale 地址。

访问 http://server_url/apple,下载并安装一个描述文件。

然后打开 Tailscale,点击登录,会看到一个英文界面,里面有一行命令

1
headscale -n NAMESPACE nodes register --key SOME_HEX_VALUE

将里面的 NAMESPACE 换成你创建的租户名称,然后去服务端 docker 里面,执行它。你就会发现,你的 mac 已经登录成功了。

Linux端:Docker 版客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3.3'
services:
tailscaled:
container_name: tailscaled
image: tailscale/tailscale
network_mode: host
privileged: true
restart: always
cap_add:
- net_admin
- sys_module
volumes:
- ./lib:/var/lib
- /dev/net/tun:/dev/net/tun
command: sh -c "mkdir -p /var/run/tailscale && ln -s /tmp/tailscaled.sock /var/run/tailscale/tailscaled.sock && tailscaled"

启动容器后,需要进入容器,输入这个东西进行登录:

1
2
tailscale up --login-server=http://server_url --accept-routes=true --accept-dns=false

如果没问题,那么会提示你访问一个网址,拿到 Token,回到 Server 端进行登录就好。

synology

Access Synology NAS from anywhere
Tailscale Packages

tailscale up 参数

  • –hostname 设置名称
  • –accept-routes 接受服务端配置的路由
  • –accept-dns 推荐将 DNS 功能关闭,因为它会覆盖系统的默认 DNS
  • –advertise-routes 申请路由到该节点,Tailscale 实现「出口节点」,即打通局域网内部的路由访问,这个网段的所有设备都可以被访问
  • –advertise-exit-node 可以建立数据导向节点exit node,即本机访问互联网皆通过此节点 bolean
  • –exit-node 指定出口节点,导向所有流量经这出口节点

headscale命令

通过服务端授权客户端

1
headscale -n default nodes register --key 905cf165204800247fbd33989dbc22be95c987286c45aac3033937041150d846

查看注册的节点

1
2
3
4
headscale nodes list

ID | Name | NodeKey | Namespace | IP addresses | Ephemeral | Last seen | Online | Expired
1 | coredns | [Ew3RB] | default | 10.1.0.1 | false | 2022-03-20 09:08:58 | online | no

通过 Pre-Authkeys 接入

前面的接入方法都需要服务端同意,步骤比较烦琐,其实还有更简单的方法,可以直接接入,不需要服务端同意。

首先在服务端生成 pre-authkey 的 token,有效期可以设置为 24 小时:

1
headscale preauthkeys create -e 24h -n default

查看已经生成的 key:

1
headscale -n default preauthkeys list

现在新节点就可以无需服务端同意直接接入了:

1
tailscale up --login-server=http://<HEADSCALE_PUB_IP>:8080 --accept-routes=true --accept-dns=false --authkey $KEY

打通局域网

WZtD67
假设你的家庭内网有一台 Linux 主机(比如 Nas)安装了 Tailscale 客户端,我们希望其他 Tailscale 客户端可以直接通过家中的局域网 IP(例如 192.168.100.0/24) 访问家庭内网的任何一台设备。

官方文档:Subnet routers and traffic relay nodes
群辉具体操作见:headscale组网打通群辉局域网内部访问

linux 配置方法很简单,首先需要设置 IPv4 与 IPv6 路由转发:

1
2
3
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

客户端修改注册节点的命令,在原来命令的基础上加上参数 --advertise-routes=192.168.100.0/24

1
tailscale up --login-server=http://<HEADSCALE_PUB_IP>:8080 --accept-routes=true --accept-dns=false --advertise-routes=192.168.100.0/24

在 Headscale 端查看路由,可以看到相关路由是关闭的。

1
2
3
4
5
6
7
headscale nodes list|grep nas
6 | nas | [7LdVc] | default | 10.1.0.6 | false | 2022-03-20 15:50:46 | online | no

headscale routes list -i 6
Route | Enabled

192.168.100.0/24 | false

开启路由:

1
2
3
headscale routes enable -i 6 -r "192.168.100.0/24"
Route | Enabled
192.168.100.0/24 | true

其他节点查看路由结果:

1
2
ip route
192.168.100.0/24 dev tailscale0

现在你在任何一个 Tailscale 客户端所在的节点都可以 ping 通家庭内网的机器了

为了能让headscale稳定,我们可以自建中继服务器
headscale之DERP中继服务器自建

相关链接

NAT 穿透是如何工作的:技术原理及企业级实践