SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor

Не работает DNS через WireGuard: как исправить

Туннель активен, но сайты не открываются или запросы идут мимо VPN? Разберитесь в трех причинах сбоев DNS в WireGuard, включая конфликты resolvconf и ошибки маршрутизации.

Почему DNS перестает работать сразу после поднятия туннеля WireGuard

DNS поверх WireGuard перестает работать по трем причинам, и для каждой есть свое решение. Либо запросы не проходят совсем, либо имена разрешаются, но запросы уходят с вашего устройства вне туннеля, либо системный менеджер резолвера перезаписывает настройки через несколько секунд после запуска интерфейса. Проблема почти никогда не заключается в самом туннеле. Проблема кроется в одной строке, которая указывает клиенту, какой резолвер использовать, и в маршрутизации, определяющей путь пакетов к этому резолверу.

WireGuard передает IP-пакеты и ничего не знает о DNS (системе доменных имен, сервисе, который преобразует имена, такие как example.com, в IP-адреса). Параметр DNS = в блоке [Interface] клиента не является настройкой WireGuard. Его считывает wg-quick — оболочка, которая поднимает интерфейс, после чего wg-quick изменяет конфигурацию резолвера клиента на время работы туннеля и восстанавливает её при 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 должна показывать пира с недавним latest handshake, и оба пинга должны отвечать. Если ping 1.1.1.1 выдает таймаут, скорее всего, у вас проблема с пересылкой (forwarding) или NAT (трансляцией сетевых адресов), а не с DNS, и никакие изменения в конфигурации резолвера не помогут. Межсетевой экран, блокирующий ICMP, дает такой же таймаут, поэтому проверьте это с помощью curl -sI https://1.1.1.1, прежде чем менять правила пересылки. Если пинги проходят, но пропускная способность падает при реальной нагрузке, это отдельная проблема, и низкая скорость WireGuard почти всегда связана с MTU, а не с чем-либо, описанным на этой странице. В каждом примере здесь 10.8.0.0/24 используется как подсеть туннеля, а 10.8.0.1 — как адрес сервера в туннеле. Подставьте свои значения.

Сбой один: ничего не разрешается, так как резолвер не отвечает

Симптом предельно ясен. ping 1.1.1.1 работает, а curl https://example.com возвращает следующее:

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

Запросите туннельный резолвер напрямую с клиента. Утилита 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.

К этому приводят две причины. Либо на сервере не запущен резолвер, либо серверный файрвол отбрасывает запрос до того, как он доходит до цели. Проверьте оба варианта на сервере.

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

Запущенный и корректно привязанный резолвер показывает строку с 10.8.0.1:53 или 0.0.0.0:53. В Ubuntu сюрпризом обычно оказывается 127.0.0.53:53: это stub-слушатель systemd-resolved, который привязывается к loopback-адресу и намеренно недоступен с других машин. Настройка VPN-клиента на сервер, где единственным резолвером является этот stub, приводит именно к такому таймауту.

Решение заключается в установке резолвера, который слушает адрес туннеля, и добавлении правила файрвола, разрешающего узлам доступ к нему.

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 для публичного интернета. Открытый рекурсивный резолвер обнаруживается сканерами в течение нескольких дней и используется для усиления DDoS-атак, и ваш провайдер заметит этот трафик раньше вас.

