SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

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.

  1. AllowedIPs trên client phải bao phủ subnet ở xa. Nếu không, packet không bao giờ đi vào tunnel.
  2. AllowedIPs trê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ã.
  3. net.ipv4.ip_forward phải là 1 trên server, vì Linux drop mọi packet không được gửi đến chính máy đó.
  4. 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à enp1s0 và giữ 192.168.20.5, còn tunnel interface là wg0 và 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.2 bê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 ở hai đầu là nguyên nhân của hầu hết các ticket này. WireGuard gọi cơ chế đó 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ó gì được ghi vào log trừ khi đã bật kernel debug messages. Dấu vết duy nhất là receive error count trên wg0, được ip -s link show wg0 in ra, còn packet thì biến mất.

Vì vậy, hai file cấu hình không bao giờ là bản sao đối xứng 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 = 25

Server, /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/32

Router 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/24 trên client, thay cho 0.0.0.0/0, ::/0. Đây là split tunnel: subnet của tunnel và LAN tại nhà đi qua wg0, 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/32 trên server, dùng một địa chỉ thay vì một range. Ghi 10.8.0.0/24 tạ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 = 25 trê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 cùng subnet ở hai đầu khiến kết nối hỏng

Chọn một subnet tại nhà mà hầu như không mạng nào 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 gia đình, nên sớm hay muộn laptop của bạn cũng sẽ kết nối vào mạng tại quán cà phê hoặc khách sạn sử dụng đúng dải địa chỉ đó.

Xung đột này khiến kết nối dừng hẳ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 Wi-Fi interface. Nếu route hiện có có cùng metric, ip route add sẽ từ chối và interface không khởi động được:

RTNETLINK answers: File exists

Trên laptop do NetworkManager quản lý, Wi-Fi route thường có metric như 600, nên thao tác thêm route sẽ thành công. Tunnel route có metric 0 sẽ được ưu tiên. NAS phản hồi, nhưng mọi host trong dải địa chỉ đó trên mạng quán cà phê, thường cả DNS server của mạng, giờ nằm phía sau tunnel.

Với full tunnel, wg-quick cài đặt các policy routing rule để cố ý giữ các route cụ thể hơn khỏi main table. Route cục bộ 192.168.1.0/24 được ưu tiên hơn tunnel, nên mọi packet đến remote LAN đều đi qua local link. Tunnel đang hoạt động, handshake bình thường, nhưng không thể truy cập NAS. Đổi lại dải địa chỉ của home LAN là cách sửa 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_forward

Lệ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ó tham số cũng đặt cùng giá trị đó, nhưng giá trị 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. Với backend iptables mặc định, Docker cũng tự đặt policy tương tự khi cần bật forwarding lúc startup, trừ khi ip-forward-no-drop được đặt trong /etc/docker/daemon.json. Vì vậy, 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 cấu hình firewall thủ công, nguyên nhân thường là Docker đã đặt giá trị này. Tuy nhiên, provisioning script hoặc firewall manager khác cũng có thể làm việc đó. Dù nguyên nhân là gì, tunnel traffic vẫn cần một accept rule rõ ràng.

Vì sao reply không bao giờ quay về

Nếu cấu hình đúng rule 1 đến 3, ping thực sự đến được NAS. Tuy nhiên, bạn vẫn không thấy phản hồi vì reply không có đường quay về. NAS trả lời 10.8.0.2, là địa chỉ nằm ngoài subnet của nó, nên chuyển packet đến default gateway là router gia đình tại 192.168.20.1. Router đó chưa biết 10.8.0.0/24 nằm ở đâu, nên chuyển reply đến default gateway của chính nó là đườ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 từ tunnel được forward qua enp1s0 thành 192.168.20.5, là địa chỉ LAN của chính interface đó. NAS sẽ thấy request đến từ một host cùng subnet, trả lời thẳng cho server, rồi server đảo ngược thay đổi này và gửi packet trở lại tunnel. Bạn không cần thay đổi gì trên các host khác trong LAN.

Đặt rule vào block [Interface] của server để rule xuất hiện và biến mất 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 MASQUERADE

Trên máy đã được quản lý bằng nftables, thay vào đó hãy ghi 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ữ lại keyword counter. Nếu thiếu keyword này, sudo nft list ruleset sẽ in rule mà không có packet count. Chính counter này 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 như vậy, và một số NAS admin panel cũng vậy. Trên các host này, packet từ 10.8.0.2 sẽ bị drop ngay cả khi routing hoàn toàn đúng. Sau khi masquerade, source trở thành 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 tất cả host trên LAN. Vì vậy, bạn không thể phân biệt các client, và các rule theo từng client trên thiết bị LAN sẽ không hoạt động.

