SSD Nodes Learn RAM 8GB — $66/ปี
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-01

แก้ DNS ผ่าน WireGuard: 3 อาการเสียและวิธีแก้

Tunnel WireGuard ทำงาน แต่แปลงชื่อไม่ได้หรือ DNS รั่วไปยังเราเตอร์ ตรวจหาความขัดข้องทั้ง 3 แบบ พร้อมวิธีแก้ routing และ resolver manager

เหตุใด DNS จึงขัดข้องทันทีที่ WireGuard เริ่มทำงาน

DNS ผ่าน WireGuard ขัดข้องได้ 3 รูปแบบ และแต่ละรูปแบบมีวิธีแก้เฉพาะของตนเอง ไม่มีชื่อใดถูกแปลงเป็นที่อยู่ได้เลย หรือชื่อถูกแปลงได้แต่คำขอออกจากเครื่องของคุณโดยอยู่นอก tunnel หรือ resolver manager ของไคลเอ็นต์เขียนค่าทับอีกครั้งภายในไม่กี่วินาทีหลังจากอินเทอร์เฟซเริ่มทำงาน โดยแทบไม่ใช่ปัญหาที่ tunnel เอง ปัญหาอยู่ที่บรรทัดหนึ่งซึ่งระบุให้ไคลเอ็นต์ส่งคำถามไปยัง resolver ใด และการกำหนดเส้นทางที่ตัดสินใจว่าแพ็กเก็ตจะเดินทางไปยัง resolver นั้นอย่างไร

WireGuard รับส่งแพ็กเก็ต IP และไม่รู้จัก DNS (ระบบชื่อโดเมน ซึ่งเป็นบริการที่แปลงชื่อ เช่น example.com เป็นที่อยู่ IP) บรรทัด DNS = ในบล็อกไคลเอ็นต์ [Interface] ไม่ใช่การตั้งค่าของ WireGuard แต่ wg-quick ซึ่งเป็น shell wrapper ที่เปิดใช้งานอินเทอร์เฟซ จะอ่านบรรทัดนี้ และ wg-quick จะแก้ไขการกำหนดค่า resolver ของไคลเอ็นต์ขณะที่ tunnel ทำงานอยู่ แล้วคืนค่าดังกล่าวเมื่อทำงานบน wg-quick down ดังนั้นปัญหาทั้งหมดด้านล่างจึงเป็นปัญหาการกำหนดเส้นทางหรือปัญหา wg-quick ไม่ใช่ปัญหาการเข้ารหัส หากยังไม่ได้สร้าง tunnel ให้เริ่มจาก VPN WireGuard ที่โฮสต์เองบน VPS ของคุณ แล้วกลับมาที่หน้านี้

ตรวจสอบว่า tunnel ทำงานปกติก่อนแตะต้อง DNS

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

wg show ควรแสดง peer พร้อมค่า latest handshake ล่าสุด และ ping ทั้งสองรายการควรได้รับการตอบกลับ หาก ping 1.1.1.1 หมดเวลา แสดงว่าคุณมีปัญหาการส่งต่อหรือ NAT (การแปลงที่อยู่เครือข่าย) ไม่ใช่ปัญหา DNS และการตั้งค่า resolver ไม่ว่าจะมากเพียงใดก็ไม่ช่วย ตัวอย่างทั้งหมดในที่นี้ใช้ 10.8.0.0/24 เป็นซับเน็ตของ tunnel และ 10.8.0.1 เป็นที่อยู่ tunnel ของเซิร์ฟเวอร์ ให้แทนที่ด้วยค่าของคุณเอง

ปัญหาที่หนึ่ง: ไม่สามารถแปลงชื่อใดๆ ได้ เพราะตัวแก้ไขชื่อไม่ตอบสนอง

อาการนี้ชัดเจน ping 1.1.1.1 ทำงานได้ แต่ curl https://example.com แสดงผลดังนี้:

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

เรียกใช้ตัวแก้ไขชื่อของ tunnel โดยตรงจาก client dig อยู่ในแพ็กเกจ dnsutils บน Ubuntu และ Debian

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

คำสั่งแรกส่งคืน address ซึ่งยืนยันว่าแพ็กเก็ตสามารถเข้าถึงอินเทอร์เน็ตผ่าน tunnel ได้ คำสั่งที่สองไม่ส่งคืนผลลัพธ์ใดๆ และแสดง ;; communication timed out; no servers could be reached นี่คือสาเหตุทั้งหมด: client ของคุณชี้ไปที่ 10.8.0.1 แต่ 10.8.0.1 ไม่ตอบสนองบน UDP port 53

