حل مشکل DNS در WireGuard: سه خطای رایج و راهکارها
تونل WireGuard فعال است اما DNS کار نمیکند یا درخواستها نشت میکنند؟ با بررسی این 3 سناریوی خرابی، مشکل تنظیمات DNS و مسیریابی سیستم خود را در چند دقیقه شناسایی و رفع کنید.
چرا با برقراری تونل WireGuard، سرویس DNS از کار میافتد
سرویس DNS روی WireGuard به سه دلیل دچار اختلال میشود و هر کدام راهکار خاص خود را دارند. یا هیچ نامی resolve نمیشود، یا نامها resolve میشوند اما درخواستها خارج از تونل ارسال میگردند، یا مدیر resolver کلاینت، تنظیمات را چند ثانیه پس از بالا آمدن اینترفیس بازنویسی میکند. مشکل تقریباً هرگز خودِ تونل نیست. مشکل، آن خطی است که به کلاینت میگوید از کدام resolver استفاده کند و مسیریابیای که تعیین میکند بستهها به سمت آن resolver چگونه حرکت کنند.
WireGuard بستههای IP را جابهجا میکند و هیچ اطلاعی از DNS (سیستم نام دامنه، سرویسی که نامهایی مانند example.com را به آدرسهای IP تبدیل میکند) ندارد. خط DNS = در بلوک [Interface] کلاینت، یک تنظیم مربوط به WireGuard نیست. این خط توسط wg-quick خوانده میشود؛ همان shell wrapper که اینترفیس را بالا میآورد. سپس wg-quick در زمان فعال بودن تونل، فایل پیکربندی resolver کلاینت را ویرایش کرده و هنگام wg-quick down آن را بازیابی میکند. بنابراین، تمام مشکلات زیر یا مربوط به مسیریابی هستند یا مربوط به wg-quick، و هرگز مشکل رمزنگاری نیستند. اگر خودِ تونل هنوز برقرار نشده است، با راهاندازی یک VPN WireGuard روی VPS شخصی شروع کنید و پس از آن به این صفحه بازگردید.
پیش از دست زدن به تنظیمات DNS، از سلامت تونل اطمینان حاصل کنید.
sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1دستور wg show باید peer را با یک latest handshake اخیر نمایش دهد و هر دو پینگ باید پاسخ دهند. اگر ping 1.1.1.1 با timeout مواجه شد، احتمالاً با مشکل forwarding یا NAT (ترجمه آدرس شبکه) روبرو هستید، نه مشکل DNS؛ و هیچ تغییری در تنظیمات resolver کمکی نخواهد کرد. فایروالی که بستههای ICMP را drop میکند نیز همین timeout را ایجاد میکند، بنابراین پیش از تغییر قوانین forwarding، با curl -sI https://1.1.1.1 موضوع را بررسی کنید. اگر پینگها پاسخ میدهند اما با شروع ترافیک واقعی، throughput به شدت افت میکند، این یک خطای مجزا است و کند بودن WireGuard تقریباً همیشه به MTU مربوط میشود، نه به هیچکدام از موارد این صفحه. تمام مثالهای اینجا از 10.8.0.0/24 به عنوان زیرشبکه تونل و 10.8.0.1 به عنوان آدرس تونل سرور استفاده میکنند. مقادیر خود را جایگزین کنید.
خطای اول: هیچچیزی resolve نمیشود، زیرا resolver هرگز پاسخ نمیدهد
نشانه دقیق است. دستور ping 1.1.1.1 کار میکند و دستور curl https://example.com خروجی زیر را برمیگرداند:
curl: (6) Could not resolve host: example.comمستقیماً از سمت کلاینت، tunnel resolver را پرسوجو کنید. ابزار dig در پکیج dnsutils در توزیعهای Ubuntu و Debian موجود است.
dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.comدستور اول یک آدرس برمیگرداند که ثابت میکند بستهها از طریق تونل به اینترنت میرسند. دستور دوم هیچچیزی برنمیگرداند و خطای ;; communication timed out; no servers could be reached را چاپ میکند. تشخیص نهایی این است: کلاینت شما به سمت 10.8.0.1 تنظیم شده است و 10.8.0.1 روی پورت UDP 53 پاسخ نمیدهد.
دو دلیل برای این اتفاق وجود دارد. یا هیچ resolver روی سرور در حال اجرا نیست، یا فایروال سرور پیش از رسیدن پرسوجو، آن را مسدود میکند. هر دو مورد را روی سرور بررسی کنید.
sudo ss -ulnp | grep ':53'
sudo nft list rulesetیک resolver که در حال اجراست و بهدرستی bind شده، خطی شامل 10.8.0.1:53 یا 0.0.0.0:53 را نشان میدهد. در Ubuntu، معمولاً با 127.0.0.53:53 مواجه میشوید: این همان stub listener مربوط به systemd-resolved است که روی آدرس loopback قرار دارد و عمداً از ماشینهای دیگر غیرقابلدسترسی است. تنظیم کلاینت VPN روی سروری که تنها resolver آن همین stub است، دقیقاً منجر به این timeout میشود.
راهحل، استفاده از resolverای است که روی آدرس تونل گوش میدهد، به همراه یک قانون فایروال که به کلاینتها اجازه دسترسی به آن را میدهد.
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'سپس پورت را فقط برای ترافیک تونل باز کنید. با استفاده از nftables، این دو خط را به زنجیره input در فایل /etc/nftables.conf اضافه کنید و با 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 همین کار را انجام میدهد. هرگز پورت 53 را برای اینترنت عمومی باز نکنید. یک recursive resolver باز، ظرف چند روز توسط اسکنرها پیدا شده و برای تقویت حملات denial of service استفاده میشود؛ ارائهدهنده خدمات شما پیش از خودتان متوجه این ترافیک خواهد شد.
دستور dig +short @10.8.0.1 example.com را دوباره از سمت کلاینت اجرا کنید. وجود یک آدرس در خروجی به این معنی است که مسیر resolver کار میکند و کلاینت اکنون فقط باید از آن استفاده کند. خط مربوطه را به بلوک [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، به دلیل عدم هدایت resolver در split tunnel
این مورد بدتر است، زیرا همهچیز بهظاهر درست کار میکند. نامها resolve میشوند، صفحات بارگذاری میشوند و پرسوجوها بهصورت متن آشکار (cleartext) از شبکه محلی که نمیخواستید به آن اعتماد کنید، عبور میکنند.
دو پیکربندی باعث بروز این مشکل میشوند. اولی، کلاینتی با AllowedIPs = 0.0.0.0/0, ::/0 و بدون خط DNS = است. wg-quick مسیر پیشفرض را در جدول مسیریابی خود نصب کرده و قانونی با suppress_prefixlength 0 اضافه میکند که مسیرهای محلی خاصتر را عمداً فعال نگه میدارد تا دستگاه همچنان بتواند به چاپگر خود دسترسی داشته باشد. resolverای که کلاینت از طریق DHCP یاد گرفته، معمولاً روتر در 192.168.1.1، با یکی از آن مسیرهای محلی مطابقت دارد. ترافیک شما از تونل عبور میکند، اما شبکه محلی همچنان لیست کامل نامهایی که جستجو میکنید را دریافت میکند.
دومی یک split tunnel است: AllowedIPs = 10.8.0.0/24 با DNS = 9.9.9.9. از آنجا که 9.9.9.9 داخل AllowedIPs نیست، کلاینت مسیری به آن از طریق تونل ندارد، بنابراین پرسوجو دقیقاً مانند حالت اول از طریق لینک محلی خارج میشود.
اثبات کنید کدام resolver واقعاً پاسخ میدهد. whoami.akamai.net یک نام تست عمومی است که با آدرس IP همان recursive resolver که پرسش را مطرح کرده پاسخ میدهد، بنابراین میتوانید پاسخ آن را با آدرس عمومی سرور خود مقایسه کنید.
resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53resolvectl status برای هر لینک یک بلوک چاپ میکند. اگر بلوک مربوط به لینک اترنت یا وایرلس شما همچنان Current DNS Server: 192.168.1.1 را نشان میدهد در حالی که بلوک wg0 هیچ موردی ندارد، این همان نشت است. dig +short whoami.akamai.net که آدرس پهنباند خانگی شما را به جای آدرس سرور بازمیگرداند، این موضوع را از سمت مقصد تأیید میکند. خط tcpdump مدرکی است که به بحثها پایان میدهد: خروجی سالم، تمام بستههای پورت 53 که دستگاه را ترک میکنند روی wg0 قرار میدهد و نشت، آنها را روی wlan0 یا enp3s0 میگذارد. بستههای روی lo به یا از 127.0.0.53، برنامههایی هستند که با stub محلی systemd-resolved صحبت میکنند و نشت محسوب نمیشوند.
رفع این مشکل دو بخش دارد و هر دو الزامی هستند. DNS را روی آدرسی تنظیم کنید که داخل تونل قرار دارد و مطمئن شوید آن آدرس داخل 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/1610.8.0.1 در داخل 10.8.0.0/24 قرار دارد، بنابراین پرسوجو رمزنگاری شده و به سرور ارسال میشود. اگر اصرار دارید از یک resolver عمومی در split tunnel استفاده کنید، آن را به عنوان یک host route اضافه کنید: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. بستهها سپس تونل میشوند، هرچند شبکه محلی همچنان میتواند ببیند که شما آن ارائهدهنده را از نشستهای قبلی انتخاب کردهاید. resolverای که خودتان اجرا میکنید، این مسئله را منتفی میکند.
تخصیص resolver یکی از تفاوتهای مشهود بین WireGuard دستساز و یک mesh هماهنگشده است که بخشی از بدهبستان در مقایسه WireGuard با Tailscale است. اجرای یک سرور کنترل Headscale خودمیزبان، آن هماهنگی را بدون واگذاری کلیدهای رمزنگاری به شخص ثالث برای شما فراهم میکند. اگر عبارت آخر شما را نگران میکند، توجه داشته باشید که Tailscale هرگز کلیدهایی که ترافیک شما را رمزنگاری میکنند در اختیار ندارد و پرسش دقیقتر این است که یک سرور هماهنگکننده آسیبدیده یا یک حساب کاربری سرقتشده چه چیزی میتواند به شبکه شما اضافه کند.
خطای سوم: تداخل resolvconf و systemd-resolved در کلاینتهای لینوکسی
کلاینتهای macOS، ویندوز، iOS و اندروید، تنظیمات DNS = را از طریق اپلیکیشن رسمی اعمال میکنند و مشکل چندانی ایجاد نمیکنند. در لینوکس، این تنظیمات توسط یک اسکریپت شل اعمال میشود که باید حدس بزند شما از کدامیک از چندین مدیریتکننده resolver استفاده میکنید.
خطای اول آشکار است. sudo wg-quick up wg0 با پیام زیر متوقف میشود:
resolvconf: command not foundwg-quick به resolvconf فراخوانی میفرستد، اما آن باینری نصب نشده است. در Debian 12 و Ubuntu 24.04 یا نسخههای جدیدتر، دستور resolvconf که با systemd-resolved ارتباط برقرار میکند، در بسته systemd-resolved ارائه میشود؛ بنابراین آن را نصب کنید و سپس اینترفیس را دوباره بالا بیاورید. در Ubuntu 22.04 بسته جداگانهای برای این کار وجود ندارد؛ در آنجا، لینک سازگاری را خودتان با sudo ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf ایجاد کنید و از خط نصب صرفنظر کنید.
sudo apt install -y systemd-resolved
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0خطای دوم خاموش است و همان خطایی است که یک شب وقت شما را میگیرد. اینترفیس بالا میآید، resolvectl status wg0 بهدرستی DNS Servers: 10.8.0.1 را نشان میدهد، اما جستجوها همچنان به resolver قدیمی میرسند. systemd-resolved، تنظیمات wg0 را نادیده نمیگیرد. نامی که با هیچ routing domain مطابقت نداشته باشد، به سرورهای DNS تمام لینکهایی که به عنوان default route محسوب میشوند ارسال میگردد، و لینکی که سرور DNS دارد اما route-only domain ندارد، بهطور پیشفرض یک default route محسوب میشود. بنابراین پرسوجو همزمان به 10.8.0.1 و روترِ روی لینک بیسیم ارسال میشود و اولین پاسخ موفق برنده است. روتر یک گام (hop) با شما فاصله دارد و معمولاً زودتر پاسخ میدهد، و در هر صورت پرسوجو بهصورت متن ساده (cleartext) خارج شده است. نامهای تحت search domain خودِ لینک بیسیم، مانند lan، فقط به همان لینک میروند، زیرا خاصترین routing domain برنده است.
هنگامی که wg-quick تنظیمات DNS = را از طریق wrapper اختصاصی resolvconf در systemd اعمال میکند، خودبهخود درخواست یک routing domain فراگیر (catch-all) را میدهد، بنابراین این خطا بیشتر زمانی رخ میدهد که پیادهسازی دیگری از resolvconf یا یک network manager تنظیمات را اعمال کرده باشد. تنظیم صریح آن، حدس و گمان را حذف میکند.
resolver را تنظیم کنید و routing domain فراگیر را در همان مرحله مطالبه کنید. %i به نام اینترفیس بسط مییابد، بنابراین این بلوک بدون تغییر روی هر اینترفیسی کار میکند.
[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %iهنگامی که از PostUp به این روش استفاده میکنید، خط DNS = را حذف کنید، زیرا در غیر این صورت دو مکانیزم وضعیت resolver را مینویسند و تنها یکی از آنها پس از پایان کار، پاکسازی را انجام میدهد. آرگومان ~. نیمه مهم ماجراست: این آرگومان باعث میشود wg0 به route-only domain برای هر نامی تبدیل شود، بنابراین systemd-resolved ارسال نامهایی که با هیچ دامنه خاصتری مطابقت ندارند به سایر لینکها را متوقف میکند. نامهای تحت دامنه لینک دیگر، مانند lan، همچنان به همان لینک میروند که معمولاً برای میزبانهای محلی همان چیزی است که میخواهید. آن را بررسی کنید.
resolvectl status wg0خروجی سالم شامل DNS Servers: 10.8.0.1 و DNS Domain: ~. است. اگر ~. وجود ندارد، نیمه resolvectl domain اجرا نشده است و wg0 دوباره با سایر لینکها مسابقه میدهد. از پرچم default route به عنوان ابزار بررسی استفاده نکنید: این پرچم حتی بدون ~. نیز yes (یا +DefaultRoute در خط Protocols، بسته به نسخه systemd) را میخواند، زیرا لینکی که route-only domain ندارد، به هر حال یک default route است.
یک مورد دیگر ارزش ذکر کردن دارد. اگر /etc/resolv.conf یک فایل واقعی است و نه یک symlink به /run/systemd/resolve/stub-resolv.conf، چیز دیگری مالک آن است، که معمولاً NetworkManager یا یک container runtime است. پیش از عیبیابی هر چیز دیگری، ls -l /etc/resolv.conf را اجرا کنید، زیرا ابزاری که آن فایل را در هر تغییر شبکه بازنویسی میکند، کار شما را در نامناسبترین لحظه خنثی خواهد کرد.
ارتقا: استفاده از resolver فیلترکننده شخصی روی تونل
هنگامی که کوئریها بهطور مطمئن از طریق تونل منتقل میشوند، resolver در سمت دیگر به یک نقطه کنترل تبدیل میشود. اجرای AdGuard Home در آنجا، امکان فیلترینگ مبتنی بر لیست سیاه و ثبت لاگ کوئریها را برای تمام دستگاههای متصل فراهم میکند، بدون اینکه نیازی به نصب نرمافزار روی کلاینتها یا پیکربندی جداگانه برای هر دستگاه باشد. اسکریپت نصب رسمی که در اکتبر 2026 بررسی شده است، تنها یک خط است.
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -vویزارد راهاندازی در اولین اجرا روی پورت 3000 گوش میدهد. به جای باز کردن عمومی این پورت، از طریق تونل و با استفاده از http://10.8.0.1:3000 به آن دسترسی پیدا کنید. در ویزارد، آدرس گوشدهی DNS و آدرس گوشدهی پنل مدیریت را هر دو روی 10.8.0.1 تنظیم کنید. اگر unbound از مرحله شکست اول هنوز همان آدرس را در اختیار دارد، ابتدا آن را با sudo systemctl disable --now unbound متوقف کنید؛ زیرا در غیر این صورت هر دو برای پورت UDP 53 روی یک آدرس با هم رقابت میکنند و AdGuard Home با خطای listen udp 10.8.0.1:53: bind: address already in use خارج میشود.
اگر پیکربندی کلاینتها از قبل روی DNS = 10.8.0.1 تنظیم شده باشد، نیازی به تغییر ندارند. اکنون لاگ کوئریها تمام جستجوهایی را که از هر peer به آن میرسند نشان میدهد، مگر اینکه کلاینتی را از ثبت لاگ مستثنی کنید. این یک تصمیم واقعی در حوزه حریم خصوصی است و نه یک مزیت رایگان؛ شما اعتماد را از ارائهدهنده اینترنت خود به خودتان منتقل میکنید و مسئولیت بهروزرسانی و وصله کردن آن سرور بر عهده شماست. سروری که در معرض اینترنت قرار دارد، ابتدا به تنظیمات امنیتی پایه نیاز دارد که در ده دقیقه اول روی یک VPS جدید پوشش داده شده است.
FAQ
چرا تونل WireGuard من متصل میشود اما نامها resolve نمیشوند؟
تونل فقط بستهها را منتقل میکند و هیچ نقشی در مدیریت نامها ندارد؛ بنابراین اگر تونل برقرار است اما جستجوی نامها با خطا مواجه میشود، به این معناست که resolver مورد نظر شما پاسخگو نیست. با استفاده از dig +short @10.8.0.1 example.com از سمت کلاینت تست کنید. دریافت پاسخ communication timed out به این معنی است که یا هیچ resolver روی آن آدرس تونل گوش نمیدهد (که اغلب به دلیل این است که stub مربوط به systemd-resolved فقط روی 127.0.0.53 گوش میدهد) و یا فایروال سرور بستههای UDP پورت 53 که به wg0 میرسند را مسدود میکند. ابتدا listener را اصلاح کنید و سپس پورت را فقط برای wg0 باز کنید.
چگونه بررسی کنم که آیا DNS من از طریق WireGuard نشت (leak) میکند؟
دستور sudo tcpdump -ni any -c 10 port 53 را روی کلاینت اجرا کنید و هنگام وبگردی، ستون interface را زیر نظر بگیرید. هر بستهای که از دستگاه خارج میشود باید روی wg0 باشد؛ بستههایی که روی lo به مقصد یا از مبدأ 127.0.0.53 هستند، مربوط به stub محلی systemd-resolved بوده و مشکلی ندارند. اگر این بستهها روی رابط بیسیم (wireless) یا اترنت شما ظاهر شوند، پرسوجوها به صورت متن آشکار (cleartext) ارسال میشوند. dig +short whoami.akamai.net نظر دوم را ارائه میدهد، زیرا با آدرس عمومی هر resolver بازگشتی (recursive resolver) که پرسوجو را انجام داده پاسخ میدهد؛ بنابراین اگر پاسخ دریافتی آدرس سرور شما نباشد، نشت DNS تأیید میشود.
آیا در صورت استفاده از split tunnel به خط DNS = نیاز دارم؟
بله، و آدرس resolver نیز باید درون AllowedIPs قرار داشته باشد، در غیر این صورت کلاینت مسیری به آن ندارد. با AllowedIPs = 10.8.0.0/24، یک resolver در 10.8.0.1 پوشش داده شده و پرسوجو رمزنگاری میشود. یک resolver عمومی مانند 9.9.9.9 پوشش داده نمیشود، بنابراین پرسوجو از طریق لینک محلی خارج میشود، حتی اگر خط DNS درست به نظر برسد.
چرا resolvectl سرور درست را نشان میدهد اما جستجوها به جای دیگری میروند؟
سرویس systemd-resolved نامی را که با هیچ routing domain مطابقت ندارد، همزمان به تمام لینکهای دارای default-route از جمله wg0 ارسال میکند و اولین پاسخ موفق را برمیگرداند که معمولاً از روتر محلی میآید. عبارت PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. را به بلوک [Interface] در کلاینت اضافه کرده و خط DNS = را حذف کنید. در این صورت resolvectl status wg0 باید DNS Domain: ~. را گزارش دهد و هر نامی که هیچ لینک دیگری با دامین اختصاصیتر ادعای آن را نداشته باشد، فقط به wg0 ارسال میشود.
وقتی چندین کلاینت دچار مشکل هستند، کدام را ابتدا اصلاح کنم؟
یک کلاینت Linux را اصلاح کنید، زیرا تنها پلتفرمی است که مکانیزم کار را به شما نشان میدهد. resolvectl status و tcpdump به شما میگویند کدام resolver پاسخ داده و کدام رابط، بسته را حمل کرده است. اپلیکیشنهای موبایل و دسکتاپ همان مقادیر DNS و AllowedIPs را بدون نمایش جزئیات فنی اعمال میکنند؛ بنابراین وقتی کلاینت Linux را اصلاح کردید، در واقع پیکربندیای را کپی میکنید که قبلاً صحت آن را اثبات کردهاید.