SSD Nodes Learn 8GB RAM — $66/năm
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-01

Cách sửa lỗi DNS không phân giải khi dùng WireGuard

WireGuard kết nối thành công nhưng DNS không phản hồi hoặc bị rò rỉ ra ngoài. Hướng dẫn khắc phục 3 lỗi DNS phổ biến do cấu hình sai định tuyến hoặc xung đột systemd-resolved.

Tại sao DNS bị lỗi ngay khi tunnel WireGuard được kích hoạt

DNS qua WireGuard thường gặp lỗi theo ba cách, và mỗi cách đều có cách khắc phục riêng. Hoặc là không phân giải được gì cả, hoặc tên miền phân giải được nhưng các truy vấn lại đi ra ngoài tunnel, hoặc trình quản lý resolver của client ghi đè lên thiết lập chỉ vài giây sau khi interface khởi động. Tunnel hầu như không bao giờ là nguyên nhân. Vấn đề nằm ở dòng lệnh chỉ định client sử dụng resolver nào và định tuyến quyết định cách các gói tin đến resolver đó di chuyển.

WireGuard truyền các gói tin IP và không biết gì về DNS (hệ thống tên miền, dịch vụ chuyển đổi các tên như example.com thành địa chỉ IP). Dòng DNS = trong block [Interface] của client không phải là một thiết lập của WireGuard. Nó được đọc bởi wg-quick, trình bao bọc shell giúp khởi động interface, và sau đó wg-quick sẽ chỉnh sửa cấu hình resolver của client khi tunnel đang hoạt động và khôi phục nó khi wg-quick down. Vì vậy, mọi vấn đề dưới đây đều là vấn đề định tuyến hoặc vấn đề wg-quick, không bao giờ là vấn đề mật mã. Nếu tunnel chưa được thiết lập, hãy bắt đầu với tự host WireGuard VPN trên VPS của bạn và quay lại trang này sau.

Hãy xác nhận tunnel hoạt động bình thường trước khi bạn đụng đến DNS.

sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1

wg show sẽ liệt kê peer với latest handshake gần đây, và cả hai lệnh ping đều phải phản hồi. Nếu ping 1.1.1.1 bị timeout, bạn đang gặp vấn đề về forwarding hoặc NAT (network address translation) chứ không phải vấn đề DNS, và việc cấu hình resolver sẽ không giúp ích gì. Mọi ví dụ ở đây đều sử dụng 10.8.0.0/24 làm subnet của tunnel và 10.8.0.1 làm địa chỉ tunnel của server. Hãy thay thế bằng thông tin của riêng bạn.

Lỗi thứ nhất: không phân giải được gì vì resolver không phản hồi

Triệu chứng rất cụ thể. ping 1.1.1.1 hoạt động bình thường, và curl https://example.com trả về kết quả sau:

curl: (6) Could not resolve host: example.com

Hãy truy vấn trực tiếp tunnel resolver từ client. dig nằm trong gói dnsutils trên Ubuntu và Debian.

dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.com

Lệnh đầu tiên trả về một địa chỉ, chứng tỏ các gói tin đi ra internet thông qua tunnel. Lệnh thứ hai không trả về gì cả và in ra ;; communication timed out; no servers could be reached. Đó là toàn bộ chẩn đoán: client của bạn đang trỏ tới 10.8.0.1, và 10.8.0.1 không phản hồi trên cổng UDP 53.

Có hai nguyên nhân gây ra lỗi này. Hoặc là không có resolver nào đang chạy trên server, hoặc firewall của server chặn truy vấn trước khi nó đến nơi. Hãy kiểm tra cả hai trên server.

sudo ss -ulnp | grep ':53'
sudo nft list ruleset

Một resolver đang chạy và bind đúng cách sẽ hiển thị một dòng có 10.8.0.1:53 hoặc 0.0.0.0:53. Trên Ubuntu, điều bất ngờ thường là 127.0.0.53:53: đó là stub listener của systemd-resolved, nó bind vào địa chỉ loopback và cố tình không thể truy cập được từ các máy khác. Việc trỏ một VPN client vào một server mà resolver duy nhất là stub này sẽ gây ra lỗi timeout chính xác như trên.

Cách khắc phục là sử dụng một resolver lắng nghe trên địa chỉ tunnel, cộng với một quy tắc firewall cho phép các peer truy cập vào nó.