สาเหตุมี 2 ประการ อาจไม่มีตัวแก้ไขชื่อทำงานอยู่บน server หรือ firewall ของ server ทิ้ง query ก่อนที่ query จะมาถึง ตรวจสอบทั้งสองกรณีบน server

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

ตัวแก้ไขชื่อที่ทำงานอยู่และ bind อย่างถูกต้องจะแสดงบรรทัดที่มี 10.8.0.1:53 หรือ 0.0.0.0:53 บน Ubuntu จุดที่มักทำให้เข้าใจผิดคือ 127.0.0.53:53 ซึ่งเป็น systemd-resolved stub listener ที่ bind กับ loopback address และตั้งใจไม่ให้เครื่องอื่นเข้าถึงได้ การชี้ VPN client ไปยัง server ที่มีตัวแก้ไขชื่อเพียงตัวเดียวเป็น stub นี้ จะทำให้เกิด timeout แบบเดียวกัน

วิธีแก้คือใช้ตัวแก้ไขชื่อที่รับฟังบน tunnel address และเพิ่มกฎ firewall 1 รายการเพื่ออนุญาตให้ peer เข้าถึงได้

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'

จากนั้นเปิด port สำหรับ traffic จาก tunnel เท่านั้น หากใช้ nftables ให้เพิ่ม 2 บรรทัดนี้ลงใน chain input ใน /etc/nftables.conf แล้ว reload ด้วย sudo systemctl reload nftables

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

หากใช้ ufw sudo ufw allow in on wg0 to any port 53 จะทำหน้าที่เดียวกัน ห้ามเปิด port 53 สู่อินเทอร์เน็ตสาธารณะ ตัวแก้ไขชื่อแบบ recursive ที่เปิดให้เข้าถึงได้จะถูก scanner ค้นพบภายในไม่กี่วันและถูกใช้เพื่อขยายการโจมตีแบบปฏิเสธการให้บริการ และ provider ของคุณจะสังเกตเห็น traffic ดังกล่าวก่อนที่คุณจะทราบ

เรียกใช้ dig +short @10.8.0.1 example.com จาก client อีกครั้ง หากผลลัพธ์มี address แสดงว่าเส้นทางไปยังตัวแก้ไขชื่อทำงานแล้ว ดังนั้น client เหลือเพียงต้องใช้ตัวแก้ไขชื่อนี้ เพิ่มบรรทัดดังกล่าวลงใน block [Interface] ของ client แล้ว restart interface ด้วย 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

ความล้มเหลวที่สอง: DNS รั่วไหล เนื่องจาก split tunnel ไม่ได้กำหนดเส้นทางให้ resolver

กรณีนี้ร้ายแรงกว่า เพราะทุกอย่างดูเหมือนทำงานตามปกติ ชื่อโดเมนถูกแปลงเป็น IP, หน้าเว็บโหลดได้ และคำขอ DNS ถูกส่งแบบไม่เข้ารหัสผ่านเครือข่ายท้องถิ่นที่คุณไม่ต้องการให้เชื่อถือ

สาเหตุเกิดจากการกำหนดค่า 2 แบบ แบบแรกคือ client ที่มี AllowedIPs = 0.0.0.0/0, ::/0 แต่ไม่มีบรรทัด DNS = wg-quick จะติดตั้ง default route ใน routing table ของตนเอง และเพิ่ม rule ด้วย suppress_prefixlength 0 ซึ่งจงใจเก็บ local route ที่มีความจำเพาะมากกว่าไว้ เพื่อให้เครื่องยังเข้าถึง printer ของตนเองได้ resolver ที่ client เรียนรู้ผ่าน DHCP ซึ่งโดยทั่วไปคือ router ที่ 192.168.1.1 จะตรงกับ local route เหล่านั้น ทราฟฟิกของคุณจะวิ่งผ่าน tunnel แต่เครือข่ายท้องถิ่นยังคงได้รับรายชื่อโดเมนทั้งหมดที่คุณค้นหา

