Собственный DNS-резолвер за VPN: Unbound и AdGuard Home для приватных запросов без сторонних серверов

VPN шифрует трафик и скрывает IP-адрес, но DNS-запросы часто остаются слабым звеном. Если клиент отправляет их напрямую провайдеру или публичному резолверу, наблюдатель видит полный список доменов, которые вы посещаете, даже не расшифровывая сам трафик DNS leak: как VPN может скрыть IP, но выдать DNS-запросы, и как это проверить. Решение — поднять собственный рекурсивный или фильтрующий DNS-сервер на VPN-узле и направлять все запросы исключительно через туннель.

Почему DNS ломает приватность VPN​


Типичная ситуация: клиент подключается к WireGuard, трафик идёт через туннель, но системный резолвер по-прежнему указывает на DNS провайдера или на 8.8.8.8. Провайдер видит plaintext-запросы и сопоставляет их с временными метками подключения. Это называется DNS leak DNS leak: как VPN может скрыть IP, но выдать DNS-запросы, и как это проверить.

Причины утечек:


Архитектура: VPN-узел как DNS-сервер​


Целевая схема:

Код:
Клиент ──WireGuard──▶ VPN-сервер ──▶ Unbound / AdGuard Home ──▶ корневые серверы
                         (wg0)           (127.0.0.1:53)

Клиент отправляет DNS-запросы на адрес VPN-сервера внутри туннеля (например, 10.10.0.1). На сервере запросы обрабатывает локальный резолвер, который выполняет рекурсию самостоятельно или фильтрует через списки блокировок. Внешний наблюдатель видит только зашифрованный UDP-трафик WireGuard и не может определить, какие домены запрашиваются Что видит интернет-провайдер при использовании VPN: метаданные, DNS и границы приватности.

Unbound: рекурсивный резолвер без логирования​


Unbound выполняет полную рекурсию: от корневых серверов до авторитативных, не передавая запросы промежуточным резолверам вроде 8.8.8.8 или 1.1.1.1. Это означает, что ни один сторонний сервис не видит ваши запросы.

Конфигурация для самостоятельной рекурсии​


YAML:
server:
    interface: 10.10.0.1
    port: 53
    access-control: 10.10.0.0/24 allow
    hide-identity: yes
    hide-version: yes
    qname-minimisation: yes
    private-address: 10.0.0.0/8
    private-address: 192.168.0.0/16

Здесь нет forward-zone — Unbound сам выполняет рекурсию от корневых серверов. Параметр interface: 10.10.0.1 привязывает резолвер к адресу WireGuard-интерфейса, поэтому сервис должен запускаться после поднятия туннеля. В systemd это решается через [email protected] в unit-файле или через ExecStartPre с проверкой доступности адреса.

Ключевые параметры приватности​


ПараметрНазначение
qname-minimisation: yesОтправляет минимально необходимое имя в запросе к вышестоящим серверам
hide-identity: yesНе раскрывает hostname сервера в ответах
hide-version: yesНе раскрывает версию Unbound
access-controlОграничивает, какие клиенты могут отправлять запросы

Установка и запуск​


Bash:
## Debian/Ubuntu
sudo apt install unbound
sudo systemctl enable --now unbound

## Проверка конфигурации
unbound-checkconf

## Проверка, что резолвер отвечает
dig @10.10.0.1 example.com

AdGuard Home: фильтрация и приватность в одном сервисе​


AdGuard Home — DNS-сервер с встроенной фильтрацией рекламы, трекеров и вредоносных доменов. В отличие от Unbound, он не выполняет рекурсию самостоятельно, а перенаправляет запросы на вышестоящие серверы. Приватность здесь достигается за счёт того, что запросы не уходят к провайдеру, а фильтрация происходит локально.

Конфигурация через веб-интерфейс​


После установки AdGuard Home доступен на http://<адрес_сервера>:3000 для первоначальной настройки. В интерфейсе задаются:

  • Адрес и порт прослушивания (например, 10.10.0.1:53).
  • Вышестоящие DNS-серверы. Для максимальной приватности выбирают резолверы с поддержкой DoH/DoT: Cloudflare, Quad9, NextDNS или собственный Unbound на том же хосте.
  • Списки фильтрации (EasyList, AdGuard DNS filter и др.).

Связка AdGuard Home + Unbound​


Распространённая схема: AdGuard Home слушает порт 53 и фильтрует запросы, а для «чистых» запросов перенаправляет их на Unbound, работающий на порту 8053 того же хоста. Это даёт и фильтрацию, и полную рекурсию без сторонних серверов.

Код:
Клиент ──▶ AdGuard Home (:53) ──фильтрация──▶ Unbound (:8053) ──▶ корневые серверы

В настройках AdGuard Home в поле «Вышестоящие DNS-серверы» указывают 127.0.0.1:8053.

Конфигурация Unbound для этой связки отличается от самостоятельной рекурсии:

YAML:
server:
    interface: 127.0.0.1
    port: 8053
    access-control: 127.0.0.0/8 allow
    hide-identity: yes
    hide-version: yes
    qname-minimisation: yes

Здесь Unbound слушает только loopback на порту 8053, чтобы не конфликтовать с AdGuard Home на порту 53. Параметр do-not-query-localhost по умолчанию равен yes, но в этой схеме он не влияет на работу, поскольку Unbound не пересылает запросы на localhost — он сам является конечной точкой рекурсии.

Настройка WireGuard для маршрутизации DNS​


На стороне клиента в конфигурации WireGuard нужно убедиться, что DNS-запросы идут через туннель. В файле конфигурации клиента:

