Tailscale chậm: kiểm tra relay hay kết nối trực tiếp
Tailscale qua relay chậm hơn kết nối trực tiếp. Dùng 2 lệnh để kiểm tra, rồi xử lý UDP bị chặn và NAT cứng trên VPS để tăng tốc.
Tại sao Tailscale chậm: dùng relay thay vì kết nối trực tiếp
Tailscale chậm khi kết nối phải đi qua relay và gần đạt tốc độ đường truyền khi kết nối trực tiếp. Kết nối trực tiếp truyền các gói WireGuard đã mã hóa thẳng từ máy này sang máy kia, nên tốc độ phụ thuộc vào khả năng truyền tải của hai đường truyền Internet. Kết nối qua relay gửi mọi gói tin qua một máy thứ ba trước, nên phải chịu độ trễ của máy đó và phần băng thông mà bạn được chia sẻ. Trang thông tin hiệu năng của Tailscale nêu rõ: "Kết nối trực tiếp gần như luôn có độ trễ thấp hơn và throughput cao hơn."
Ứng dụng không hiển thị sự khác biệt này. Lệnh sao chép file chỉ chạy chậm, còn phiên SSH chỉ bị trễ. Vì vậy, việc đầu tiên là xác định bạn đang dùng loại kết nối nào. Hai lệnh có thể trả lời trong chưa đầy một phút; mọi bước sau đó đều nhằm sửa nguyên nhân. Bạn nên nắm phần thiết lập trước khi bắt đầu, vì coordination server và data plane của WireGuard là hai hệ thống tách biệt và chỉ data plane mới truyền dữ liệu của bạn.
Hai lệnh cho biết kết nối là trực tiếp hay qua relay
Gửi một ít lưu lượng đến peer trước khi đo. Tailscale xây dựng path theo nhu cầu, vì vậy peer mà bạn chưa trao đổi dữ liệu hôm nay có thể chưa thương lượng path. Khi đó, bạn sẽ đọc một kết quả đã cũ. Chỉ cần chạy một ping hoặc một curl đến địa chỉ tailnet của peer.
tailscale statusKết quả nằm ở cuối dòng của từng peer.
100.113.160.82 device-a tagged-devices linux active; offers exit node; direct 203.0.113.9:41641
100.104.93.78 device-b you@ android active; relay "tor"direct theo sau bởi một địa chỉ và một port nghĩa là các packet đi thẳng đến địa chỉ đó. relay "tor" là tên của một máy chủ DERP (designated encrypted relay for packets), tức một trong các máy relay của Tailscale; mọi packet đến peer đó đều đi qua máy này. Giá trị thứ ba, peer-relay, được giải thích trong phần tiếp theo.
tailscale ping device-bMột kết nối bình thường bắt đầu qua relay rồi chuyển sang kết nối trực tiếp. Các packet đầu tiên đi qua máy chủ DERP gần nhất trong lúc hai máy thương lượng, sau đó path thay đổi:
pong from device-b (100.113.160.82) via DERP(tor) in 51ms
pong from device-b (100.113.160.82) via DERP(tor) in 48ms
pong from device-b (100.113.160.82) via 203.0.113.9:41641 in 35msLệnh dừng tại đó vì --until-direct mặc định có giá trị true. Kết nối không thể chuyển sang direct sẽ có dạng như sau và kết thúc bằng một câu thay vì một pong:
pong from device-b (100.104.93.78) via DERP(tor) in 53ms
pong from device-b (100.104.93.78) via DERP(tor) in 60ms
direct connection not establishedDòng cuối cùng là kết quả cần tìm. Điều đó nghĩa là Tailscale đã gửi toàn bộ probe cần gửi nhưng không bao giờ tạo được direct path. Để tiếp tục theo dõi một relayed path thay vì dừng ở direct path đầu tiên, hãy chạy tailscale ping --until-direct=false -c 20 device-b và đọc độ phân tán của latency. Relayed path thường có cả giá trị cao hơn và dao động lớn hơn, vì đó là hai network path nối với nhau qua một máy mà bạn không kiểm soát.
Peer-relay trong tailscale status nghĩa là gì?
Peer relay là một máy trong tailnet của bạn, dùng để chuyển tiếp traffic cho các thành viên khác khi không thể thiết lập kết nối trực tiếp. Máy này lắng nghe trên một cổng UDP do bạn chọn, và daemon sẽ ưu tiên dùng nó thay vì DERP. tailscale status đánh dấu một kết nối như vậy peer-relay, còn tailscale ping hiển thị endpoint của relay:
pong from device-b (100.97.143.93) via peer-relay(203.0.113.42:40000:vni:1) in 4ms
direct connection not establishedHãy đọc kỹ kết quả này. Đây vẫn không phải là kết nối trực tiếp, nên lần chạy vẫn kết thúc bằng direct connection not established. Điểm thay đổi là máy nào thực hiện việc chuyển tiếp. Một VPS có địa chỉ IP public và băng thông được cấp rộng rãi phù hợp làm relay cho traffic của bạn hơn nhiều so với một node DERP dùng chung. Vì vậy, tính năng này đáng chú ý với bất kỳ ai thuê server. Hãy bật tính năng này trên máy có public endpoint ổn định:
sudo tailscale set --relay-server-port=40000Cổng 0 sẽ chọn một cổng chưa được sử dụng một cách ngẫu nhiên. Chuỗi rỗng sẽ tắt relay server. Sau đó, cấp quyền cho các thiết bị client sử dụng relay này bằng capability tailscale.com/cap/relay trong file policy của tailnet:
{
"grants": [
{
"src": ["tag:us-east-vpc"],
"dst": ["tag:us-east-relays"],
"app": {
"tailscale.com/cap/relay": []
}
}
]
}Cả thiết bị relay và các thiết bị client đều cần Tailscale 1.86 trở lên. Vì vậy, hãy kiểm tra bằng tailscale version trên từng thiết bị trước khi mất cả giờ chỉnh file policy. Bạn nên ghi nhớ thứ tự daemon thử các phương án. Trước tiên, daemon thử kết nối trực tiếp. Nếu kết nối này thất bại, daemon tìm một peer relay mà nó được phép sử dụng. Nếu không có peer relay, daemon chuyển sang DERP. DERP không bao giờ hoàn toàn bị loại khỏi quá trình này, vì đây cũng là kênh để hai máy thương lượng kết nối ngay từ đầu.
Nguyên nhân 1: firewall egress chặn UDP
Tailscale nêu hai lý do khiến kết nối vẫn đi qua relay. Lý do đầu tiên là UDP bị chặn. Hãy kiểm tra trực tiếp trên máy:
tailscale netcheckPhần report ở đây đã được rút gọn. Trường ở đầu là trường quyết định mọi thứ:
Report:
* UDP: true
* IPv4: yes, 203.0.113.9:41641
* IPv6: no
* MappingVariesByDestIP: false
* PortMapping:
* Nearest DERP: DallasUDP: false là toàn bộ kết luận khi bạn thấy giá trị này. Máy không thể gửi gói UDP đến các probe server của Tailscale, nên không thể thiết lập đường truyền trực tiếp. Daemon chuyển sang dùng DERP qua TCP port 443. Vì vậy máy vẫn trông hoàn toàn khỏe mạnh: máy vẫn kết nối, vẫn reachable và mọi byte vẫn được relay.
Tailscale tài liệu hóa 2 rule outbound. “Cho phép thiết bị nội bộ khởi tạo UDP từ :41641 đến *:*” là traffic WireGuard, và “Cho phép thiết bị nội bộ khởi tạo UDP đến *:3478” là STUN (session traversal utilities for NAT), giao thức máy dùng để tìm public address và port của chính nó. Hãy dùng wildcard cho destination. Tailscale bổ sung relay server theo thời gian, nên danh sách address viết thủ công sẽ sai trong vòng 1 năm.
Trên server thuê, thủ phạm thường là egress policy quá chặt. Policy này có thể có sẵn trong hardened image hoặc do provider áp dụng ở upstream. Trước tiên, hãy xem policy outbound mặc định:
sudo ufw status verbose
sudo nft list rulesetDefault: deny (incoming), allow (outgoing) là bình thường và không phải nguyên nhân. Outgoing default là deny, kèm một allow list ngắn chỉ cho TCP 443 và DNS, chính là kiểu cấu hình khiến server luôn dùng relay. Đường DERP qua TCP 443 đi được qua lỗ mở này, còn đường trực tiếp thì không. Các rule đó thực sự nằm ở đâu còn tùy máy đang dùng iptables hay nftables ở bên dưới, và sửa nhầm firewall là cách phổ biến khiến thay đổi không có tác dụng.
Chiều inbound cũng quan trọng, vì VPS có public IP address nên có thể trở thành nửa dễ kết nối của cặp máy. Nếu firewall cho phép inbound UDP trên port mà tailscaled đang listen, các peer phía sau những home router khó kết nối vẫn có thể truy cập máy mà không cần thủ thuật nào. Hãy tìm port thực sự đang được dùng:
sudo ss -lunp | grep tailscaled
sudo ufw allow 41641/udp41641 là port tĩnh mặc định. Tailnet bật setting randomizeClientPort sẽ khiến client chọn port ngẫu nhiên. Khi đó, hãy lấy số thực tế từ output của ss thay vì dùng số trên trang này. Sau đó kiểm tra control panel của provider. Hầu hết host đều có network firewall riêng, tách biệt với firewall bên trong server. Vì vậy, rule bạn thêm bằng ufw sẽ không có tác dụng với firewall đó.
Nguyên nhân 2: NAT cứng ở một hoặc cả hai đầu
Nguyên nhân thứ hai đã được ghi nhận là NAT cứng. NAT (network address translation) là cơ chế router dùng để chuyển địa chỉ private của bạn thành địa chỉ public. Router thân thiện giữ nguyên public port cho một socket nội bộ nhất định, bất kể bạn đang kết nối với ai. Cơ chế này được gọi là endpoint independent mapping. NAT cứng cấp một public port khác nhau cho từng đích, nên địa chỉ mà máy học được từ STUN server không phải là địa chỉ mà peer có thể sử dụng. Tailscale báo trạng thái này trong netcheck dưới dạng MappingVariesByDestIP: true.
Một NAT cứng vẫn có thể hoạt động. Nếu đầu bên kia có public endpoint ổn định, máy nằm sau NAT cứng vẫn có thể kết nối đến đó và hình thành đường truyền. Hai NAT cứng cùng lúc là trường hợp bị lỗi, vì không bên nào có thể dự đoán port mà bên kia sẽ xuất hiện.
Trên VPS có địa chỉ IPv4 public, trường này phải hiển thị false vì không có thiết bị nào chuyển đổi địa chỉ đó. Nếu trường này hiển thị true trên server bạn thuê, địa chỉ đang bị chuyển đổi ở đâu đó trong network của nhà cung cấp, và không có firewall rule nào bên trong máy có thể thay đổi điều đó. Bạn có thể đặt peer relay trên một máy có public endpoint thực sự ổn định, hoặc chuyển workload sang nơi khác. Đây cũng là trường hợp việc quảng bá các dải private từ subnet router phát huy tác dụng, vì bạn chỉ cần một đường truyền tốt vào network thay vì một đường truyền tốt đến từng thiết bị trong đó.
Vì sao exit node khiến Tailscale có vẻ chậm hơn thực tế
Exit node là một hop thứ hai, nên người dùng thường đổ lỗi cho tunnel. Khi chọn một exit node, request rời khỏi laptop, đi qua tunnel đến VPS, rời VPS để vào Internet công cộng, rồi response quay lại theo cùng đường đó. Ngay cả khi kết nối trực tiếp đến VPS hoàn toàn ổn định, tổng tốc độ cũng không thể cao hơn uplink của chính VPS. Khoảng cách tăng thêm sẽ thể hiện trong thời gian tải của mọi trang.
Hãy đo riêng hai phần. Tắt exit node, rồi kiểm tra riêng tunnel đến địa chỉ tailnet của VPS:
sudo tailscale set --exit-node=
sudo apt install -y iperf3
iperf3 -sChạy iperf3 -c 100.113.160.82 từ client đến địa chỉ tailnet đó. Kết quả này là tốc độ tunnel. Bây giờ bật lại exit node bằng sudo tailscale set --exit-node=100.113.160.82, rồi chạy speed test thông thường đến Internet công cộng. Kết quả này là tốc độ của tunnel cộng với uplink của VPS. Nếu kết quả đầu tốt nhưng kết quả sau kém, Tailscale không phải vấn đề. Hãy kiểm tra network và sizing của chính exit node. tailscale exit-node list hiển thị các lựa chọn nếu bạn không chắc mình đã chọn node nào.
CPU là yếu tố còn lại giới hạn tốc độ của exit node. Theo hướng dẫn của Tailscale, nên ưu tiên CPU thuộc thế hệ mới với clock speed cao hơn thay vì nhiều core hơn. Vì vậy, plan có nhiều vCPU hơn không tự động nhanh hơn trong trường hợp này. Trên shared host đang bận, CPU được cam kết không phải lúc nào cũng là CPU thực tế bạn nhận được. Steal time từ noisy neighbour sẽ biểu hiện thành throughput thay đổi theo từng giờ dù phía bạn không có thay đổi.
Một thiết lập tinh chỉnh duy nhất: rx-udp-gro-forwarding
Tailscale tài liệu hóa một thiết lập Linux duy nhất. Thiết lập này áp dụng cho các máy chuyển tiếp lưu lượng, tức exit node và subnet router. Client thông thường không hưởng lợi. Tính năng này cần Tailscale 1.54 trở lên và Linux kernel 6.2 trở lên, vì vậy hãy xác nhận cả hai trước khi thay đổi:
tailscale version
uname -rSau khi đã đáp ứng các điều kiện đó, hãy bật tính năng chuyển tiếp UDP GRO (generic receive offload) trên interface hướng ra Internet:
NETDEV=$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")
sudo ethtool -K $NETDEV rx-udp-gro-forwarding on rx-gro-list offKiểm tra xem thiết lập đã có hiệu lực chưa:
ethtool -k $NETDEV | grep -E 'rx-udp-gro-forwarding|rx-gro-list'Bạn phải thấy rx-udp-gro-forwarding: on và rx-gro-list: off. Thiết lập này hữu ích vì traffic của Tailscale sử dụng UDP. Khi kernel giữ các UDP packet nhỏ ở dạng đã được coalesced trong suốt đường chuyển tiếp, daemon sẽ xử lý ít segment lớn hơn với cùng số byte. ethtool -K không được giữ lại sau khi reboot, vì vậy hãy lưu cấu hình này. Trên hệ thống sử dụng networkd-dispatcher:
printf '#!/bin/sh\n\nethtool -K %s rx-udp-gro-forwarding on rx-gro-list off \n' "$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")" | sudo tee /etc/networkd-dispatcher/routable.d/50-tailscale
sudo chmod 755 /etc/networkd-dispatcher/routable.d/50-tailscaleChạy script thủ công một lần và kiểm tra exit status có bằng 0 không. Forwarding node cũng phải bật IP forwarding ngay từ đầu. Đây là một thiết lập riêng và có thể gây ra lỗi riêng:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.confInterface tailscale0 của bạn đang dùng MTU bao nhiêu?
Đừng đoán giá trị này. Hãy đọc trực tiếp trên máy:
ip link show tailscale0Giá trị mtu trong output đó là giá trị mà tunnel thực sự sử dụng. Giá trị này thấp hơn 1500 mà interface ethernet của bạn báo cáo. Đây là thiết kế có chủ đích, không phải lỗi. Mỗi packet bạn gửi bên trong tunnel đều được bọc thêm: IP header bên ngoài dài 20 byte với IPv4 hoặc 40 byte với IPv6, UDP header dài 8 byte, cùng phần framing và authentication tag của WireGuard dài 32 byte. Tất cả phải nằm trong giới hạn mà đường truyền thực tế có thể tải. Vì vậy, Tailscale chọn giá trị đủ thấp để hoạt động trên cả những đường truyền không tải được packet đủ 1500 byte. Trường hợp này gồm các kết nối PPPoE, một số mạng di động và tunnel IPv6.
Triệu chứng của lỗi MTU khá đặc trưng, nên không được chẩn đoán chỉ dựa vào việc kết nối chậm. SSH vẫn phản hồi, ping vẫn hoạt động, nhưng các lần truyền dữ liệu lớn hoặc các trang HTTPS lớn bị treo hoàn toàn thay vì chỉ chạy chậm. Mẫu này cho thấy packet quá lớn bị drop ở đâu đó, nhưng không có ICMP message quay về để báo cho bên gửi. Tăng MTU tailscale0 lên gần 1500 sẽ làm tình hình tệ hơn, vì các packet vốn đã không vừa sẽ còn lớn hơn. Cách xử lý đúng là tìm path MTU hoạt động bằng phương pháp chia đôi và giới hạn TCP MSS trên router chuyển tiếp lưu lượng. Loại kết nối không thay đổi điều này: path qua relay và path trực tiếp đều sử dụng cùng một MTU của interface.
FAQ
Làm thế nào biết kết nối Tailscale của tôi là kết nối trực tiếp hay qua relay?
Chạy tailscale status và đọc phần cuối dòng của peer. direct 203.0.113.9:41641 là kết nối trực tiếp, relay "tor" nghĩa là mọi packet đều đi qua DERP server đó, còn peer-relay nghĩa là packet đi qua một máy trong tailnet của bạn. Để kiểm tra thêm, chạy tailscale ping <peer>: đường truyền bình thường bắt đầu trên DERP rồi in ra một pong kèm địa chỉ và port thông thường, còn đường truyền qua relay sẽ in các DERP pong cho đến khi kết thúc bằng direct connection not established. Trước tiên hãy gửi một ít traffic đến peer, vì Tailscale chỉ tạo đường truyền khi có yêu cầu.
Vì sao VPS của tôi không bao giờ có kết nối trực tiếp?
Chạy tailscale netcheck trên VPS. Nếu kết quả là UDP: false, firewall egress đang drop UDP outbound và daemon đã chuyển sang DERP qua TCP 443. Vì vậy máy vẫn hiển thị là đang kết nối. Cho phép UDP outbound từ port 41641 đến mọi đích và UDP outbound đến mọi đích trên port 3478. Kiểm tra cả network firewall của provider lẫn firewall bên trong server, vì đây là 2 lớp kiểm soát riêng biệt và rule ufw không tác động đến firewall của provider.
Kết nối Tailscale qua relay có kém an toàn hơn kết nối trực tiếp không?
Không. DERP server chuyển tiếp các WireGuard packet mà nó không thể giải mã, vì các encryption key được tạo trên thiết bị của bạn và không bao giờ rời khỏi các thiết bị đó. Relay làm tăng latency và giảm throughput, không làm giảm tính bảo mật dữ liệu. Coordination server có thể kiểm soát việc thiết bị nào biết về thiết bị nào. Sự tách biệt giữa key material và connection metadata là điều cần hiểu trước khi quyết định tự host bao nhiêu thành phần.
Setting rx-udp-gro-forwarding có giúp mọi máy không?
Không. Setting này được tài liệu hóa cho các máy Linux forward traffic cho máy khác, tức là exit node và subnet router. Laptop hoặc server chỉ giao tiếp với các peer của chính nó sẽ không được lợi gì từ setting này. Setting này cũng yêu cầu Tailscale 1.54 trở lên và Linux kernel 6.2 trở lên. Vì vậy trước tiên hãy kiểm tra tailscale version và uname -r, đồng thời nhớ rằng ethtool -K sẽ reset sau khi reboot nếu bạn không lưu cấu hình persistent.
Tailscale có chậm hơn WireGuard thuần không?
Cả 2 đều dùng WireGuard để mã hóa traffic. Tailscale bổ sung phần thiết lập kết nối mà WireGuard thuần yêu cầu bạn tự cấu hình, và phần thiết lập này đôi khi khiến kết nối phải đi qua relay. WireGuard thuần không có relay để chuyển sang: nó kết nối trực tiếp hoặc hoàn toàn không kết nối được. Vì vậy hãy so sánh đúng các trường hợp tương đương, và chỉ benchmark Tailscale khi tailscale status cho biết direct. Nếu muốn dùng phiên bản cấu hình thủ công để so sánh, một WireGuard server tự dựng cần khoảng 40 dòng config. Phần đánh đổi này được trình bày trong so sánh 2 cách tiếp cận.