แบบที่สองคือ split tunnel: AllowedIPs = 10.8.0.0/24 ร่วมกับ DNS = 9.9.9.9 เนื่องจาก 9.9.9.9 ไม่ได้อยู่ภายใน AllowedIPs client จึงไม่มี route ไปยัง resolver ผ่าน tunnel คำขอจึงออกผ่านลิงก์ท้องถิ่นเช่นเดียวกับกรณีแรก

ตรวจสอบว่า resolver ใดเป็นผู้ตอบจริง whoami.akamai.net เป็นชื่อทดสอบสาธารณะที่ตอบกลับด้วย IP address ของ recursive resolver ที่ส่งคำขอ คุณจึงเปรียบเทียบคำตอบนั้นกับ public address ของ server ได้

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

resolvectl status จะแสดงข้อมูลหนึ่งบล็อกต่อหนึ่งลิงก์ หากบล็อกของลิงก์ ethernet หรือ wireless ยังคงแสดง Current DNS Server: 192.168.1.1 ขณะที่บล็อก wg0 ไม่แสดงรายการใด นั่นคือการรั่วไหล dig +short whoami.akamai.net ที่ส่งกลับ home broadband address ของคุณแทน address ของ server จะยืนยันผลจากฝั่งปลายทาง บรรทัด tcpdump เป็นหลักฐานที่ใช้ยุติข้อโต้แย้งได้: ผลลัพธ์ที่ถูกต้องจะส่ง packet ที่ใช้ port 53 ทุก packet ผ่าน wg0 ส่วนการรั่วไหลจะส่งผ่าน wlan0 หรือ enp3s0

การแก้ไขมี 2 ส่วน และต้องทำทั้งสองส่วน กำหนด DNS ให้เป็น address ที่อยู่ภายใน tunnel และตรวจสอบให้แน่ใจว่า address นั้นอยู่ภายใน 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 อยู่ภายใน 10.8.0.0/24 ดังนั้นคำขอจึงถูกเข้ารหัสและส่งไปยัง server หากคุณยืนยันจะใช้ public resolver กับ split tunnel ให้เพิ่มเป็น host route: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32 packet จะถูกส่งผ่าน tunnel แต่เครือข่ายท้องถิ่นยังคงเห็นว่าคุณเลือก provider รายดังกล่าวจาก session ก่อนหน้า การใช้ resolver ที่คุณดูแลเองช่วยหลีกเลี่ยงปัญหานี้

การกำหนด resolver เป็นหนึ่งในความแตกต่างที่เห็นได้ชัดระหว่าง WireGuard ที่สร้างและกำหนดค่าด้วยตนเองกับ mesh ที่ประสานงานแบบรวมศูนย์ ซึ่งเป็นส่วนหนึ่งของข้อแลกเปลี่ยนใน WireGuard เปรียบเทียบกับ Tailscale การเรียกใช้ control server ของ Headscale ที่โฮสต์ด้วยตนเอง ช่วยให้คุณมีการประสานงานดังกล่าว โดยไม่ต้องมอบ key material ให้บุคคลที่สาม

ความล้มเหลวประการที่ 3: resolvconf และ systemd-resolved ทำงานขัดแย้งกันบนไคลเอนต์ Linux

ไคลเอนต์ macOS, Windows, iOS และ Android ใช้ DNS = ผ่านแอปอย่างเป็นทางการและมักไม่ก่อปัญหา Linux เป็นระบบที่การตั้งค่านี้ถูกใช้ผ่าน shell script ซึ่งต้องคาดเดาว่าคุณใช้งาน resolver manager ตัวใดจากหลายตัวที่มีอยู่

ความล้มเหลวแรกแสดงข้อผิดพลาดอย่างชัดเจน sudo wg-quick up wg0 หยุดทำงานพร้อมข้อความ:

resolvconf: command not found

wg-quick เรียกใช้ resolvconf และไม่มีการติดตั้ง binary ดังกล่าว ให้ติดตั้ง implementation ที่สื่อสารกับ systemd-resolved จากนั้นเปิดใช้งาน interface อีกครั้ง

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

ความล้มเหลวที่สองเกิดขึ้นโดยไม่แสดงข้อผิดพลาด และเป็นกรณีที่ทำให้เสียเวลาทั้งเย็น interface ทำงานขึ้นมา resolvectl status wg0 แสดง DNS Servers: 10.8.0.1 อย่างถูกต้อง แต่การค้นหาชื่อยังคงส่งไปยัง resolver เดิม systemd-resolved จะเก็บรายการ resolver แยกตาม link และเลือก link สำหรับแต่ละ query หากไม่มี link ใดถูกกำหนดให้เป็น default route สำหรับชื่อ ระบบจะยังใช้ resolver ของ wireless link เพราะ link ดังกล่าวมี search domain แต่ link ของคุณไม่มี