sudo apt update && sudo apt install -y unbound
printf 'server:\n  interface: 10.8.0.1\n  access-control: 10.8.0.0/24 allow\n' \
  | sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'

Sau đó mở cổng chỉ dành cho lưu lượng tunnel. Với nftables, hãy thêm hai dòng này vào chain input trong /etc/nftables.conf và tải lại bằng sudo systemctl reload nftables.

udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" accept

Với ufw, sudo ufw allow in on wg0 to any port 53 thực hiện công việc tương tự. Đừng bao giờ mở cổng 53 ra internet công cộng. Một recursive resolver mở sẽ bị các trình quét tìm thấy trong vài ngày và bị lợi dụng để khuếch đại các cuộc tấn công từ chối dịch vụ (DoS), và nhà cung cấp của bạn sẽ phát hiện ra lưu lượng đó trước cả bạn.

Chạy lại dig +short @10.8.0.1 example.com từ client. Một địa chỉ xuất hiện trong kết quả nghĩa là đường dẫn resolver đã hoạt động, vì vậy client bây giờ chỉ cần sử dụng nó. Thêm dòng này vào block [Interface] của client và khởi động lại interface bằng sudo wg-quick down wg0 && sudo wg-quick up wg0.

[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1

Lỗi thứ hai: Rò rỉ DNS, do split tunnel không định tuyến trình phân giải

Lỗi này nghiêm trọng hơn vì mọi thứ trông có vẻ vẫn hoạt động. Tên miền được phân giải, trang web tải được, và các truy vấn truyền đi dưới dạng văn bản thuần (cleartext) qua mạng nội bộ mà bạn không muốn tin tưởng.

Hai cấu hình gây ra lỗi này. Thứ nhất là client sử dụng AllowedIPs = 0.0.0.0/0, ::/0 mà không có dòng DNS =. wg-quick cài đặt tuyến đường mặc định vào bảng định tuyến của chính nó và thêm một quy tắc với suppress_prefixlength 0, quy tắc này giữ cho các tuyến đường nội bộ cụ thể hơn vẫn hoạt động để máy tính vẫn có thể kết nối với máy in. Trình phân giải mà client nhận được qua DHCP, thường là router tại 192.168.1.1, khớp với một trong các tuyến đường nội bộ đó. Lưu lượng truy cập của bạn đi qua tunnel. Mạng nội bộ vẫn nhận được danh sách đầy đủ các tên miền bạn tra cứu.

Thứ hai là split tunnel: AllowedIPs = 10.8.0.0/24 với DNS = 9.9.9.9. Vì 9.9.9.9 không nằm trong AllowedIPs, client không có tuyến đường nào đến đó thông qua tunnel, nên truy vấn thoát ra qua kết nối nội bộ giống hệt trường hợp đầu tiên.

Hãy kiểm tra xem trình phân giải nào thực sự đang trả lời. whoami.akamai.net là một tên miền kiểm tra công khai, nó trả về địa chỉ IP của trình phân giải đệ quy đã thực hiện truy vấn, để bạn có thể so sánh câu trả lời đó với địa chỉ công khai của server của bạn.

resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53

resolvectl status in ra một khối cho mỗi liên kết. Nếu khối cho liên kết ethernet hoặc không dây của bạn vẫn hiển thị Current DNS Server: 192.168.1.1 trong khi khối wg0 không hiển thị gì, đó chính là rò rỉ. dig +short whoami.akamai.net trả về địa chỉ băng thông rộng tại nhà của bạn thay vì địa chỉ của server sẽ xác nhận điều đó từ phía xa. Dòng tcpdump là bằng chứng giải quyết mọi tranh cãi: kết quả hoạt động bình thường sẽ đưa mọi gói tin cổng 53 vào wg0, và rò rỉ sẽ đưa chúng vào wlan0 hoặc enp3s0.

Cách khắc phục gồm hai phần và bắt buộc phải thực hiện cả hai. Thiết lập DNS thành một địa chỉ nằm trong tunnel, và đảm bảo địa chỉ đó nằm trong AllowedIPs.

[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1

[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/16

10.8.0.1 nằm trong 10.8.0.0/24, vì vậy truy vấn được mã hóa và gửi đến server. Nếu bạn nhất quyết sử dụng trình phân giải công khai trên split tunnel, hãy thêm nó dưới dạng host route: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. Các gói tin sau đó sẽ được đưa vào tunnel, mặc dù mạng nội bộ vẫn có thể thấy rằng bạn đã chọn nhà cung cấp đó từ các phiên trước. Một trình phân giải do chính bạn vận hành sẽ tránh được vấn đề này.

Việc gán trình phân giải là một trong những khác biệt rõ rệt giữa WireGuard tự thiết lập và một mesh được điều phối, đây là một phần của sự đánh đổi trong WireGuard so với Tailscale. Việc chạy một server điều khiển Headscale tự lưu trữ mang lại cho bạn sự điều phối đó mà không cần giao tài liệu khóa của bạn cho bên thứ ba.

Lỗi thứ ba: resolvconf và systemd-resolved xung đột trên các client Linux

Các client macOS, Windows, iOS và Android áp dụng DNS = thông qua ứng dụng chính thức và ít gây ra vấn đề. Trên Linux, thiết lập này được áp dụng bởi một shell script, vốn phải tự đoán xem bạn đang chạy trình quản lý resolver nào trong số nhiều trình quản lý hiện có.

Lỗi đầu tiên rất dễ nhận biết. sudo wg-quick up wg0 dừng lại với thông báo:

resolvconf: command not found

wg-quick gọi đến resolvconf, và binary đó chưa được cài đặt. Hãy cài đặt bản triển khai giao tiếp với systemd-resolved, sau đó khởi động lại interface.

sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0

Lỗi thứ hai diễn ra âm thầm, và đây là lỗi khiến bạn mất cả buổi tối. Interface khởi động thành công, resolvectl status wg0 hiển thị chính xác DNS Servers: 10.8.0.1, nhưng các truy vấn vẫn đi đến resolver cũ. systemd-resolved duy trì một danh sách resolver riêng cho mỗi link và chọn link cho từng truy vấn. Trừ khi một link được đánh dấu là default route cho tên miền, nó sẽ tiếp tục sử dụng resolver của kết nối không dây, vì link đó có chứa search domain còn link của bạn thì không.

Hãy thiết lập resolver và xác nhận default route trong cùng một bước. %i sẽ mở rộng thành tên interface, vì vậy khối lệnh này hoạt động mà không cần thay đổi trên bất kỳ interface nào.

[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %i

Xóa dòng DNS = khi bạn sử dụng PostUp theo cách này, vì nếu không, hai cơ chế sẽ cùng ghi trạng thái resolver và chỉ một trong số đó dọn dẹp sau khi kết thúc. Đối số ~. là phần quan trọng: nó đánh dấu wg0 là routing domain cho mọi tên miền, nhờ đó systemd-resolved gửi tất cả truy vấn đến đó thay vì chọn link cho từng truy vấn. Hãy kiểm tra lại.

resolvectl status wg0

Kết quả đầu ra bình thường phải chứa DNS Servers: 10.8.0.1Default Route: yes. Nếu Default Route hiển thị no, nghĩa là phần resolvectl domain chưa chạy, và bạn lại quay về tình trạng chọn link thủ công.

Một trường hợp nữa cần lưu ý. Nếu /etc/resolv.conf là một file thực sự thay vì là một symlink trỏ đến /run/systemd/resolve/stub-resolv.conf, thì một tiến trình khác đang quản lý nó, thường là NetworkManager hoặc một container runtime. Hãy chạy ls -l /etc/resolv.conf trước khi debug bất cứ thứ gì khác, vì một công cụ ghi đè file đó mỗi khi mạng thay đổi sẽ làm hỏng công việc của bạn vào thời điểm không mong đợi nhất.

Nâng cấp: tự vận hành trình phân giải lọc nội dung qua tunnel

Khi các truy vấn đã truyền ổn định qua tunnel, trình phân giải ở đầu xa trở thành một điểm kiểm soát. Việc chạy AdGuard Home tại đó cung cấp tính năng lọc theo danh sách chặn và nhật ký truy vấn cho mọi thiết bị kết nối, mà không cần phần mềm client hay cấu hình trên từng thiết bị. Script cài đặt chính thức, được kiểm tra vào tháng 7 năm 2026, chỉ gồm một dòng.

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

Trình hướng dẫn thiết lập sẽ lắng nghe trên cổng 3000 trong lần chạy đầu tiên. Hãy truy cập nó qua tunnel tại http://10.8.0.1:3000 thay vì mở cổng đó công khai, và trong trình hướng dẫn, hãy đặt cả địa chỉ lắng nghe DNS và địa chỉ lắng nghe quản trị thành 10.8.0.1. Nếu unbound từ lỗi thứ nhất vẫn giữ cùng địa chỉ đó, hãy dừng nó trước bằng sudo systemctl disable --now unbound, vì hai tiến trình không thể cùng bind cổng UDP 53 trên một địa chỉ và tiến trình thứ hai sẽ thoát với listen udp 10.8.0.1:53: bind: address already in use.

Cấu hình client không cần thay đổi nếu chúng đã trỏ đến DNS = 10.8.0.1. Nhật ký truy vấn giờ đây sẽ hiển thị mọi tra cứu từ mọi peer, đây là một quyết định về quyền riêng tư thực sự thay vì là một lợi ích miễn phí: bạn chuyển sự tin tưởng từ nhà cung cấp internet sang chính mình, và bạn là người phải giữ cho máy chủ đó được cập nhật bản vá. Một máy chủ phơi bày ra internet cần có các thiết lập cơ bản trước, và mười phút đầu tiên trên một VPS mới sẽ bao quát các nội dung đó.

FAQ

Tại sao tunnel WireGuard của tôi kết nối được nhưng không phân giải được tên miền?

Tunnel chỉ truyền tải gói tin và không xử lý tên miền, vì vậy nếu tunnel hoạt động nhưng truy vấn thất bại thì nghĩa là trình phân giải (resolver) bạn trỏ tới không phản hồi. Hãy kiểm tra bằng dig +short @10.8.0.1 example.com từ client. Phản hồi communication timed out nghĩa là không có trình phân giải nào đang lắng nghe trên địa chỉ tunnel đó, thường do stub của systemd-resolved chỉ bind vào 127.0.0.53, hoặc firewall trên server đang chặn cổng UDP 53 trên wg0. Hãy sửa trình lắng nghe trước, sau đó mở cổng chỉ cho wg0.

Làm thế nào để kiểm tra DNS có bị rò rỉ qua WireGuard không?

Chạy sudo tcpdump -ni any -c 10 port 53 trên client và theo dõi cột interface trong khi bạn duyệt web. Mọi gói tin phải nằm trên wg0. Nếu chúng xuất hiện trên interface wifi hoặc ethernet, các truy vấn đang bị gửi đi dưới dạng văn bản thuần (cleartext). dig +short whoami.akamai.net cung cấp một cách kiểm tra thứ hai, vì nó trả về địa chỉ public của trình phân giải đệ quy (recursive resolver) đã thực hiện truy vấn, nên nếu kết quả trả về không phải là địa chỉ server của bạn thì xác nhận đã xảy ra rò rỉ.

Tôi có cần dòng DNS = nếu tôi sử dụng split tunnel không?

Có, và địa chỉ trình phân giải cũng phải nằm trong AllowedIPs, nếu không client sẽ không có route tới đó. Với AllowedIPs = 10.8.0.0/24, một trình phân giải tại 10.8.0.1 sẽ được bao phủ và truy vấn được mã hóa. Một trình phân giải công cộng như 9.9.9.9 sẽ không được bao phủ, nên truy vấn sẽ thoát ra qua kết nối nội bộ mặc dù dòng DNS trông có vẻ đúng.

Tại sao resolvectl hiển thị đúng server nhưng các truy vấn vẫn đi nơi khác?

systemd-resolved duy trì một danh sách trình phân giải cho mỗi link và chọn link cho mỗi truy vấn, vì vậy một mục nhập đúng trên wg0 sẽ bị bỏ qua nếu một link khác đang giữ route mặc định cho tên miền. Hãy thêm PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. vào block [Interface] của client và xóa dòng DNS =. Khi đó resolvectl status wg0 sẽ báo cáo Default Route: yes.

Tôi nên sửa client nào trước khi có nhiều client bị lỗi?

Hãy sửa một Linux client, vì đây là nền tảng duy nhất cho bạn thấy cơ chế hoạt động. resolvectl statustcpdump cho bạn biết trình phân giải nào đã phản hồi và interface nào đã truyền gói tin. Các ứng dụng trên điện thoại và máy tính để bàn áp dụng cùng các giá trị DNSAllowedIPs mà không hiển thị các thành phần bên dưới, vì vậy khi Linux client đã đúng, bạn chỉ cần sao chép cấu hình mà bạn đã kiểm chứng.