Chạy Tailscale subnet router trên VPS
Quảng bá mạng private vào tailnet từ VPS, duyệt route trong admin console, bật IP forwarding qua reboot và dùng --accept-routes trên Linux.
Tailscale subnet router làm gì
Tailscale subnet router là một máy quảng bá cả một dải địa chỉ IP private vào tailnet, để mọi thiết bị trong tailnet đều có thể truy cập các địa chỉ trong dải đó dù các thiết bị ở đó không chạy Tailscale. Tailnet là mạng Tailscale private của bạn: tập hợp các thiết bị đã đăng nhập vào cùng một tài khoản hoặc tổ chức. Exit node là tính năng thường bị nhầm với subnet router, nhưng nó thực hiện công việc ngược lại. Nó gửi toàn bộ traffic của một thiết bị qua VPS, để VPS trở thành tuyến kết nối của thiết bị đó ra public Internet.
Mỗi loại giải quyết một việc. Subnet router giúp một mạng private có thể truy cập từ tailnet. Exit node thay đổi nơi traffic public của bạn đi ra Internet. Nếu bạn cần loại thứ hai, hãy đọc cách chạy Tailscale exit node trên VPS. Đây là hai flag riêng biệt. Một VPS có thể chạy cả hai cùng lúc, nhưng chúng giải quyết các vấn đề khác nhau và có thể fail theo những cách khác nhau.
Khi VPS cần làm subnet router
Trường hợp phổ biến là một private network đã được nhà cung cấp cấp sẵn. VPS có một địa chỉ public và một interface thứ hai trên một phân đoạn private. Các server khác trên phân đoạn đó hoàn toàn không có địa chỉ public, chẳng hạn database tại 10.0.0.20 và máy đích backup tại 10.0.0.30. Cài Tailscale trên một VPS, quảng bá 10.0.0.0/24, rồi laptop của bạn có thể truy cập trực tiếp các địa chỉ private đó. Không cần thay đổi gì trên các server khác trong phân đoạn, và database vẫn không có địa chỉ public.
Trường hợp còn lại là một network nằm phía bên kia VPS. Đó có thể là LAN (local area network) tại nhà hoặc văn phòng phía sau router riêng, hoặc một rack gồm các appliance hoàn toàn không chạy được Tailscale, chẳng hạn managed switch hoặc NAS cũ có firmware bị khóa. Một Linux box trên network đó sẽ làm subnet router cho tất cả thiết bị còn lại.
Cả hai trường hợp đều có một yêu cầu chung. Subnet router phải truy cập được range mà nó quảng bá bằng routing table và firewall của chính nó. Tailscale không tự tạo kết nối đó. Tailscale chuyển traffic đến router rồi giao cho kernel forward.
Cài Tailscale và kiểm tra route cục bộ trước
curl -fsSL https://tailscale.com/install.sh | shScript xác định distribution, thêm package repository của Tailscale, cài command tailscale và daemon tailscaled, rồi enable service. Xác nhận bằng systemctl is-active tailscaled; kết quả phải là active.
Trước tiên, hãy xác nhận VPS có thể truy cập network mà bạn dự định quảng bá.
ip route show
ping -c3 10.0.0.20ip route show phải liệt kê private range trên một interface thực, chẳng hạn 10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5. Nếu ping thất bại ở đây, ngay trên router, thì không có flag Tailscale nào khắc phục được. Nguyên nhân nằm ở cấu hình network của VPS hoặc firewall trên host đích. Hãy sửa vấn đề đó trước, vì mọi kiểm tra tiếp theo đều phụ thuộc vào nó.
Bật IP forwarding và giữ cấu hình sau khi reboot
Linux sẽ loại bỏ mọi packet không được gửi đến chính nó nếu forwarding chưa được bật. Chuyển tiếp packet của các máy khác là nhiệm vụ chính của subnet router, nên không thể bỏ qua bước này.
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.confKiểm tra bằng sysctl net.ipv4.ip_forward. Lệnh này phải in ra net.ipv4.ip_forward = 1.
Nhiều người chỉ thực hiện đúng một nửa bước này. sudo sysctl -w net.ipv4.ip_forward=1 có hiệu lực ngay lập tức nhưng mất sau lần boot tiếp theo. Vì vậy, subnet router có thể chạy trong nhiều tuần rồi dừng vào buổi sáng sau khi reboot để nâng cấp kernel. Điểm gây nhầm lẫn là không có dấu hiệu rõ ràng cho thấy hệ thống bị lỗi. tailscale status vẫn hiển thị node đang online, admin console vẫn hiển thị route đã được phê duyệt, và các client vẫn cài route đó. Packet đến VPS nhưng kernel loại bỏ chúng mà không ghi log. Ghi các giá trị vào /etc/sysctl.d/99-tailscale.conf là cách để khôi phục chúng sau khi reboot.
Nếu bạn advertise route trong khi forwarding vẫn tắt, tailscale up sẽ cảnh báo ngay lúc đó bằng một dòng gần giống Warning: IPv4 forwarding is disabled. Subnet routes and exit nodes may not work correctly.. Hãy đọc output của lệnh này thay vì bỏ qua nó.
Quảng bá các route
sudo tailscale up --advertise-routes=10.0.0.0/24Trên VPS đã đăng nhập vào tailnet, hãy thay đổi thiết lập trực tiếp thay vì tạo lại:
sudo tailscale set --advertise-routes=10.0.0.0/24Dùng tailscale set cho mọi thay đổi sau đó. Chạy lại tailscale up với chỉ một flag sẽ reset các flag mà bạn không lặp lại. CLI sẽ dừng và báo lỗi rằng khi thay đổi thiết lập theo cách này, bạn phải nêu tất cả flag khác giá trị mặc định. tailscale set chỉ thay đổi một thiết lập và giữ nguyên các thiết lập còn lại.
Có thể khai báo nhiều range trong một danh sách phân tách bằng dấu phẩy, không có khoảng trắng: --advertise-routes=10.0.0.0/24,192.168.50.0/24. Mỗi mục phải là một network address ở dạng CIDR (classless inter-domain routing, dạng 10.0.0.0/24). Nếu vô tình ghi địa chỉ host của chính bạn, 10.0.0.5/24, lệnh sẽ bị từ chối vì các bit sau prefix không bằng 0. Thông báo lỗi sẽ nêu prefix mà có thể bạn định dùng. Để dừng quảng bá, đặt danh sách rỗng bằng sudo tailscale set --advertise-routes=.
Phê duyệt route trong admin console
Quảng bá một route chỉ là một yêu cầu, không phải thay đổi đã được áp dụng. Cho đến khi admin phê duyệt, không client nào nhận được route và không tài nguyên nào trong dải đó có thể truy cập được. Đây là cơ chế có chủ ý, vì một máy có thể tự thêm mình vào routing table của mọi người sẽ có thể chặn traffic của bất kỳ dải nào nó muốn.
Hãy phê duyệt route trên trang Machines của admin console. VPS được liệt kê kèm subnet badge. Mở dòng của VPS, tìm phần subnets, chỉnh sửa route settings, chọn route rồi lưu.
Phê duyệt được thực hiện theo từng prefix. Hôm nay bạn quảng bá 10.0.0.0/24 và tháng sau quảng bá 192.168.50.0/24, prefix mới sẽ bắt đầu ở trạng thái chưa được phê duyệt, còn prefix cũ vẫn hoạt động. Từ phía VPS, route đã được phê duyệt và route bị bỏ qua trông giống hệt nhau, vì vậy hãy kiểm tra console trước khi debug bất kỳ phần nào khác.
Bạn có thể bỏ qua bước thủ công bằng một block autoApprovers trong policy file của tailnet:
{
"autoApprovers": {
"routes": {
"10.0.0.0/24": ["tag:subnet-router"]
}
}
}Sau đó đưa node lên cùng tag đó, sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router, và route sẽ được phê duyệt ngay khi được quảng bá. Tag này phải tồn tại trước trong phần tagOwners của cùng policy file. Bạn nên thiết lập cách này nếu rebuild VPS bằng script, vì node được rebuild là một node mới và các route của nó sẽ lại bắt đầu ở trạng thái chưa được phê duyệt.
Vì sao client Linux bỏ qua route nếu không có --accept-routes
Route đã được quảng bá và phê duyệt. Điện thoại và Mac của bạn có thể truy cập 10.0.0.20. Laptop Linux của bạn thì không, nhưng admin console không cho thấy vấn đề nào.
Chấp nhận subnet route nghĩa là ghi các entry vào routing table của client. Trên Android, iOS, macOS, tvOS và Windows, Tailscale client tự làm việc này. Trên Linux thì không, vì máy Linux thường là server hoặc router có routing table được cấu hình có chủ đích. Việc âm thầm chèn một /24 học được từ network có thể làm hỏng traffic mà máy đó đang xử lý. Vì vậy, trên Linux, bạn phải opt in trên từng client:
sudo tailscale set --accept-routesSau đó kiểm tra route đã được thêm vào đâu:
ip route show table 52
ip route get 10.0.0.20Tailscale trên Linux không đặt các route đã chấp nhận vào main routing table. Nó đặt chúng vào routing table 52 và cài các policy rule. Bạn có thể xem các rule này bằng ip rule show trong priority range từ 5210 đến 5270. Các rule đó chuyển những packet không khớp sang table này. Vì vậy, riêng ip route show sẽ không bao giờ liệt kê 10.0.0.0/24. Người chỉ kiểm tra lệnh đó sẽ kết luận rằng --accept-routes không làm gì cả. ip route show table 52 mới là lệnh hiển thị trạng thái thực tế, và kết quả phải liệt kê range đã quảng bá trên tailscale0.
Có một ngoại lệ cần biết. Nếu node Linux này cũng là subnet router thứ hai cho local network của chính nó, --accept-routes sẽ khiến node gửi traffic đến subnet được kết nối trực tiếp của nó qua router còn lại, thay vì qua interface của chính nó. Trên router dự phòng trong một cặp high availability, hãy để --accept-routes tắt và chỉ quảng bá route.
Chế độ lỗi: hai router quảng bá các dải địa chỉ chồng lấn
Hai subnet router không được quảng bá các dải địa chỉ giống hệt nhau. Các dải chồng lấn nhưng có độ dài prefix khác nhau vẫn được phép, và Tailscale sẽ chọn tuyến khớp cụ thể nhất. Khi router A quảng bá 10.0.0.0/24 còn router B quảng bá 10.0.0.0/16, lưu lượng đến 10.0.0.20 sẽ đi qua A.
Điểm dễ gây bất ngờ là hành vi khi A offline. Tailscale không chuyển sang tuyến ít cụ thể hơn. Lưu lượng đến 10.0.0.20 sẽ dừng, còn lưu lượng đến 10.1.0.20 vẫn hoạt động qua B. Triệu chứng trông như một nửa mạng riêng bị mất kết nối, nhưng nguyên nhân là một node offline đang giữ prefix cụ thể hơn. Nếu muốn có failover, hãy để router có dải rộng hơn cũng quảng bá các prefix hẹp hơn, để cả hai cùng bao phủ các địa chỉ đó.
Một kiểu chồng lấn khác xảy ra gần phía client hơn. Khi bạn đang dùng mạng khách sạn tại 192.168.1.0/24 trong lúc subnet router quảng bá 192.168.1.0/24, hai tuyến sẽ cùng cạnh tranh cho các đích giống nhau. Tuyến nào thắng phụ thuộc vào platform. Trên Linux, hãy thêm một rule đứng trước rule riêng của Tailscale để các địa chỉ local sử dụng main table:
sudo ip rule add to 192.168.1.0/24 priority 2500 lookup mainRule này không persistent và sẽ mất sau lần boot tiếp theo. Cách xử lý thực sự là chọn một private range mà bạn sẽ không gặp trên các mạng khác. 192.168.0.0/24 và 192.168.1.0/24 là các giá trị mặc định trên hầu hết home router, vì vậy hãy chọn một dải bên trong 10.0.0.0/8 theo chủ ý của bạn. Xung đột tương tự cũng làm hỏng WireGuard VPN thông thường mà bạn tự cấu hình, vì cùng lý do: route local cụ thể hơn sẽ thắng, nên lưu lượng không bao giờ đi vào tunnel.
Chế độ lỗi: DNS phân giải thành địa chỉ không có route bao phủ
Trường hợp này khó debug vì không có thành phần nào báo lỗi. Tên được phân giải thành công. Kết nối bị timeout.
Giả sử db.internal.example.com được private nameserver phân giải thành 10.0.5.20, còn bạn đã quảng bá 10.0.0.0/24. Tra cứu vẫn thành công vì phân giải DNS (domain name system) và định tuyến IP là hai bước riêng biệt, không bước nào kiểm tra bước kia. Sau đó, packet đi đến 10.0.5.20 không tìm thấy route phù hợp trên tailnet, nên đi ra qua default gateway của client rồi biến mất.
Hai lệnh dưới đây tách riêng hai phần:
nslookup db.internal.example.com
ip route get 10.0.5.20Nếu lệnh tra cứu trả về một địa chỉ nhưng ip route get không phản hồi với dev tailscale0, thì tên không có vấn đề và route đang thiếu. Hãy quảng bá một range bao phủ địa chỉ đó, bằng 10.0.0.0/16 hoặc bằng một prefix tường minh thứ hai, rồi approve prefix mới trong console.
Nameserver cũng có một lỗi tương tự. Nếu bạn đặt nameserver toàn cục trong admin console tại một địa chỉ private như 10.0.0.53, địa chỉ đó phải nằm trong một route đã được approve. Nếu không, thiết bị của bạn hoàn toàn không thể truy cập resolver. Nếu bật tùy chọn ghi đè DNS server cục bộ trong khi trỏ đến một resolver mà không thiết bị nào có thể truy cập, mọi thiết bị trong tailnet sẽ mất khả năng phân giải tên cùng lúc, kể cả những thiết bị vừa hoạt động bình thường trước đó. Hãy quảng bá và approve route đến resolver trước, rồi mới thay đổi DNS setting. Nếu DNS bên trong tunnel là phần bạn thường xuyên phải xử lý, cách DNS bị lỗi qua tunnel WireGuard mô tả cùng cơ chế này mà không có thêm lớp điều phối.
NAT nguồn và kết nối site-to-site
Mặc định, subnet router sẽ ghi đè địa chỉ nguồn của mọi packet được forward bằng địa chỉ private của chính nó. Đây là SNAT (source network address translation). Cơ chế này giúp các gói trả lời hoạt động mà không cần thay đổi gì trên private network: database tại 10.0.0.20 trả lời VPS, vì nó đã biết cách truy cập VPS. Đổi lại, database thấy mọi kết nối từ tailnet đều đến từ VPS, nên firewall rule theo source và access log không cung cấp thông tin hữu ích.
Tắt SNAT trên Linux khi bạn muốn giữ nguyên địa chỉ tailnet thực của client:
sudo tailscale set --snat-subnet-routes=falseKhi đó, các host trên private network cần có route quay về 100.64.0.0/10, là dải địa chỉ Tailscale cấp cho các thiết bị, trỏ đến subnet router. Nếu không có route quay về này, các gói trả lời sẽ đi đến default gateway và không bao giờ đến nơi, khiến kết nối bị treo sau packet đầu tiên. Thêm static route trên gateway của private network, hoặc giữ SNAT bật.
Kết nối site-to-site là khi hai subnet router cùng thực hiện việc này, mỗi router quảng bá network của mình và chấp nhận network của router còn lại:
sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routesChạy command tương ứng trên router còn lại với dải địa chỉ riêng của router đó. Hai dải địa chỉ phải khác nhau. Nếu các lượt truyền dữ liệu lớn bị treo trong khi ssh và ping vẫn hoạt động bình thường, nguyên nhân là MSS (maximum segment size), tức kích thước lớn nhất của phần dữ liệu mà một TCP packet có thể mang. Overhead của tunnel khiến packet được forward quá lớn đối với một link nào đó trên đường đi, và việc clamping sẽ khắc phục vấn đề này:
sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuLưu rule đó bằng iptables-persistent, nếu không rule sẽ biến mất sau lần boot tiếp theo.
Công việc bảo trì để hệ thống luôn hoạt động
Mặc định, node key hết hạn sau 180 ngày kể từ tháng 8 năm 2026. Khi key trên subnet router hết hạn, node sẽ đăng xuất và toàn bộ dải mạng được quảng bá trở nên không thể truy cập. Không có thay đổi cấu hình nào ở nơi khác để giải thích sự cố này. Hãy tắt tính năng hết hạn key cho máy này trên trang Machines của admin console, rồi ghi lại rằng bạn đã thực hiện việc đó.
Tailscale ưu tiên kết nối trực tiếp giữa các peer và chuyển sang relay server khi không thiết lập được kết nối trực tiếp. Relay vẫn hoạt động, nhưng làm tăng latency. VPS có địa chỉ public là trường hợp đơn giản: cho phép UDP inbound trên cổng 41641, và phần lớn peer sẽ kết nối trực tiếp. Nếu ufw đang quản lý firewall, các rule ufw mà một VPS thực sự cần sẽ trình bày đúng cú pháp.
Access rule là phần còn lại. Với tailnet mặc định, mọi device của bạn đều có thể truy cập mọi device khác, nên route đã được phê duyệt sẽ hoạt động ngay. Khi viết chính sách ACL, phía đích của rule phải chỉ rõ private range, vì 10.0.0.20 không phải là địa chỉ tailnet và không được các rule viết theo tailnet IP hoặc tag áp dụng.
Cuối cùng, hãy quyết định xem bạn có muốn dùng một coordination server do bên khác vận hành hay không. Control plane của Tailscale là một hosted service. Key vẫn nằm trên các máy của bạn, nhưng account và policy file nằm trên server đó. Chạy Headscale, control server Tailscale tự host sẽ giữ các thành phần này trên VPS của bạn, nhưng bạn phải tự bảo trì. Nếu vẫn đang cân nhắc giữa mô hình này và cấu hình viết thủ công, bài so sánh WireGuard và Tailscale giải thích coordination layer cung cấp gì và chi phí phải trả là gì.
FAQ
Subnet router và exit node khác nhau thế nào?
Subnet router quảng bá một dải địa chỉ private, để các thiết bị trong tailnet có thể truy cập những máy không chạy Tailscale. Exit node tự quảng bá là route đến toàn bộ Internet, nên thiết bị gửi toàn bộ traffic qua địa chỉ public của node đó. Một VPS có thể làm cả hai. Đây là hai flag riêng biệt, --advertise-routes và --advertise-exit-node, và mỗi flag cần được phê duyệt riêng trong admin console.
Vì sao Linux client bỏ qua subnet route đã quảng bá?
Linux client không tự chấp nhận subnet route nếu bạn không yêu cầu. Chạy sudo tailscale set --accept-routes trên client. Sau đó kiểm tra bằng ip route show table 52, không dùng ip route show. Tailscale cài các route đã được chấp nhận vào routing table 52 và truy cập chúng thông qua policy rule, nên main table không liệt kê các route này và một route đang hoạt động có thể trông như bị thiếu.
Subnet của tôi ngừng hoạt động sau khi reboot. Lỗi ở đâu?
Nhiều khả năng là IP forwarding. Giá trị đặt bằng sysctl -w sẽ không tồn tại sau reboot, nên hãy ghi nó vào /etc/sysctl.d/99-tailscale.conf và xác nhận bằng sysctl net.ipv4.ip_forward. Nếu forwarding đã bật mà dải địa chỉ vẫn không truy cập được, hãy kiểm tra node trong admin console. Node key mặc định hết hạn sau 180 ngày. Khi subnet router hết hạn, sự cố trông giống lỗi mạng thay vì lỗi tài khoản.
Hai subnet router có thể quảng bá cùng một dải không?
Không nếu hai dải giống hệt nhau. Các dải chồng lấn nhưng có prefix length khác nhau vẫn được, và route cụ thể nhất sẽ được ưu tiên. Cần cẩn thận khi cấu hình failover: khi router đang giữ prefix cụ thể hơn offline, Tailscale không chuyển sang route rộng hơn, nên traffic đó sẽ dừng. Để tạo một cặp standby thực sự, hãy cho cả hai router quảng bá cùng các prefix cụ thể.
Hostname phân giải được nhưng kết nối bị timeout. Vì sao?
DNS resolution và routing là hai bước riêng biệt. Một tên có thể phân giải thành địa chỉ mà không route nào được phê duyệt bao phủ, nên packet sẽ đi qua default gateway của client. Chạy ip route get <address> trên client. Nếu kết quả không chứa dev tailscale0, hãy quảng bá một dải bao phủ địa chỉ đó và phê duyệt prefix mới trong admin console.