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域名
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 102 103 |
# Headscale访问域名 server_url: https://headscale.luminous-example.com # Headscale本地监听地址 listen_addr: 127.0.0.1:8080 # 运行报告,位于/metrics目录,非必要 metrics_listen_addr: 127.0.0.1:9090 # grpc接口,非必要 grpc_listen_addr: 127.0.0.1:50443 # 允许grpc不安全 grpc_allow_insecure: false ## Headscale主服务TS2021 Noise协议 noise: # 密钥路径,请修改为实际值 private_key_path: /home/headscale/data/noise_private.key # 内网IP段,建议在以下受支持的CGNAT段内 prefixes: v6: fd7a:115c:a1e0::/48 v4: 100.64.0.0/16 # IP分配模式,顺序sequential和随机random allocation: sequential ## 内置DERP转发服务 derp: server: # 是否开启内置DERP,若非单机部署可不开启 enabled: true # DERP基础信息 region_id: 999 region_code: "headscale" region_name: "Headscale Embedded DERP" # STUN服务端口,建议修改为非标端口 stun_listen_addr: "0.0.0.0:3478" # DERP私钥,请修改为实际值 private_key_path: /home/headscale/data/derp_server_private.key # 自动添加内置DERP至列表 automatically_add_embedded_derp_region: true # DERP服务主机IP地址,请修改为实际值 ipv4: 110.42.1.1 ipv6: 2402:4e00::1 # 从URL引入官方DERP服务器 urls: - https://controlplane.tailscale.com/derpmap/default # 可选从本地配置文件引入自建DERP服务器 # paths: # - /home/headscale/derp.yaml # 自动更新引入的DERP服务器 auto_update_enabled: true # How often should we check for DERP updates? update_frequency: 24h # 禁止Headscale检查更新 disable_check_updates: true # 不活跃临时节点删除时间 ephemeral_node_inactivity_timeout: 30m ## 数据库配置 database: type: sqlite debug: false gorm: prepare_stmt: true parameterized_queries: true skip_err_record_not_found: true slow_threshold: 1000 # SQLite路径,请修改为实际值 sqlite: path: /home/headscale/data/db.sqlite # SQLite WAL日志 write_ahead_log: false ## ACL参数设置 policy: mode: file path: "" ## DNS配置 dns: # 虚拟机局域网MagicDNS magic_dns: true # 虚拟网根域名 base_domain: luminous.network # 公共DNS设置,以DNSPod+百度DNS为例 nameservers: global: - 119.29.29.29 - 223.6.6.6 split: {} search_domains: [] extra_records: [] use_username_in_magic_dns: false # Unix嵌套字 unix_socket: /var/run/headscale/headscale.sock unix_socket_permission: "0770" # Logtail日志服务 logtail: enabled: false # 随机客户端端口 randomize_client_port: true |
用于引入其他自建DERP服务器的derp.yaml
示例如下,请根据实际修改并在上方Headscale配置文件对应位置引入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
regions: 900: regionid: 900 regioncode: sh-cm regionname: Shanghai Mobile nodes: - name: node1 regionid: 900 hostname: derp1.example.com ipv4: 10.10.10.10 ipv6: "2600::1" stunport: 3478 stunonly: false derpport: 443 |
自启动配置
如下将文件路径修改正确后,在systemd
目录下创建headscale.service
,即可通过service headscale start|stop|restart
管理进程状态,确认无误后使用systemctl enable headscale
允许开机自启。因为是自用,博主直接使用root
用户启动进程,若对安全有额外的需求请新建一个headscale
用户进行运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# Headscale进程路径 # /etc/systemd/system/headscale.service [Unit] Description=Headscale Service After=network.target [Service] Type=simple User=root Restart=on-failure RestartSec=5s # 请根据实际修改文件路径 WorkingDirectory=/home/headscale ExecStart=/home/headscale/headscale serve -c /home/headscale/config.yaml [Install] WantedBy=multi-user.target |
NGINX配置
Headscale仅从/key
、/ts2021
、/derp
和/api
四个路径进行数据交换,但鉴于官方并未明确说明,博主还是推荐对Headscale全局/
路径进行反向代理。其中,要单独为headscale-admin静态站点进行排除和指向,若全局反向代理影响证书签发可使用相同的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 反向代理Headscale服务端口,并允许websocket location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; } # 将/admin指向Headscale-admin目录 location /admin { root /home/headscale/web; } |
防火墙配置
在以上的配置中,Headscale进程启用了HTTP
协议监听本地的主服务(8080
)、Mertics(9090
)和grpc(50443
)三个端口,在需要时均可以通过NGINX转发至标准端口并绑定域名,无需单独对外放通。唯一需要额外放通的是转发服务DERP STUN的UDP
端口3478
端口(或设定的端口号),基本满足了简单、安全和与其他服务共存的需要。
1 2 3 4 5 6 |
# CentOS firewalld firewall-cmd --zone=public --add-port=3478/udp --permanent # Debian/Ubuntu ufw ufw allow 3478/udp # iptables iptables -I INPUT 1 -p udp --dport 3478 -j ACCEPT |
若使用云服务器搭建,则要额外注意在安全组中放通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页面进行放通以开放内网广播。以下是几个简单的实例:
1 2 3 4 5 6 |
# 作为独立设备接入 tailscale up --login-server=https://headscale.example.com --accept-dns --accept-routes # 作为出口设备接入 tailscale up --login-server=https://headscale.example.com --advertise-exit-node --exit-node-allow-lan-access --accept-dns --accept-routes # 接入同时路由内网的192.168.1.0/24到虚拟局域网 tailscale up --login-server=https://headscale.example.com --exit-node-allow-lan-access --advertise-routes=192.168.1.0/24 --accept-dns --accept-routes |
手机端同样可以从Google Play或官网下载(点击前往),随后可以从右上角设置
–Accounts
–右上角菜单
–Alternate Server
进入设置,其余操作大同小异。路由器端需要从OpenWRT源(点击前往)下载对应架构较新的最小化构建.ipk
包,同时下载Luci App及语言包(点击前往)两个.ipk
包,将三个文件置于路由器同一个文件夹下使用opkg install *
安装即可。如果内存不宽裕,可以添加go的GOMEMLIMIT=100MiB环境变量,以约束Tailscale使用的内存。客户端的使用这部分网络上有大量的资料可供参考,三言两语很难说得清楚,在此不再过多赘述。
结语
结尾没什么好说的,刚刚告别了国庆假期,祝大家在一年之末工作顺利、生活愉快吧~
整个折腾过程就是让异地组网合规风险小了一些,别的也没有什么实质性的改变。博主在这方面属实了解甚少,有不足的地方,欢迎大家在评论区补充和指正,谢谢大家~
*原创文章,转载请注明出处
我想问一下 ,没有https证书和密钥指向的地址吗
牛啊,最近刚有这个需求,马上实践一下,有结果了过来反馈!
derper 还需要配置https证书吗
博客逛多了,发现个有趣的事,技术流的博客搭配二次元的主题和配图
博主,您好,蓝奏云盘的链接失效啦,能再分享一下不?谢谢
4m小水管服务器,跑tailscale带宽受限么?
话说在大陆服务器上跑https,域名不用备案的嘛?