INI:
[Interface]
PrivateKey = <ключ_клиента>
Address = 10.10.0.2/24
DNS = 10.10.0.1

[Peer]
PublicKey = <ключ_сервера>
Endpoint = <публичный_IP_сервера>:51820
AllowedIPs = 0.0.0.0/0

Директива DNS = 10.10.0.1 указывает клиенту использовать адрес сервера внутри туннеля как резолвер. AllowedIPs = 0.0.0.0/0 маршрутизирует весь трафик, включая DNS, через туннель VPN-клиент на Linux: как NetworkManager управляет маршрутами и DNS при подключении туннеля.

На сервере в конфигурации WireGuard:

INI:
[Interface]
PrivateKey = <ключ_сервера>
Address = 10.10.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <ключ_клиента>
AllowedIPs = 10.10.0.2/32

WireGuard ассоциирует туннельные IP-адреса с публичными ключами. Когда сервер получает пакет от клиента, он проверяет, что source IP соответствует AllowedIPs этого пира. Это обеспечивает криптографическую привязку маршрутизации к идентичности Собственный VPN-сервер против коммерческого провайдера: реальные границы приватности.

Предотвращение утечек на клиенте​


Linux с NetworkManager​


NetworkManager может перезаписать DNS при подключении туннеля. Чтобы этого не произошло:

Bash:
## Проверить текущие DNS
resolvectl status

## Убедиться, что для интерфейса wg0 назначен нужный сервер
resolvectl dns wg0 10.10.0.1
resolvectl domain wg0 "~."

domain "~." означает, что все домены маршрутизируются через этот интерфейс VPN-клиент на Linux: как NetworkManager управляет маршрутами и DNS при подключении туннеля.

Блокировка DNS в обход туннеля​


Дополнительная защита — запретить исходящие DNS-запросы мимо туннеля через iptables:

Bash:
## Запретить UDP/53 мимо интерфейса wg0
sudo iptables -A OUTPUT -p udp --dport 53 ! -o wg0 -j REJECT
sudo iptables -A OUTPUT -p tcp --dport 53 ! -o wg0 -j REJECT

Это гарантирует, что даже если приложение проигнорирует системный резолвер, запрос не уйдёт напрямую. Правила применяются немедленно и действуют до перезагрузки; для постоянства их сохраняют через iptables-save или переносят в nftables.

IPv6​


Если IPv6 не маршрутизируется через туннель, DNS-запросы по AAAA-записям могут уходить в обход. Варианты:

  • Маршрутизировать IPv6 через WireGuard (добавить IPv6-адрес в AllowedIPs).
  • Отключить IPv6 на клиенте, если он не нужен.
  • Убедиться, что резолвер не слушает IPv6 вне туннеля.

Проверка отсутствия утечек​


После настройки нужно убедиться, что DNS-запросы действительно идут через туннель:

  1. dnsleaktest.com — показывает, какие резолверы обрабатывают запросы. В списке должен быть только IP вашего VPN-сервера.
  2. browserleaks.com/dns — аналогичная проверка с дополнительными деталями.
  3. Локальная проверка — на сервере включить логирование Unbound и убедиться, что запросы приходят:

YAML:
## В unbound.conf добавить в секцию server:
    log-queries: yes
    logfile: /var/log/unbound.log

Bash:
sudo systemctl restart unbound
tail -f /var/log/unbound.log

Если в логе видны запросы с IP клиента из туннеля — всё работает. Если запросов нет, а сайты открываются — DNS уходит в обход.

Ограничения и нюансы​


  • Скорость рекурсии. Unbound при первом запросе домена выполняет полную цепочку от корневых серверов. Это медленнее, чем обращение к кэширующему резолверу. Кэш смягчает проблему, но первый запрос к новому домену занимает 50–200 мс.
  • Ресурсы VPS. Полная рекурсия нагружает CPU и память при большом числе клиентов. Для одного-двух пользователей достаточно минимального VPS.
  • DNSSEC. Unbound поддерживает валидацию DNSSEC из коробки. AdGuard Home передаёт DNSSEC-ответы, но сам не валидирует их — валидация происходит на стороне Unbound, если он стоит ниже по цепочке.
  • DoH/DoT на клиенте. Если клиент использует DoH (например, Firefox), запросы идут поверх HTTPS и не перехватываются правилом iptables на порт 53. В этом случае нужно либо отключить DoH в браузере, либо направить его на собственный DoH-endpoint.
  • Локальные домены. Если в сети есть внутренние имена (.local, .internal), их нужно добавить в local-zone Unbound или в правила AdGuard Home, иначе рекурсия уйдёт наружу.
  • Порядок запуска сервисов. Если Unbound привязан к адресу WireGuard-интерфейса, он не сможет запуститься до поднятия туннеля. В systemd-юните добавляют зависимость [email protected] и [email protected], либо используют interface: 0.0.0.0 с ограничением через access-control.

Итоговая проверка развёртывания​


ШагЧто проверить
WireGuard поднятwg show отображает интерфейс и пиров
DNS назначен клиентуresolvectl status показывает 10.10.0.1 для wg0
Unbound/AdGuard Home слушаетss -ulnp | grep :53 на сервере
Запросы доходятЛог Unbound содержит записи
Утечек нетdnsleaktest.com показывает только IP сервера
Обход заблокированdig @8.8.8.8 example.com с клиента не проходит
IPv6 не утекаетdig AAAA example.com идёт через туннель или отключён

Источники​


 
Назад
Верх Низ