自建tailscale服务接入headscale服务器实现异地组网

背景

在日常生活中,有各个地区的云服务器的同学,一定有个困惑,就是管理困难,ip地址跨域之大,错综复杂,太难记了;家里有nas、软路由(ALL IN ONE)的小伙伴,以及有独服搭建pve并且ip地址不够,使用nat进行ip下放的同学,也有一个问题,就是我只有一个公网ip,如果我想访问子系统的某个服务,我可能需要使用frp或者realm等转发工具来映射出去,前者需要一台公共的服务器,后者需要公网ip,并且一个服务一个端口,简直是煎熬

而今天,我推荐给大家一个针对上述问题的解决方案,headscale+tailscale实现异地组网,在不同地区、不同服务器、不同网段下的网络设备实现内网互联,比如说,我有一台ovh波兰的独服,使用nat将黑群晖分配了192.168.0.6这个内网ip,如果我想在外网访问它的服务,我需要使用rinetd实现端口转发到主服务器上,如下,一个服务对应一条规则,配置好后,如果我想访问群晖的入口,我需要访问的的主服务器的ip+端口,比如输入box.wuan.me:5000跳转到登录页

Untitled.png

在我使用tailscale互联后,我只需要直接访问192.168.0.6:5000就能直接访问群晖后台,而且tailscale在你使用当前客户端与你需要访问服务的客户端能直连的话就能走直连,如果不能直连则会走derp中继服务器,类似frp中转来提升访问的体验,我们也可以在多个地区自建derp,来提升各地互联的体验,如下图,使用 tailscale status来获取组网的所有客户端,可以看到使用了德国的中继服务器

Untitled 1.png

Untitled 2.png

可以看到,即使对端的线路不是直连,也可以通过中继服务器的方案达到比较理想的效果,接下来我们就开始准备环境来搭建headscale

环境准备

  • 一台有公网用于搭建headscale服务的服务器
  • n台用于组网的客户端,可以是win,mac,linux,android或者ios
  • 域名(非必需)
  • 勤劳的小手

Headscale服务搭建

搭建步骤

  1. 我们先从github根据服务器的架构下载文件到我们的服务器中,常见的x86选amd64,arm选arm64,我们的架构是x86,所以下载x86架构

✨如果因为网络问题可以在客户端使用代理的情况下下载下来再复制到服务器上

wget --output-document=/usr/local/bin/headscale https://github.com/juanfont/headscale/releases/download/v0.23.0-alpha1/headscale_0.23.0-alpha1_linux_amd64

chmod +x /usr/local/bin/headscale

✨如果是debian或者ubuntu系统则可以下载.deb文件,然后执行以下代码即可安装

dpkg -i dpkg -i headscale_0.23.0-alpha1_linux_amd64.deb
  1. 创建配置目录
mkdir -p /etc/headscale
  1. 创建目录用来存储数据与证书
mkdir -p /var/lib/headscale
  1. 创建空的 SQLite 数据库文件:
touch /var/lib/headscale/db.sqlite
  1. 从github拉 Headscale 配置文件

✨如果因为网络问题可以在客户端使用代理的情况下下载下来再上传到服务器上

wget https://github.com/juanfont/headscale/raw/main/config-example.yaml -O /etc/headscale/config.yaml
  • 修改配置文件,将 server_url 改为公网 IP 或域名。如果是国内服务器,域名必须要备案。我的域名无法备案,所以我就直接用公网 IP 了。
  • 如果暂时用不到 DNS 功能,可以先将 magic_dns 设为 false。
  • server_url 设置为 http://<PUBLIC_IP>:8080,将 <PUBLIC_IP> 替换为公网 IP 或者域名。
  • 可自定义私有网段,也可同时开启 IPv4 和 IPv6:
  • listen_addr设置为http://0.0.0.0:8080
ip_prefixes:
  # - fd7a:115c:a1e0::/48
  - 10.1.0.0/16
  1. 创建 SystemD service 配置文件

✨ debian或者ubuntu系统如果通过.deb安装了tailscale的话可以忽略

nano /etc/systemd/system/headscale.service
# /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
  1. 创建 headscale 用户