Повторно запустите dig +short @10.8.0.1 example.com с клиента. Адрес в выводе означает, что путь к резолверу работает, и теперь клиенту нужно только начать его использовать. Добавьте строку в блок [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 не направляет запросы к резолверу

Эта проблема опаснее, так как всё выглядит рабочим. Имена разрешаются, страницы загружаются, а запросы передаются в открытом виде через локальную сеть, которой вы не доверяли.

К этому приводят две конфигурации. Первая — клиент с AllowedIPs = 0.0.0.0/0, ::/0 без строки DNS =. wg-quick устанавливает маршрут по умолчанию в своей таблице маршрутизации и добавляет правило с suppress_prefixlength 0, которое намеренно сохраняет более специфичные локальные маршруты, чтобы машина могла, например, видеть принтер. Резолвер, полученный клиентом по DHCP (обычно это роутер по адресу 192.168.1.1), соответствует одному из таких локальных маршрутов. Ваш трафик идет через туннель, но локальная сеть по-прежнему получает полный список имен, которые вы запрашиваете.

Вторая конфигурация — split tunnel: AllowedIPs = 10.8.0.0/24 с DNS = 9.9.9.9. Поскольку 9.9.9.9 не входит в AllowedIPs, у клиента нет маршрута к нему через туннель, поэтому запрос уходит через локальный интерфейс, как и в первом случае.

Проверьте, какой именно резолвер отвечает на запросы. whoami.akamai.net — это публичное тестовое имя, которое возвращает IP-адрес рекурсивного резолвера, выполнившего запрос. Вы можете сравнить этот ответ с публичным адресом вашего сервера.

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

resolvectl status выводит по одному блоку на каждый сетевой интерфейс. Если в блоке для вашего Ethernet или Wi-Fi интерфейса всё еще отображается 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/16

10.8.0.1 находится внутри 10.8.0.0/24, поэтому запрос шифруется и отправляется на сервер. Если вы настаиваете на использовании публичного резолвера при split tunnel, добавьте его как хостовый маршрут: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. Пакеты будут передаваться через туннель, хотя локальная сеть все равно сможет увидеть, что вы выбрали этого провайдера, на основе предыдущих сессий. Использование собственного резолвера снимает этот вопрос.

Назначение резолвера — одно из заметных различий между WireGuard, настроенным вручную, и координированной mesh-сетью, что является частью компромисса в сравнении WireGuard и Tailscale. Запуск собственного сервера управления Headscale дает вам эту координацию без передачи ключей третьей стороне. Если вас беспокоит именно последняя фраза, учтите, что Tailscale никогда не хранит ключи, которыми шифруется ваш трафик, и более важный вопрос заключается в том, что скомпрометированный сервер координации или украденная учетная запись могут добавить в вашу сеть.

Сбой три: конфликт resolvconf и systemd-resolved на Linux-клиентах

Клиенты на macOS, Windows, iOS и Android применяют DNS = через официальное приложение и редко вызывают проблемы. В Linux настройка применяется через shell-скрипт, который должен угадать, какой из нескольких менеджеров DNS-резолверов вы используете.

Первый сбой проявляется явно. sudo wg-quick up wg0 останавливается с ошибкой:

resolvconf: command not found

wg-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, но запросы всё равно уходят к старому резолверу. systemd-resolved не игнорирует wg0. Имя, которое не совпадает ни с одним доменом маршрутизации, отправляется на DNS-серверы каждого линка, который считается маршрутом по умолчанию, а линк с DNS-серверами и без указанного домена маршрутизации по умолчанию считается таковым. В итоге запрос уходит одновременно к 10.8.0.1 и к роутеру в беспроводной сети, и побеждает тот, кто ответил первым. Роутер находится в одном хопе и обычно отвечает быстрее, при этом запрос в любом случае уходит в открытом виде. Имена внутри собственного поискового домена беспроводной сети, например lan, уходят только в этот линк, так как побеждает наиболее специфичный домен маршрутизации.

Когда wg-quick применяет DNS = через собственный оберточный скрипт resolvconf от systemd, он уже запрашивает домен маршрутизации «для всего» (catch-all), поэтому данный сбой чаще возникает, когда настройку применяет другая реализация resolvconf или сетевой менеджер. Явное указание настроек исключает неопределенность.

Укажите резолвер и закрепите домен маршрутизации «для всего» одним шагом. %i разворачивается в имя интерфейса, поэтому этот блок работает без изменений на любом интерфейсе.

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

Удалите строку DNS =, когда используете PostUp таким образом, иначе два механизма будут записывать состояние резолвера, и только один из них очистит его после завершения. Аргумент ~. — важная часть: он делает wg0 доменом маршрутизации для всех имен, поэтому systemd-resolved перестает отправлять имена, для которых нет более специфичного домена, в другие линки. Имена внутри домена другого линка, например lan, по-прежнему будут уходить в тот линк, что обычно и требуется для локальных хостов. Проверьте это.

resolvectl status wg0

Здоровый вывод содержит DNS Servers: 10.8.0.1 и DNS Domain: ~.. Если ~. отсутствует, часть resolvectl domain не выполнилась, и wg0 снова соревнуется с другими линками. Не используйте флаг маршрута по умолчанию в качестве проверки: он читает yes (или +DefaultRoute в строке Protocols, в зависимости от версии systemd) даже без ~., так как линк без домена маршрутизации по умолчанию является маршрутом по умолчанию.

Стоит упомянуть еще один случай. Если /etc/resolv.conf является обычным файлом, а не символической ссылкой на /run/systemd/resolve/stub-resolv.conf, значит, им управляет что-то другое, обычно NetworkManager или среда выполнения контейнеров. Запустите ls -l /etc/resolv.conf перед тем, как приступать к отладке чего-либо еще, так как инструмент, перезаписывающий этот файл при каждом изменении сети, отменит ваши изменения в самый неподходящий момент.

Обновление: собственный фильтрующий резолвер поверх туннеля

Когда запросы начинают стабильно проходить через туннель, удаленный резолвер становится точкой контроля. Запуск 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. Теперь в журнале запросов будут отображаться все обращения, поступающие от любого узла, если только вы не исключите клиента из логирования. Это решение в области конфиденциальности, а не просто бесплатное преимущество: вы переносите доверие со своего интернет-провайдера на себя, и именно вы должны поддерживать этот сервер в актуальном состоянии. Сервер, доступный из Интернета, должен быть защищен базовыми настройками, которые описаны в статье первые десять минут на новом VPS.

FAQ

Почему туннель WireGuard устанавливается, но имена не разрешаются?

Туннель передает пакеты и не занимается обработкой имен, поэтому работающий туннель при неработающем разрешении имен означает, что используемый резолвер не отвечает. Проверьте это с помощью dig +short @10.8.0.1 example.com на клиенте. Ответ communication timed out означает, что либо на этом адресе туннеля никто не слушает (часто потому, что stub-резолвер systemd-resolved привязан только к 127.0.0.53), либо сетевой экран сервера блокирует UDP-порт 53, приходящий на wg0. Сначала исправьте настройки слушающего процесса, затем откройте порт только для wg0.

Как проверить, не происходит ли утечка DNS через WireGuard?

Запустите sudo tcpdump -ni any -c 10 port 53 на клиенте и наблюдайте за столбцом интерфейса во время работы в сети. Каждый пакет, покидающий машину, должен проходить через wg0; пакеты на lo от или к 127.0.0.53 относятся к локальному stub-резолверу systemd-resolved, это нормально. Если они появляются на вашем беспроводном или Ethernet-интерфейсе, запросы уходят в открытом виде. dig +short whoami.akamai.net дает второе мнение, так как отвечает публичным адресом того рекурсивного резолвера, который сделал запрос. Ответ, отличный от адреса вашего сервера, подтверждает утечку.

Нужна ли строка DNS = при использовании split tunnel?

Да, и адрес резолвера также должен находиться внутри AllowedIPs, иначе у клиента не будет маршрута к нему. При использовании AllowedIPs = 10.8.0.0/24 резолвер на 10.8.0.1 будет охвачен, и запрос будет зашифрован. Публичный резолвер, такой как 9.9.9.9, не охвачен, поэтому запрос уйдет через локальное соединение, даже если строка DNS выглядит корректно.

Почему resolvectl показывает правильный сервер, но запросы все равно уходят в другое место?

systemd-resolved отправляет имя, которое не соответствует ни одному домену маршрутизации, на все интерфейсы с маршрутом по умолчанию одновременно, включая wg0, и возвращает первый успешный ответ, который обычно приходит от локального роутера. Добавьте PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. в блок [Interface] на клиенте и удалите строку DNS =. После этого resolvectl status wg0 должен показывать DNS Domain: ~., и каждое имя, которое не закреплено за другим интерфейсом более специфичным доменом, будет уходить только на wg0.

Какой клиент исправлять первым, если не работают несколько?

Исправьте один Linux-клиент, так как это единственная платформа, показывающая механизм работы. resolvectl status и tcpdump показывают, какой резолвер ответил и какой интерфейс передал пакет. Мобильные и десктопные приложения применяют те же значения DNS и AllowedIPs без видимых настроек, поэтому, настроив Linux-клиент, вы просто скопируете уже проверенную конфигурацию.