กำหนด resolver และยึด default route ในขั้นตอนเดียวกัน %i จะขยายเป็นชื่อ interface ดังนั้น block นี้จึงใช้ได้โดยไม่ต้องแก้ไขกับทุก interface

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

ลบบรรทัด DNS = เมื่อใช้ PostUp ในลักษณะนี้ เพราะมิฉะนั้นจะมี 2 กลไกเขียนสถานะของ resolver และมีเพียงกลไกเดียวที่ล้างสถานะภายหลัง อาร์กิวเมนต์ ~. เป็นส่วนสำคัญ โดยกำหนดให้ wg0 เป็น routing domain สำหรับทุกชื่อ ดังนั้น systemd-resolved จะส่ง query ทั้งหมดไปที่นั่น แทนการเลือก link สำหรับแต่ละ query ให้ตรวจสอบผลลัพธ์

resolvectl status wg0

ผลลัพธ์ที่ถูกต้องจะมี DNS Servers: 10.8.0.1 และ Default Route: yes หาก Default Route อ่านค่าเป็น no แสดงว่าส่วน resolvectl domain ยังไม่ได้ทำงาน และระบบกลับไปใช้การเลือก link อีกครั้ง

ยังมีอีกกรณีหนึ่งที่ควรกล่าวถึง หาก /etc/resolv.conf เป็นไฟล์จริง ไม่ใช่ symlink ไปยัง /run/systemd/resolve/stub-resolv.conf แสดงว่ามีโปรแกรมอื่นเป็นผู้ดูแลไฟล์ดังกล่าว โดยทั่วไปคือ NetworkManager หรือ container runtime ให้เรียกใช้ ls -l /etc/resolv.conf ก่อนตรวจสอบสาเหตุอื่น เพราะเครื่องมือที่เขียนทับไฟล์นี้ทุกครั้งที่เครือข่ายเปลี่ยนแปลงจะยกเลิกการตั้งค่าของคุณในเวลาที่ไม่เหมาะสมที่สุด

การอัปเกรด: resolver สำหรับกรองของคุณเองผ่าน tunnel

เมื่อ query เดินทางผ่าน tunnel ได้อย่างเสถียร resolver ที่ปลายทางจะกลายเป็นจุดควบคุม การเรียกใช้ AdGuard Home ที่ปลายทางจะทำให้อุปกรณ์ที่เชื่อมต่อทั้งหมดใช้การกรองด้วย blocklist และมี query log โดยไม่ต้องติดตั้งซอฟต์แวร์ฝั่ง client หรือกำหนดค่าแยกสำหรับแต่ละอุปกรณ์ install script อย่างเป็นทางการ ซึ่งตรวจสอบเมื่อ July 2026 มีเพียงบรรทัดเดียว

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

setup wizard จะ listen บน port 3000 ในการเรียกใช้ครั้งแรก ให้เข้าถึงผ่าน tunnel ที่ http://10.8.0.1:3000 แทนการเปิด port ดังกล่าวต่อสาธารณะ และใน wizard ให้ตั้งทั้ง DNS listen address และ admin listen address เป็น 10.8.0.1 หาก unbound จากความขัดข้องครั้งแรกยังคงใช้ address เดิม ให้หยุดการทำงานก่อนด้วย sudo systemctl disable --now unbound เนื่องจาก process สองตัวไม่สามารถ bind UDP port 53 บน address เดียวกันได้ และตัวที่สองจะออกจากการทำงานพร้อม listen udp 10.8.0.1:53: bind: address already in use

ไม่ต้องเปลี่ยนค่า client config หากตั้งค่าเป็น DNS = 10.8.0.1 อยู่แล้ว query log จะแสดง lookup ทุกครั้งจาก peer ทุกตัว ซึ่งเป็นการตัดสินใจด้านความเป็นส่วนตัวอย่างแท้จริง ไม่ใช่ประโยชน์ที่ได้มาโดยไม่มีต้นทุน: คุณย้ายความไว้วางใจจากผู้ให้บริการอินเทอร์เน็ตมาไว้ที่ตัวคุณเอง และคุณต้องดูแลให้เครื่องดังกล่าวได้รับ patch อยู่เสมอ server ที่เปิดให้เข้าถึงจากอินเทอร์เน็ตต้องวางมาตรการพื้นฐานให้เรียบร้อยก่อน และ 10 นาทีแรกบน VPS ใหม่ ครอบคลุมเรื่องเหล่านี้