useradd headscale -d /home/headscale -m
  1. 修改 /var/lib/headscale 目录的 owner
chown -R headscale:headscale /var/lib/headscale
  1. Reload SystemD 以加载新的配置文件
systemctl daemon-reload
  1. 启动 Headscale 服务并设置开机自启
systemctl enable --now headscale
  1. 查看运行状态,状态显示running则代表启动成功
systemctl status headscale

Untitled 3.png

  1. Tailscale 中有一个概念叫 tailnet,你可以理解成租户,租户与租户之间是相互隔离的,具体看参考 Tailscale 的官方文档: What is a tailnet。Headscale 也有类似的实现叫 namespace,即命名空间。我们需要先创建一个 namespace,以便后续客户端接入,例如:
headscale namespaces create default
  1. 查看命名空间
headscale namespaces list
2023-10-12T07:32:02-04:00 TRC DNS configuration loaded dns_config={"ExitNodeFilteredSet":null,"Nameservers":["1.1.1.1"],"Resolvers":[{"Addr":"1.1.1.1"}]}
ID | Name    | Created
1  | default | 2023-10-12 11:32:00

Tailscale接入

接入步骤

linux

因为官方服务器在海外,国内的服务器使用一键脚本可能拉不下来,国内服务器可以使用手动方式安装

官方脚本:使用官方提供的一键安装脚本
curl -fsSL https://tailscale.com/install.sh | sh

安装完成后查看启动状态,现实running表示正常

systemctl status tailscaled

Untitled 4.png

手动安装方式:

从官方编译好的release下载压缩文件

wget https://pkgs.tailscale.com/stable/tailscale_1.50.1_amd64.tgz

解压缩文件

tar zxvf tailscale_1.50.1_amd64.tgz

将二进制文件复制到官方软件包默认的路径下

cp tailscale_1.50.1_amd64/tailscaled /usr/sbin/tailscaled
cp tailscale_1.50.1_amd64/tailscale /usr/bin/tailscale

将 systemD service 配置文件复制到系统路径下

cp tailscale_1.50.1_amd64/systemd/tailscaled.service /lib/systemd/system/tailscaled.service

将环境变量配置文件复制到系统路径下

cp tailscale_1.50.1_amd64/systemd/tailscaled.defaults /etc/default/tailscaled

启动 tailscaled.service 并设置开机自启

systemctl enable --now tailscaled

查看服务状态

systemctl status tailscaled
Tailscale 接入 Headscale
# 将 <HEADSCALE_PUB_IP> 换成你的 Headscale 公网 IP 或域名
tailscale up --login-server=http://<HEADSCALE_PUB_IP>:8080 --accept-routes=true --accept-dns=false

执行后会提示

To authenticate, visit:

        http://103.***.***.***:8080/register/nodekey:902c1cacf5463aca26cd067d303e9f415f0c3cd4c37b113d7677a7d4f304e870

打开这个链接复制到浏览器打开会显示一条命令

Untitled 5.png

将USERNAME更换为上面创建的默认用户default执行,会提示客户端已注册到headscale

headscale nodes register --user default --key nodekey:902c1cacf5463aca26cd067d303e9f415f0c3cd4c37b113d7677a7d4f304e870
An updated version of Headscale has been found (0.23.0-alpha1 vs. your current v0.22.3). Check it out https://github.com/juanfont/headscale/releases
Machine cc registered

查看headscale中所有注册的客户端,到此linux就注册完成了

headscale nodes list
An updated version of Headscale has been found (0.23.0-alpha1 vs. your current v0.22.3). Check it out https://github.com/juanfont/headscale/releases
ID | Hostname | Name | MachineKey | NodeKey | User    | IP addresses                  | Ephemeral | Last seen           | Expiration          | Online  | Expired
1  | cc       | cc   | [fMmN1]    | [kCwcr] | default | 100.64.0.1, fd7a:115c:a1e0::1 | false     | 2023-10-12 12:20:33 | 0001-01-01 00:00:00 | offline | no
macos

macOS 有 3 种安装方法:

这三种安装包的核心数据包处理代码是相同的,唯一的区别在于在于打包方式以及与系统的交互方式。

