WireGuard không truy cập được LAN gia đình: cách sửa
Handshake WireGuard vẫn hoạt động nhưng 192.168.20.10 không trả lời? Kiểm tra 4 thiết lập: AllowedIPs, IP forwarding, firewall và route quay về LAN.
Vì sao mạng LAN gia đình không phản hồi qua WireGuard
Để định tuyến đến mạng LAN gia đình qua WireGuard, 4 thiết lập riêng biệt phải khớp với nhau. Đúng 3 trong 4 thiết lập vẫn tạo ra một tunnel trông hoàn toàn bình thường. Đây là lý do lỗi này khó chẩn đoán. wg show báo có handshake gần đây, ping 10.8.0.1 phản hồi trong vài mili giây, còn ping 192.168.20.10 hoàn toàn không trả về gì.
Dưới đây là toàn bộ danh sách, theo thứ tự một packet đi qua. LAN là viết tắt của local area network, tức mạng riêng phía sau router gia đình.
AllowedIPstrên client phải bao phủ subnet ở xa. Nếu không, packet không bao giờ đi vào tunnel.AllowedIPstrên server phải bao phủ địa chỉ tunnel của client. Nếu không, packet bị drop ngay sau khi giải mã.net.ipv4.ip_forwardphải là1trên server, vì Linux drop mọi packet không được gửi đến chính máy đó.- LAN phải biết route quay về
10.8.0.0/24, thông qua masquerade rule trên server hoặc static route trên router gia đình.
Mỗi thiết lập này đều có thể fail mà không có error message. Không có gì được ghi vào log và không có cảnh báo nào xuất hiện. Handshake vẫn hoạt động suốt thời gian đó. Hãy kiểm tra theo đúng thứ tự. Bạn thường sẽ xác định được thiết lập bị lỗi trong khoảng 1 phút.
Mạng được dùng trong hướng dẫn này
Mọi địa chỉ bên dưới đều là ví dụ. Hãy thay bằng địa chỉ của bạn và giữ nhất quán trong toàn bộ cấu hình, vì cấu hình cập nhật dở dang là nguyên nhân phổ biến thứ hai gây ra vấn đề này.
- LAN gia đình là
192.168.20.0/24. Router gia đình là192.168.20.1. - WireGuard server là một máy Linux trong LAN đó. Interface LAN của máy là
enp1s0và giữ192.168.20.5, còn tunnel interface làwg0và giữ10.8.0.1. - Host bạn muốn truy cập là một NAS (network attached storage) tại
192.168.20.10. - Client là một laptop ở nơi khác, có địa chỉ
10.8.0.2bên trong tunnel.
Server là một máy trong LAN, không phải chính router. Đây là trường hợp thông thường, chẳng hạn Raspberry Pi hoặc một mini PC cũ. Điều này quan trọng đối với rule 4: router không biết tunnel tồn tại nếu bạn không cấu hình cho nó, và mọi host trong LAN đều gửi traffic đến các subnet khác qua router đó.
Nếu kết nối Internet tại nhà không có public IP address, cách này sẽ không tự hoạt động, vì không có thiết bị nào trên Internet có thể mở handshake đến mạng nhà bạn. Phần về việc đặt một VPS ở giữa sẽ trình bày trường hợp này. 4 rule tương tự vẫn áp dụng, nhưng có thêm một peer cần theo dõi cho đúng.
AllowedIPs có hai ý nghĩa khác nhau
Một setting thực hiện hai nhiệm vụ. Đọc nó theo cùng một cách ở cả hai đầu là nguyên nhân của phần lớn các ticket này. WireGuard gọi cơ chế này là cryptokey routing, được mô tả chi tiết hơn trong cách WireGuard liên kết public key với các dải IP.
Khi đọc theo chiều outbound, AllowedIPs là một routing table. wg-quick biến mỗi entry thành một route trỏ đến wg0. Một packet đến 192.168.20.10 chỉ được mã hóa và gửi đến một peer nếu có peer khai báo một range chứa địa chỉ đó. Chỉ liệt kê 10.8.0.0/24 khiến laptop gửi traffic LAN ra Wi-Fi cục bộ, nơi traffic có thể bị mất hoặc đi đến một 192.168.20.10 hoàn toàn khác.
Khi đọc theo chiều inbound, AllowedIPs là một access control list. Sau khi WireGuard giải mã packet từ một peer, nó kiểm tra địa chỉ source bên trong packet với AllowedIPs của peer đó và drop packet nếu không khớp. Không có log line hay counter nào cho lần drop này. Packet chỉ đơn giản biến mất.
Vì vậy, hai file cấu hình không bao giờ là ảnh phản chiếu của nhau. Client liệt kê những gì nó muốn truy cập thông qua server. Server liệt kê những địa chỉ source mà client đó được phép sử dụng.
Cặp file cấu hình tương ứng
Client, /etc/wireguard/wg0.conf:
[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
[Peer]
PublicKey = <server public key>
Endpoint = home.example.com:51820
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24
PersistentKeepalive = 25Server, /etc/wireguard/wg0.conf:
[Interface]
PrivateKey = <server private key>
Address = 10.8.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <laptop public key>
AllowedIPs = 10.8.0.2/32Router tại nhà cũng cần port forward UDP 51820 đến 192.168.20.5. Nếu không, handshake sẽ không bắt đầu và log của client sẽ ghi Handshake for peer 1 did not complete after 5 seconds, retrying. Hướng dẫn này giả định bạn đã xử lý xong phần đó.
Bốn dòng khác với cấu hình full-tunnel thông thường. Mỗi thay đổi đều có chủ đích.
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24trên client, thay cho0.0.0.0/0, ::/0. Đây là split tunnel: subnet của tunnel và LAN tại nhà đi quawg0, còn mọi lưu lượng khác vẫn dùng route cục bộ. Lưu lượng web không đi qua kết nối tại nhà của bạn. Đây thường là điều bạn muốn khi chỉ cần truy cập NAS.AllowedIPs = 10.8.0.2/32trên server, dùng một địa chỉ thay vì một range. Ghi10.8.0.0/24tại đó thì client duy nhất này có thể nhận bất kỳ địa chỉ nào trong tunnel. Nếu sau đó thêm một peer có range chồng lấn, traffic sẽ chuyển đến peer được cấu hình sau cùng, mà không có lỗi nào được in ra.- Chỉ có
PersistentKeepalive = 25trên client. Client nằm sau NAT (network address translation), và router của client sẽ xóa mapping UDP sau một hoặc hai phút không có traffic. Khi đó server không thể tiếp cận client nữa. Server có địa chỉ public nên không cần keepalive. - Chưa có dòng
DNS =. Thêm dòng này sẽ thay đổi việc phân giải tên cho toàn bộ máy client. Phần DNS bên dưới giải thích tác dụng của dòng này trước khi bạn bật nó.
Full tunnel cũng truy cập được LAN, vì 0.0.0.0/0 khớp với mọi địa chỉ. Tuy nhiên, nó khiến toàn bộ traffic của bạn đi qua tunnel và tạo ra một xung đột subnet mà bạn không thể sửa từ client.
Vì sao dùng cùng subnet ở hai đầu sẽ làm kết nối hỏng
Chọn một subnet gia đình mà hầu như không ai khác sử dụng, chẳng hạn như 192.168.20.0/24 hoặc 10.44.7.0/24. 192.168.1.0/24 và 192.168.0.0/24 là giá trị mặc định của nhà sản xuất trên hầu hết router dân dụng, nên sớm muộn gì laptop của bạn cũng sẽ kết nối vào mạng ở quán cà phê hoặc khách sạn sử dụng đúng dải đó.
Xung đột này khiến kết nối dừng hoàn toàn và biểu hiện khác nhau trong hai trường hợp. Với split tunnel, wg-quick cố thêm một route cho prefix đã tồn tại trên interface Wi-Fi, ip route add từ chối, nên interface không thể khởi động:
RTNETLINK answers: File existsVới full tunnel, wg-quick cài các policy routing rule để cố ý giữ những route cụ thể hơn khỏi main table. Route 192.168.1.0/24 cục bộ có độ ưu tiên cao hơn tunnel, nên mọi packet đến remote LAN đều đi qua link cục bộ. Tunnel vẫn hoạt động, handshake vẫn bình thường, nhưng không thể truy cập NAS. Đổi subnet của LAN gia đình là cách khắc phục thực sự duy nhất.
Biến server thành router
ip route show default
printf 'net.ipv4.ip_forward = 1\n' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forwardLệnh đầu tiên cho biết tên thực của interface LAN. Các image hiện nay thường dùng những tên như enp1s0 hoặc ens3, hiếm khi là eth0. Rule masquerade ghi sai interface sẽ không match được gói nào. Lệnh cuối cùng phải in ra net.ipv4.ip_forward = 1. Lệnh sudo sysctl -w không có đối số cũng đặt cùng giá trị, nhưng giá trị này sẽ mất sau lần reboot tiếp theo. Đây là nguyên nhân kinh điển của tình trạng “chạy được cho đến thứ Ba”.
Forwarding cũng phải được cho phép qua firewall. Trên Ubuntu khi ufw đang active, các packet được forward sẽ bị drop nếu DEFAULT_FORWARD_POLICY="ACCEPT" chưa được đặt trong /etc/default/ufw. Docker tự đặt policy tương tự, nên nếu sudo iptables -S FORWARD | head -1 in ra -P FORWARD DROP trên một máy mà bạn chưa từng tự cấu hình firewall, thì Docker đã đặt policy đó. Khi đó, tunnel traffic của bạn cần một accept rule cụ thể.
Vì sao reply không bao giờ quay về
Nếu cấu hình đúng rules 1 đến 3, ping thực sự đã đến NAS. Tuy nhiên bạn vẫn không thấy reply, vì reply không có đường quay về. NAS trả lời 10.8.0.2, một địa chỉ nằm ngoài subnet của nó, nên chuyển packet đến default gateway là home router tại 192.168.20.1. Router đó chưa từng biết đến 10.8.0.0/24, nên chuyển reply đến default gateway của chính nó, tức đường kết nối Internet, rồi packet bị drop. Request đến nơi, nhưng reply bị loại bỏ.
Tùy chọn A: masquerade trên WireGuard server. Server rewrite source address của mọi packet được forward thành 192.168.20.5, là địa chỉ LAN của chính server. NAS lúc này thấy request đến từ một thiết bị cùng subnet, reply thẳng về server, rồi server đảo ngược việc rewrite và gửi reply trở lại qua tunnel. Không cần thay đổi gì trên các thiết bị khác trong LAN.
Đặt rule này trong block [Interface] của server để rule được tạo và xóa cùng interface:
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp1s0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o enp1s0 -j MASQUERADETrên máy đã được quản lý bằng nftables, thay vào đó hãy viết rule vào /etc/nftables.conf:
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.8.0.0/24 oifname "enp1s0" counter masquerade
}
}Giữ keyword counter. Nếu thiếu keyword này, sudo nft list ruleset sẽ in rule mà không có packet count. Chính packet count cho biết rule có đang được sử dụng hay không.
Masquerade còn có một lợi ích thứ hai dễ bị bỏ qua. Nhiều host chạy firewall chỉ chấp nhận connection từ subnet của chính chúng. Windows file sharing mặc định hoạt động theo cách này, và một số NAS admin panel cũng vậy. Target host sẽ drop packet từ 10.8.0.2 ngay cả khi routing hoàn toàn chính xác. Sau khi masquerade, source là một địa chỉ LAN nên các rule đó sẽ match. Đổi lại, mọi tunnel client đều xuất hiện dưới dạng 192.168.20.5 trong log của mọi host trên LAN. Vì vậy bạn không thể phân biệt các client, và per-client rule trên thiết bị LAN sẽ không hoạt động.
Tùy chọn B: static route trên home router. Khai báo với router rằng 10.8.0.0/24 nằm phía sau 192.168.20.5. Trên Linux router, chỉ cần một command:
sudo ip route add 10.8.0.0/24 via 192.168.20.5Consumer router thường có trang Static Routes hoặc Routing trong phần advanced settings: destination 10.8.0.0, mask 255.255.255.0, gateway 192.168.20.5. Hãy lưu route vào stored configuration của router, vì một ip route add được nhập trên Linux box sẽ mất sau lần reboot tiếp theo.
Cách này giữ nguyên client address thực, nên log và per-client rule trên LAN vẫn có ý nghĩa. Tuy nhiên cần router hỗ trợ static route, và chỉ có tác dụng với các host dùng router đó làm default gateway. Host nào có local firewall giới hạn theo subnet vẫn cần rule riêng cho 10.8.0.0/24. Hãy bắt đầu bằng masquerade vì không cần thay đổi gì bên ngoài box mà bạn đã kiểm soát, sau đó chuyển sang static route khi cần giữ client address thực.
Cách xác định mục nào trong 4 mục bị sai
Hãy kiểm tra từ phía client ra ngoài. Mỗi bước cho biết packet đã đi được đến đâu.
Packet có đi vào tunnel không? Trên client:
ip route get 192.168.20.10Kết quả phải hiển thị dev wg0. Nếu kết quả hiển thị interface Wi-Fi, rule 1 bị sai và AllowedIPs trên client không bao phủ subnet LAN. Một ping: connect: Network is unreachable cũng chỉ ra cùng dòng cấu hình đó.
Packet có đến server không? Chạy lệnh này trên server, sau đó ping NAS từ client:
sudo tcpdump -ni wg0 icmpĐường truyền hoạt động sẽ hiển thị IP 10.8.0.2 > 192.168.20.10: ICMP echo request. ICMP là Internet Control Message Protocol, giao thức mà ping sử dụng. Nếu không có kết quả nào ở đây dù handshake vẫn bình thường, nguyên nhân là rule 2: AllowedIPs của server cho peer đó không bao gồm 10.8.0.2, nên packet bị drop trong bước decryption trước khi đến wg0.
Packet có rời server để đi vào LAN không? Trên server, theo dõi phía LAN:
sudo tcpdump -ni enp1s0 icmpNếu thấy request trên wg0 nhưng không thấy gì ở đây, nguyên nhân là rule 3. Forwarding đang tắt hoặc một rule trong chain FORWARD đã drop packet. Nếu thấy request ở đây với source 10.8.0.2 nhưng không có reply, nguyên nhân là rule 4. Reply không có route quay lại. Nếu thấy request ở đây với source 192.168.20.5 nhưng không có reply, masquerade rule đang hoạt động và chính host đích đang từ chối kết nối. Hãy kiểm tra firewall trên NAS. Cách kiểm tra này cũng áp dụng cho các dịch vụ khác. Chỉ cần thay icmp bằng port 445 hoặc port bạn cần kiểm tra.
Tôi truy cập được IP nhưng không truy cập được bằng tên
ssh 192.168.20.10 hoạt động nhưng ssh nas.home.arpa thất bại:
ssh: Could not resolve hostname nas.home.arpa: Name or service not knownTunnel không có vấn đề. Phân giải tên là một đường đi riêng, và laptop của bạn vẫn đang gửi yêu cầu đến resolver mà nó nhận từ Wi-Fi cục bộ. Resolver đó không biết các tên trên mạng gia đình của bạn.
Có 2 điều kiện để tên trong mạng gia đình hoạt động. Địa chỉ của resolver phải nằm trong AllowedIPs trên client, nếu không truy vấn DNS (domain name system) sẽ không đi vào tunnel. Resolver cũng phải chấp nhận truy vấn có địa chỉ nguồn là 10.8.0.2. Nhiều resolver trong mạng gia đình mặc định từ chối kiểu truy vấn này: dnsmasq chạy với local-service chỉ trả lời truy vấn từ một subnet được kết nối trực tiếp, còn Pi-hole mặc định có listening mode chỉ cho phép request cục bộ. Rule masquerade che giấu vấn đề này, vì sau khi rewrite, truy vấn sẽ đến từ 192.168.20.5.
Phía client chỉ cần thêm một dòng:
DNS = 192.168.20.1Trên Linux client cần có openresolv hoặc cấu hình tương đương. Nếu không, wg-quick sẽ dừng với resolvconf: command not found. Trên máy chạy systemd-resolved, hãy hiểu rõ tác động của cấu hình này trước khi đặt: wg-quick đăng ký độc quyền các server đó, nên khi tunnel đang hoạt động, mọi lần lookup trên laptop đều được gửi đến resolver trong mạng gia đình, không chỉ các tên trong mạng gia đình. Kiểm tra kết quả bằng resolvectl status wg0. Nếu bạn muốn phân giải tên trong mạng gia đình tại mạng gia đình, còn mọi tên khác được phân giải cục bộ, đó là split DNS. Bài cấu hình DNS qua tunnel WireGuard trình bày đầy đủ cách thiết lập.
Không có IP public ở nhà? Đặt một VPS ở giữa
Nếu trang trạng thái của router hiển thị địa chỉ WAN nằm trong 100.64.0.0/10 hoặc địa chỉ private 192.168.x.x, bạn đang ở sau CGNAT (carrier grade network address translation), nên không có handshake nào từ Internet có thể đến được mạng nhà bạn. Handshake đi ra ngoài vẫn hoạt động bình thường, vì vậy cách xử lý là thêm một node thứ ba có địa chỉ public. Một VPS nhỏ chạy hub, còn máy ở nhà chủ động kết nối ra VPS đó.
4 quy tắc không thay đổi. Chúng chỉ áp dụng qua 2 hop, nên phần ghi chép địa chỉ tăng gấp đôi.
- Trên VPS, peer entry của máy ở nhà nhận
AllowedIPs = 10.8.0.3/32, 192.168.20.0/24: địa chỉ tunnel của chính nó, cộng với subnet mà nó được phép đại diện. - Trên VPS, peer entry của laptop vẫn giữ
AllowedIPs = 10.8.0.2/32. - Trên laptop, peer của VPS nhận
AllowedIPs = 10.8.0.0/24, 192.168.20.0/24, vì bây giờ mọi traffic đều đi đến hub. - Trên máy ở nhà, peer của VPS nhận
AllowedIPs = 10.8.0.0/24, còn máy ở nhà mangPersistentKeepalive = 25, vì bây giờ đây là phía nằm sau NAT. - VPS cũng cần
net.ipv4.ip_forward = 1, và forward chain của nó phải cho phépwg0đếnwg0, vì traffic từ laptop đi vào và đi ra trên cùng một interface. Một firewall được viết cho VPS full-tunnel thông thường sẽ chặn đúng trường hợp này.
Nếu bạn chưa dựng xong phía VPS, thiết lập WireGuard trên VPS trình bày cách tạo key, cấu hình firewall và systemd unit. Mô hình tổng quát để truy cập một máy không thể nhận kết nối đến từ bên ngoài được trình bày trong mở reverse tunnel từ phía sau CGNAT. Khi việc tự quản lý địa chỉ peer không còn thuận tiện, chạy Tailscale subnet router sẽ thực hiện cùng công việc định tuyến và tự động hóa việc quản lý địa chỉ.
Duy trì sau khi reboot
sudo systemctl enable --now wg-quick@wg0
sudo systemctl enable --now nftables
sudo wg showenable --now là phần nhiều người bỏ qua. Một wg-quick up wg0 chạy thủ công sẽ biến mất sau lần nâng cấp kernel và reboot tiếp theo. wg show phải hiển thị peer với dòng latest handshake mới và các bộ đếm truyền dữ liệu khác 0 theo cả hai chiều.
Sau này thêm client thứ hai không cần restart, vì restart sẽ ngắt tất cả các client đang kết nối:
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'wg-quick strip in cấu hình mà không có các key chỉ wg-quick hiểu, còn syncconf áp dụng phần khác biệt khi các session đang hoạt động vẫn tiếp tục chạy. Lệnh này chỉ cập nhật peer. Nếu thay đổi Address hoặc thêm dòng PostUp thì vẫn phải down rồi up hoàn toàn.
FAQ
Tại sao tôi ping được WireGuard server nhưng không truy cập được gì khác trong LAN gia đình?
Ping được 10.8.0.1 chỉ xác nhận tunnel đang hoạt động. Phần còn lại của LAN là vấn đề định tuyến. AllowedIPs của client phải bao gồm 192.168.20.0/24, nếu không packet sẽ không đi vào tunnel. Server cần đặt net.ipv4.ip_forward thành 1, nếu không nó sẽ loại bỏ mọi packet không gửi đến chính nó. LAN cũng cần có route quay về 10.8.0.0/24. Chạy sudo tcpdump -ni enp1s0 icmp trên server trong lúc ping: nếu request đi ra với source 10.8.0.2 nhưng không có reply quay về, đường về là phần còn thiếu.
Tôi có cần static route trên home router không?
Chỉ cần nếu bạn không dùng masquerade rule. Masquerade rule trên WireGuard server sẽ đổi source address của traffic trong tunnel thành LAN address của chính server. Vì vậy, các host trong LAN sẽ reply đến một thiết bị lân cận mà chúng đã biết cách truy cập, và router không cần tham gia. Static route cho 10.8.0.0/24 thông qua LAN address của server là phương án thay thế. Cách này đáng dùng nếu bạn muốn các host trong LAN ghi log đúng address của từng client, hoặc muốn áp dụng firewall rule riêng cho từng client tại đó.
Tại sao dùng cùng một subnet ở cả hai đầu lại làm tunnel hỏng?
Laptop của bạn không thể giữ 2 route cho cùng một prefix. Nếu local network cấp 192.168.1.0/24 và home LAN cũng dùng 192.168.1.0/24, split-tunnel wg-quick up sẽ fail khi ip route add từ chối với RTNETLINK answers: File exists. Full tunnel vẫn được thiết lập, nhưng wg-quick cài các policy rule khiến các route cụ thể hơn không còn được ưu tiên từ main table. Vì vậy, local network thắng và remote LAN vẫn không thể truy cập. Hãy đổi home LAN sang một subnet ít phổ biến hơn, chẳng hạn 192.168.20.0/24. Không có cách sửa ở phía client.
Tôi truy cập được NAS bằng IP nhưng không truy cập được bằng tên. Còn thiếu gì?
Name resolution không tự đi qua tunnel. Thêm DNS = 192.168.20.1, tức resolver ở nhà của bạn, vào block [Interface] của client, đồng thời bảo đảm address đó nằm trong AllowedIPs của peer. Nếu không, query sẽ không đi vào tunnel. Sau đó kiểm tra resolver có trả lời query từ bên ngoài subnet riêng của nó hay không. dnsmasq với local-service và chế độ chỉ lắng nghe local của Pi-hole đều từ chối các query này. Masquerade rule trên WireGuard server có thể xử lý bằng cách đổi source address của query.
Kết nối Internet tại nhà không có public IP. Tôi vẫn có thể truy cập LAN không?
Có, nếu dùng thêm một node thứ ba. Khi ở sau CGNAT, WAN address của router là private nên không peer nào trên Internet có thể bắt đầu handshake với router. Tuy nhiên, handshake đi ra ngoài vẫn hoạt động bình thường. Chạy WireGuard trên một VPS có public address, cho home box kết nối ra VPS bằng PersistentKeepalive = 25, rồi thêm vào peer entry của home box trên VPS một AllowedIPs chứa tunnel address của nó cùng với 192.168.20.0/24. VPS sau đó cần bật forwarding và có forward rule cho phép wg0 đến wg0.