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域名
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使用的記憶體。客戶端的使用這部分網路上有大量的資料可供參考,三言兩語很難說得清楚,在此不再過多贅述。
========= End