应用商店里的应用运行在一个 应用沙箱中,与系统的其他部分隔离。在沙箱内,应用可以是一个 网络扩展,以实现 VPN 或者类 VPN 的功能。网络扩展实现的功能对应用商店之外的应用是无法生效的。

从 macOS 从 10.15 开始新增了 系统扩展,说白了就是运行在用户态的内核扩展,它相比于传统的网络扩展增强了很多功能,比如内容过滤、透明代理、DNS 代理等。Tailscale 独立于应用商店的安装包使用的就是系统扩展,通过 DMG 或者 zip 压缩包进行分发。

不要同时安装应用商店版本和独立分发版本,同时只能装一个。

而命令行工具既没有使用网络扩展也没有使用系统扩展,而是使用的 utun 接口,相比于 GUI 版本缺少了部分功能,比如 MagicDNS 和 Taildrop。

总览:

应用商店(网络扩展) 独立应用(系统扩展) 命令行版本
是否可用 https://apps.apple.com/ca/app/tailscale/id1475387142 yes, https://tailscale.com/kb/1167/release-stages/#beta https://github.com/tailscale/tailscale/wiki/Tailscaled-on-macOS
图形界面 yes yes no; CLI
macOS 最低版本 macOS 10.13 macOS 10.15 macOS 10.13
后台运行 no; sandboxed 理论上支持; 尚未实现 yes
使用的钥匙串🔑 用户级 系统级 直接存放在文件中
沙盒隔离 yes no no
自动更新 yes; 应用商店直接更新 yes; https://sparkle-project.org/ no
是否开源 no no yes
MagicDNS yes yes yes
Taildrop yes yes 未实现

安装完 GUI 版应用后还需要做一些骚操作,才能让 Tailscale 使用 Headscale 作为控制服务器。当然,Headscale 已经给我们提供了详细的操作步骤,你只需要在浏览器中打开 URL:http://<HEADSCALE_PUB_IP>:8080/apple,便会出现如下的界面:

Untitled 6.png

然后按住alt键+鼠标右键点击tailscale图标,选择debug—>login,输入headscale注册地址,会自动出现注册到headscale的命令,复制到headscale服务器执行就可以了。

非应用商店版本的 macOS 客户端需要将 io.tailscale.ipn.macos 替换为 io.tailscale.ipn.macsys。即:defaults write io.tailscale.ipn.macsys ControlURL http://<HEADSCALE_PUB_IP>:8080

修改完成后重启 Tailscale 客户端,在 macOS 顶部状态栏中找到 Tailscale 并点击,然后再点击 Log in

Untitled 7.png

然后立马就会跳转到浏览器并打开一个页面。

https://jsdelivr.icloudnative.io/gh/yangchuansheng/imghosting3@main/uPic/2022-03-20-17-46-AbzngB.png

接下来与之前 Linux 客户端相同,回到 Headscale 所在的机器执行浏览器中的命令即可,注册成功:

Untitled 8.png

回到 Headscale 所在主机,查看注册的节点:

$ headscale nodes listAn updated version of Headscale has been found (0.23.0-alpha1 vs. your current v0.22.3). Check it out https://github.com/juanfont/headscale/releases
ID | Hostname                 | Name                     | MachineKey | NodeKey | User    | IP addresses                  | Ephemeral | Last seen           | Expiration          | Online  | Expired
1  | cc                       | cc                       | [fMmN1]    | [kCwcr] | default | 100.64.0.1, fd7a:115c:a1e0::1 | false     | 2023-10-12 12:20:33 | 0001-01-01 00:00:00 | offline | no
2  | sglite1-2023101121410056 | sglite1-2023101121410056 | [i3GT7]    | [mZUoj] | default | 100.64.0.2, fd7a:115c:a1e0::2 | false     | 2023-10-12 12:36:22 | 0001-01-01 00:00:00 | offline | no

回到 macOS,测试是否能 ping 通对端节点