Tùy chọn B: static route trên router gia đình. Cho router biết 10.8.0.0/24 nằm phía sau 192.168.20.5. Trên Linux router, bạn chỉ cần chạy một command:

sudo ip route add 10.8.0.0/24 via 192.168.20.5

Các router gia đình thường có trang Static Routes hoặc Routing trong phần cài đặt nâng cao: destination 10.8.0.0, mask 255.255.255.0, gateway 192.168.20.5. Lưu route vào cấu hình đã lưu 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 địa chỉ client thật, nên log và rule theo từng client trên LAN vẫn có ý nghĩa. Tuy nhiên, router phải hỗ trợ static route, và route chỉ có tác dụng với các host sử 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 bạn đã kiểm soát. Chuyển sang static route khi bạn cần giữ địa chỉ client thật.

Cách xác định mục nào trong bốn mục bị sai

Bắt đầu kiểm tra từ phía client và đi dần ra ngoài. Mỗi bước cho biết packet đã đi đến đâu.

Packet có đi vào tunnel không? Trên client:

ip route get 192.168.20.10

Kết quả phải hiển thị dev wg0. Nếu kết quả hiển thị interface Wi-Fi, thì rule 1 bị sai và AllowedIPs của client không bao phủ subnet LAN, hoặc một local route cho cùng dải mạng đang được ưu tiên. Đây là subnet collision đã mô tả ở trên. Một ping: connect: Network is unreachable cũng chỉ ra cùng nguyên nhân.

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, được ping sử dụng. Nếu không thấy gì ở đây trong khi handshake vẫn bình thường, gần như chắc chắn rule 2 bị sai: AllowedIPs của server cho peer đó không bao gồm 10.8.0.2, nên packet bị drop trong bước giải mã trước khi đến wg0. Việc số lượng RX error trong ip -s link show wg0 trên server tăng sau mỗi lần ping sẽ xác nhận điều này. Nếu số lượng đó không tăng, hãy kiểm tra firewall trên client có chặn traffic outgoing đến tunnel hay không.

Packet có rời server để đi vào LAN không? Trên server, theo dõi phía LAN:

sudo tcpdump -ni enp1s0 icmp

Nếu request xuất hiện trên wg0 nhưng không xuất hiện ở đây, thì rule 3 bị sai. Forwarding đang tắt hoặc một FORWARD rule đã drop packet. Ít gặp hơn, strict reverse-path filtering (rp_filter) có thể loại bỏ packet. Điều này xảy ra khi route của server quay về source đi qua interface khác. Nếu request xuất hiện ở đây với source 10.8.0.2 nhưng không có reply, thì thường rule 4 bị sai. Reply không có route quay về. Tuy nhiên, một host bỏ qua ping hoặc chỉ trả lời các host trong cùng subnet cũng cho kết quả giống hệt. Nếu request xuất hiện ở đây với source 192.168.20.5 nhưng không có reply, thì masquerade rule đang hoạt động và chính target host không trả lời. Hãy kiểm tra firewall trên NAS, và trên Linux host kiểm tra xem net.ipv4.icmp_echo_ignore_all có được đặt để bỏ qua ping hay không. Cách kiểm tra theo từng bước này cũng áp dụng cho mọi dịch vụ khác. Chỉ cần thay icmp bằng port 445 hoặc port mà 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 không hoạt động:

ssh: Could not resolve hostname nas.home.arpa: Name or service not known

Tunnel không có vấn đề gì. Phân giải tên là một đường riêng, và laptop của bạn vẫn đang hỏi 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ừ subnet được gắn 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 được rewrite, truy vấn sẽ đến từ 192.168.20.5.

Phía client chỉ cần 1 dòng:

DNS = 192.168.20.1

Trên Linux client, cần có openresolv hoặc tùy chọn tương đương. Nếu không, wg-quick sẽ dừng với resolvconf: command not found. Trước khi đặt tùy chọn này trên máy dùng systemd-resolved, hãy hiểu rõ tác động của nó: wg-quick đăng ký độc quyền các server đó. Vì vậy, khi tunnel đang hoạt động, các truy vấn trên laptop sẽ đi đến resolver trong mạng gia đình, không chỉ các tên trong mạng gia đình. Chỉ những tên thuộc domain cụ thể hơn mà interface khác đang khai báo mới tiếp tục đi theo interface đó. Kiểm tra kết quả bằng resolvectl status wg0. Nếu bạn muốn các tên trong mạng gia đình được phân giải 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. Khắc phục DNS qua tunnel WireGuard trình bày đầy đủ cách cấu hình.