FAQ

เหตุใด tunnel ของ WireGuard จึงเชื่อมต่อได้ แต่ไม่สามารถแปลงชื่อได้

tunnel ทำหน้าที่ส่งแพ็กเก็ตและไม่จัดการชื่อเลย ดังนั้นหาก tunnel ทำงานแต่การค้นหาชื่อล้มเหลว แสดงว่า resolver ที่คุณกำหนดให้ใช้งานไม่ตอบสนอง ทดสอบจาก client ด้วย dig +short @10.8.0.1 example.com การตอบกลับแบบ communication timed out หมายความว่าไม่มี resolver รับฟังอยู่ที่ address ของ tunnel หรือ firewall ของ server กำลังทิ้ง UDP port 53 ที่เข้ามาทาง wg0 ซึ่งมักเกิดจาก stub ของ systemd-resolved รับฟังเฉพาะที่ 127.0.0.53 แก้ไข listener ก่อน จากนั้นเปิด port สำหรับ wg0 เท่านั้น

จะตรวจสอบได้อย่างไรว่า DNS รั่วไหลผ่าน WireGuard

เรียกใช้ sudo tcpdump -ni any -c 10 port 53 บน client และตรวจสอบคอลัมน์ interface ขณะท่องเว็บ แพ็กเก็ตทุกแพ็กเก็ตควรอยู่บน wg0 หากปรากฏบน wireless หรือ ethernet interface แสดงว่า query กำลังออกไปเป็น cleartext dig +short whoami.akamai.net ใช้ตรวจสอบเพิ่มเติมได้ เนื่องจากคำสั่งนี้ตอบกลับด้วย public address ของ recursive resolver ที่เป็นผู้ส่ง query ดังนั้นหาก address ที่ตอบกลับไม่ใช่ address ของ server แสดงว่ามีการรั่วไหล

จำเป็นต้องมีบรรทัด DNS = หรือไม่ หากใช้ split tunnel

จำเป็น และ resolver address ต้องอยู่ภายใน AllowedIPs ด้วย มิฉะนั้น client จะไม่มี route ไปยัง resolver นั้น เมื่อใช้ AllowedIPs = 10.8.0.0/24 resolver ที่ 10.8.0.1 จะอยู่ในช่วงที่ครอบคลุม และ query จะถูกเข้ารหัส ส่วน public resolver เช่น 9.9.9.9 ไม่อยู่ในช่วงดังกล่าว ดังนั้น query จึงออกทาง local link แม้ว่าบรรทัด DNS จะดูถูกต้องก็ตาม

เหตุใด resolvectl จึงแสดง server ที่ถูกต้อง แต่การค้นหายังคงไปที่อื่น

systemd-resolved จะเก็บรายการ resolver แยกตาม link และเลือก link สำหรับแต่ละ query ดังนั้นรายการที่ถูกต้องบน wg0 จะถูกละเว้น ขณะที่ link อื่นมี default route สำหรับชื่อ ให้เพิ่ม PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. ลงในบล็อก [Interface] ของ client และลบบรรทัด DNS = จากนั้น resolvectl status wg0 ควรรายงานเป็น Default Route: yes

ควรแก้ไข client ใดก่อนเมื่อมีหลายเครื่องขัดข้อง

ให้แก้ไข Linux client หนึ่งเครื่องก่อน เนื่องจากเป็น platform เดียวที่แสดงกลไกการทำงานให้เห็น resolvectl status และ tcpdump จะระบุว่า resolver ใดตอบกลับและ interface ใดส่งแพ็กเก็ต แอปบนโทรศัพท์และ desktop จะใช้ค่า DNS และ AllowedIPs ในลักษณะเดียวกันโดยไม่แสดงการทำงานเบื้องหลัง ดังนั้นเมื่อ Linux client ถูกต้องแล้ว คุณจะสามารถคัดลอก configuration ที่ได้พิสูจน์แล้วว่าใช้งานได้