$ ping 100.64.0.2
PING 100.64.0.2 (100.64.0.2) 56(84) bytes of data.
64 bytes from 100.64.0.2: icmp_seq=2 ttl=64 time=703 ms
64 bytes from 100.64.0.2: icmp_seq=3 ttl=64 time=178 ms
64 bytes from 100.64.0.2: icmp_seq=4 ttl=64 time=180 ms
64 bytes from 100.64.0.2: icmp_seq=5 ttl=64 time=180 ms
64 bytes from 100.64.0.2: icmp_seq=6 ttl=64 time=179 ms
64 bytes from 100.64.0.2: icmp_seq=7 ttl=64 time=178 ms
64 bytes from 100.64.0.2: icmp_seq=8 ttl=64 time=175 ms
^C
--- 100.64.0.2 ping statistics ---
8 packets transmitted, 7 received, 12.5% packet loss, time 7031ms
rtt min/avg/max/mdev = 175.267/253.364/703.444/183.750 ms
ios

需要使用美区账号下载tailscale软件,然后在系统设置找到tailscale配置,修改server_url然后打开软件,后面就是跟上方操作一样了

Untitled 9.png

Windows

Windows Tailscale 客户端想要使用 Headscale 作为控制服务器,只需在浏览器中打开 URL:http://<HEADSCALE_PUB_IP>:8080/windows,便会出现如下的界面:

https://jsdelivr.icloudnative.io/gh/yangchuansheng/imghosting3@main/uPic/2022-03-20-23-30-zcQX3F.png

按照其中的步骤操作即可。

其他 Linux 发行版

除了常规的 Linux 发行版之外,还有一些特殊场景的 Linux 发行版,比如 OpenWrt、威联通(QNAP)、群晖等,这些发行版的安装方法已经有人写好了,这里就不详细描述了,我只给出相关的 GitHub 仓库,大家如果自己有需求,直接去看相关仓库的文档即可。

打通局域网

到目前为止我们只是打造了一个点对点的 Mesh 网络,各个节点之间都可以通过 WireGuard 的私有网络 IP 进行直连。但我们可以更大胆一点,还记得我在文章开头提到的访问家庭内网的资源吗?我们可以通过适当的配置让每个节点都能访问其他节点的局域网 IP。这个使用场景就比较多了,你可以直接访问家庭内网的 NAS,或者内网的任何一个服务,更高级的玩家可以使用这个方法来访问云上 Kubernetes 集群的 Pod IP 和 Service IP。

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

配置方法很简单,首先需要设置 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

客户端修改注册节点的命令,在原来命令的基础上加上参数 --advertise-routes=192.168.100.0/24,告诉 Headscale 服务器“我这个节点可以转发这些地址的路由”。

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

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

headscale nodes list|grep openwrt

6 | openwrt | [7LdVc] | default | 10.1.0.6 | false | 2022-03-20 15:50:46 | onlin

e | no

$ headscale routes list -i 6

Route | Enabled

192.168.100.0/24 | false

开启路由:

headscale routes enable -i 6 -r "192.168.100.0/24"

Route | Enabled

192.168.100.0/24 | true

如果有多条路由需要用 , 隔开:

headscale routes enable -i 6 -r "192.168.100.0/24,xxxx"

也可以通过参数 -a 开启所有路由:

headscale routes enable -i 6 -a

其他节点查看路由结果:

ip route show table 52|grep "192.168.100.0/24"
192.168.100.0/24 dev tailscale0

其他节点启动时需要增加 --accept-routes=true 选项来声明 “我接受外部其他节点发布的路由”。

现在你在任何一个 Tailscale 客户端所在的节点都可以 ping 通家庭内网的机器了,你在公司或者星巴克也可以像在家里一样用同样的 IP 随意访问家中的任何一个设备,就问你香不香?

总结

虽然操作稍显繁琐,但是成型后还是很香的,让自己分布在各个地区甚至各个国家都能组成“局域网”,使用一段时间后发现早就应该扔掉openvpn了,具体使用体验各位自己实际使用过欢迎分享,后面也会分享怎么自建derp中转服务器

PS

因为markdown不太熟练,排版不太好看,语言措辞大家也就将就着看,步骤我尽量写的详细一点,顺带打个小广告,我个人的博客网站也上线了,大家也可以到我网站里面多来看看,我也会分享一些比较好玩的东西,以下两个站基本会同时更新

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注

×
订阅图标按钮