Không có public IP ở 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, bạn đang ở sau CGNAT (carrier grade network address translation), nên không có handshake nào từ Internet có thể đến được nhà bạn. Địa chỉ 192.168.x.x private ở đó thường có nghĩa là có thêm một router đứng trước router của bạn, tạo thành double NAT: chuyển modem router của ISP sang bridge mode, hoặc forward UDP 51820 trên thiết bị đó nữa. Nếu không thể thay đổi thiết bị đó, hoặc địa chỉ WAN của chính nó cũng không phải public, hãy xử lý như CGNAT. Handshake đi ra ngoài vẫn hoạt động bình thường, nên cách khắc phục là thêm một node thứ ba có public address. Một VPS nhỏ chạy hub, còn máy ở nhà kết nối ra hub.

Bốn quy tắc không thay đổi. Bây giờ chúng áp dụng qua hai hop, nên phần cần theo dõi 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: tunnel address của chính nó, cùng 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ì mọi lưu lượng bây giờ đều đi đến hub.
  • Trên máy ở nhà, peer của VPS nhận AllowedIPs = 10.8.0.0/24, và máy ở nhà mang PersistentKeepalive = 25, vì đâ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ép wg0 đến wg0, vì lưu lượng từ laptop đến và rời đi trên cùng một interface. Firewall được viết cho một VPS full-tunnel thông thường sẽ chặn đúng trường hợp này.

Nếu chưa thiết lập phía VPS, thiết lập WireGuard trên VPS hướng dẫn 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 nằm trong mở reverse tunnel từ phía sau CGNAT. Khi việc tự quản lý peer address không cò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ý address.

Duy trì sau khi reboot

sudo systemctl enable --now wg-quick@wg0
sudo systemctl enable --now nftables
sudo wg show

enable --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

Vì sao tôi ping được WireGuard server nhưng không truy cập được gì khác trong LAN gia đình?

Ping 10.8.0.1 chỉ chứng minh 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 chứa 192.168.20.0/24, nếu không packet không bao giờ đi vào tunnel. Server cần đặt net.ipv4.ip_forward thành 1, nếu không nó sẽ drop mọi thứ 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 khi ping: nếu các request đi ra với source 10.8.0.2 nhưng không có reply quay về, nguyên nhân thường là thiếu đường đi chiều về.

Tôi có cần static route trên router gia đình không?

Chỉ khi bạn không dùng masquerade rule. Masquerade rule trên WireGuard server sẽ rewrite source address của traffic trong tunnel thành LAN address của chính server. Nhờ đó, các host trong LAN 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 qua LAN address của server là phương án thay thế. Cách này đáng dùng khi bạn muốn các LAN host ghi đúng client address trong log hoặc áp dụng firewall rule riêng cho từng client tại đó.

Vì sao cùng một subnet ở hai đầu lại làm tunnel lỗi?

Laptop của bạn không thể đồng thời dùng hai route cho cùng một prefix. Nếu local network cấp 192.168.1.0/24 và home LAN cũng là 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. Hoặc nếu Wi-Fi route có metric cao hơn, tunnel sẽ hoạt động nhưng các local host trong dải đó bị ẩn phía sau tunnel. Full tunnel vẫn hoạt động, nhưng wg-quick cài các policy rule khiến những route cụ thể hơn trong main table không được ưu tiên. Vì vậy local network thắng và remote LAN không truy cập được. Hãy đánh lại địa chỉ home LAN sang một dải ít phổ biến như 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 bằng tên. Còn thiếu gì?

Name resolution không tự đi theo tunnel. Thêm DNS = 192.168.20.1, tức home resolver của bạn, vào block [Interface] của client. Đảm bảo 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 của nó không, vì dnsmasq với local-service và chế độ listening chỉ cho 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 rewrite source address của query.

Kết nối tại nhà không có public IP. Tôi vẫn có thể truy cập LAN không?

Có, bằng một node thứ ba. Khi ở sau CGNAT, WAN address của router không phải public address nên không có peer nào trên Internet có thể bắt đầu handshake với router. Tuy nhiên, outgoing handshake 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. Sau đó VPS cần bật forwarding và có forward rule cho phép wg0 đến wg0.