На Debian и Ubuntu одна из самых частых причин ошибки port 53 busy — не BIND9, не dnsmasq и не AdGuard Home, а штатный сервис systemd-resolved. Он поднимает локальный stub-resolver и по умолчанию слушает адрес 127.0.0.53:53. Пока это поведение не учтено, любой локальный DNS-сервис пытается занять тот же порт и падает при запуске.
Проблема особенно неприятна тем, что внешне всё выглядит неоднозначно. Ставите bind9, проверяете конфиг, запускаете службу — и получаете отказ. Устанавливаете AdGuard Home, а мастер сообщает, что DNS-порт уже занят. Поднимаете dnsmasq для кэша, локальных зон или резолвинга контейнеров — и снова конфликт.
Суть в том, что systemd-resolved — это не просто клиентская утилита для DNS. В Debian и Ubuntu он часто интегрирован в сетевую подсистему и обслуживает системное разрешение имён через локальную точку входа. Симлинк /etc/resolv.conf при этом нередко указывает на файл, где записан nameserver 127.0.0.53.
Когда на сервере нужен полноценный локальный DNS-демон, возникает выбор: оставить systemd-resolved как есть и привязать ваш DNS-сервис к другому адресу, либо отключить DNSStubListener и отдать 53-й порт основному демону. Второй вариант чаще оказывается чище, особенно если сервер реально должен обслуживать DNS-запросы сам.
Важно не путать две задачи: системное разрешение имён для самого хоста и работу DNS-службы как сервера. Их можно совместить, но только если заранее понимать, кто слушает 53-й порт, кто формирует /etc/resolv.conf и куда смотрят локальные приложения.
Как понять, что виноват именно systemd-resolved
Первый симптом — ошибка запуска DNS-службы с текстом про занятый адрес или порт. Формулировка зависит от демона: address already in use, failed to listen on port 53, cannot bind socket. Но диагноз надо подтверждать, а не гадать.
Начните с проверки, кто реально слушает 53-й порт:
ss -ltnup '( sport = :53 )'
ss -lnup '( sport = :53 )'
lsof -i :53 -n -P
Если в выводе есть процесс systemd-resolve или systemd-resolved на 127.0.0.53:53, источник конфликта найден. Часто картина выглядит так: TCP и UDP 53 слушаются только на loopback-адресе 127.0.0.53, но этого уже достаточно, чтобы другой сервис не смог занять тот же сокет на всех интерфейсах или на 127.0.0.1.
Дальше полезно посмотреть статус сервиса:
systemctl status systemd-resolved
resolvectl status
Команда resolvectl status покажет, какие upstream DNS используются, на каких интерфейсах, включён ли локальный stub и как вообще организовано разрешение имён на текущем хосте.
Отдельно проверьте, куда указывает /etc/resolv.conf:
ls -l /etc/resolv.conf
cat /etc/resolv.conf
В типовой конфигурации Ubuntu вы увидите либо симлинк на файл вида /run/systemd/resolve/stub-resolv.conf, либо другой файл из каталога /run/systemd/resolve/. Если внутри указан nameserver 127.0.0.53, это ещё один явный признак активного DNSStubListener.
Главная ошибка на этом этапе — сразу отключать сервисы наугад. Сначала выясните, кто слушает порт 53, куда смотрит
/etc/resolv.confи нужен ли серверу локальный DNS именно как сервис, а не просто как клиентский резолвер.
Почему конфликт возникает даже при прослушивании только 127.0.0.53
На первый взгляд может показаться, что адрес 127.0.0.53 не мешает, ведь это не 0.0.0.0 и не внешний IP. Но для DNS-сервисов это вполне реальный конфликт. Многие демоны по умолчанию хотят слушать либо все адреса, либо весь loopback, либо одновременно и IPv4, и IPv6. Если сокет уже занят на нужном адресе или комбинации адрес и порт, сервис не стартует.
Например, bind9 часто пытается занять 53-й порт на всех доступных интерфейсах. dnsmasq обычно поднимается как локальный DNS-кэш и тоже претендует на 53-й порт на loopback. AdGuard Home при стандартной настройке хочет слушать DNS глобально, чтобы принимать запросы от клиентов сети. Во всех трёх случаях локальный stub от systemd-resolved становится препятствием.
Есть и второй слой проблемы: после отключения stub многие забывают, что сам сервер тоже должен продолжить резолвить домены. Если просто освободить порт 53, но не привести в порядок /etc/resolv.conf, можно получить ситуацию, когда DNS-сервер уже стартует, а сам хост не может выполнить apt update, скачать пакеты или достучаться до внешних API по имени.
Именно поэтому правильная схема — не просто «освободить порт», а последовательно проверить: кто слушает, кто обслуживает системный DNS и кто должен отвечать на запросы после изменений.

Рабочие схемы решения
На практике используются три базовых подхода. Выбор зависит от роли сервера и от того, нужен ли systemd-resolved как часть локальной схемы разрешения имён.
Вариант 1. Отключить только DNSStubListener и оставить systemd-resolved
Это самый удобный и обычно самый аккуратный сценарий. Сервис systemd-resolved продолжает работать, но перестаёт слушать локальный порт 53 на 127.0.0.53. В результате освобождается сокет для BIND9, dnsmasq или AdGuard Home, а системная логика resolved при желании сохраняется.
Откройте конфигурацию:
sudo editor /etc/systemd/resolved.conf
Добавьте или измените параметр:
[Resolve]
DNSStubListener=no
После этого перезапустите сервис:
sudo systemctl restart systemd-resolved
Затем обязательно проверьте, куда теперь должен смотреть /etc/resolv.conf. Обычно после отключения stub правильнее использовать файл с реальными upstream DNS, а не с адресом 127.0.0.53. Во многих случаях подходит такая привязка:
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
Проверьте результат:
cat /etc/resolv.conf
resolvectl status
ss -lnup '( sport = :53 )'
После этого можно запускать нужный DNS-сервис и повторно смотреть, кто слушает порт 53.
Этот вариант хорош тем, что меняет минимум логики в системе. Он особенно удобен, если DNS для хоста приходит через DHCP, netplan, NetworkManager или cloud-init, а вам нужно лишь убрать конфликт по порту.
Вариант 2. Полностью отключить systemd-resolved
Этот путь уместен, когда сервер сам становится основным DNS-резолвером или authoritative либо recursive-сервером и промежуточный слой systemd-resolved уже не нужен. Например, вы хотите, чтобы локальный dnsmasq или BIND9 обслуживал и сам хост, и внешних клиентов.
Последовательность такая:
sudo systemctl disable --now systemd-resolved
Далее нужно вручную привести в порядок /etc/resolv.conf. Если сервер будет резолвить через локальный DNS-сервис, можно указать:
nameserver 127.0.0.1
Но делать это стоит только после того, как ваш DNS-демон гарантированно запускается и обслуживает запросы. Более безопасный промежуточный шаг — временно прописать внешний или инфраструктурный резолвер, проверить доступность пакетов и только потом переключать хост на локальный DNS.
Минус этого варианта в том, что вы берёте на себя всё управление системным DNS. На статичном сервере это не проблема, а вот на машине с динамической сетевой конфигурацией можно случайно потерять автоматическое обновление DNS-параметров.
Вариант 3. Развести адреса прослушивания
Иногда systemd-resolved лучше оставить без изменений, а DNS-службу привязать к конкретному адресу. Такой подход встречается реже, но бывает полезен на сложных хостах, где локальный stub нужен приложениям, а DNS-сервис должен обслуживать только внешний интерфейс.
Например, можно заставить BIND9 слушать только адрес сервера в локальной сети или только публичный IP, а не весь loopback. Аналогично для dnsmasq и AdGuard Home можно ограничить список адресов и интерфейсов прослушивания.
Минус здесь в том, что конфигурация становится менее очевидной. Через пару месяцев легко забыть, почему сервис не отвечает на 127.0.0.1 или почему локальные запросы идут не туда. Поэтому для одиночного сервера обычно проще отключить DNSStubListener, чем жить с хитрым разносом адресов.
Пошагово: BIND9, если мешает 127.0.0.53
Для bind9 самый типичный сценарий — BIND должен слушать 53-й порт полноценно, а systemd-resolved только мешает. В большинстве случаев практичнее отключать именно DNSStubListener, а не весь systemd-resolved.
Базовый порядок действий:
- Проверить занятость порта 53.
- Отключить
DNSStubListenerвresolved.conf. - Исправить
/etc/resolv.conf. - Проверить конфиг BIND9.
- Запустить сервис и убедиться, что он слушает нужные интерфейсы.
Проверка конфига BIND9:
sudo named-checkconf
sudo named-checkzone example.local /etc/bind/db.example.local
Запуск и проверка:
sudo systemctl restart bind9
sudo systemctl status bind9
ss -lnup '( sport = :53 )'
Если BIND9 нужен и для самого сервера как резолвер, можно после запуска прописать в /etc/resolv.conf локальный адрес, который слушает named. Но только после проверки реального ответа на запросы, иначе получите циклическую поломку: DNS-сервис не работает, а система без резолвинга уже не может нормально чиниться.
Если DNS-сервис выносится в отдельную роль инфраструктуры, удобнее поднимать его на изолированном VDS, где не придётся разбираться с побочными конфликтами пользовательских служб и сетевых профилей.
Пошагово: dnsmasq на Debian/Ubuntu
dnsmasq часто ставят ради кэширующего DNS, локальных записей, PXE или интеграции с контейнерами и виртуалками. Конфликт с systemd-resolved здесь почти классический: оба хотят быть локальным DNS на 53-м порту.
Если dnsmasq должен стать основным локальным резолвером, схема та же: отключаете DNSStubListener и затем запускаете dnsmasq. В его конфиге особенно важно явно задавать интерфейсы и поведение, чтобы он не слушал лишнее.
Минимальная проверка сервиса:
sudo systemctl restart dnsmasq
sudo systemctl status dnsmasq
journalctl -u dnsmasq -n 50 --no-pager
Если после отключения stub dnsmasq стартует, но сам сервер перестаёт резолвить имена, почти всегда проблема не в dnsmasq, а в неправильном /etc/resolv.conf. Либо там остался 127.0.0.53, хотя stub уже выключен, либо указан 127.0.0.1, но dnsmasq не слушает loopback.
Полезная мысль: когда используете dnsmasq как локальный кэш, не пытайтесь одновременно держать два локальных резолвера с пересекающимися ролями. Это почти всегда рождает трудноуловимые петли, таймауты и разный результат у разных приложений.

Пошагово: AdGuard Home и занятый port 53
С AdGuard Home ситуация особенно частая, потому что продукт ориентирован на роль основного DNS-сервера для хоста или сети. После установки мастер настройки пытается занять 53-й порт и натыкается на локальный stub от systemd-resolved.
Если видите сообщение о том, что DNS нельзя запустить, сначала не трогайте сам AdGuard Home. Сначала освободите порт 53 со стороны systemd-resolved. То есть снова редактируете resolved.conf, задаёте DNSStubListener=no, перезапускаете службу и перепроверяете, что на 127.0.0.53:53 больше никто не слушает.
После этого уже перезапускайте AdGuard Home и смотрите его статус. Если планируете, чтобы сам сервер тоже пользовался AdGuard Home как DNS, убедитесь, что в /etc/resolv.conf указан адрес, который реально слушает сервис. Чаще всего это 127.0.0.1 или адрес конкретного интерфейса.
Здесь есть важный практический момент: если AdGuard Home слушает только внешний IP, а в /etc/resolv.conf вы прописали 127.0.0.1, резолвинг на хосте работать не будет. И наоборот: если сервис ограничен loopback, клиенты сети до него не достучатся. Всегда сверяйте конфиг слушающих адресов с тем, как реально должны ходить запросы.
Для публичных сервисов и панелей управления не забывайте и про SSL-сертификаты, чтобы административный доступ к веб-интерфейсам был защищён.
Что делать с /etc/resolv.conf после изменений
Большинство проблем после «успешного» устранения конфликта начинаются именно тут. Админ видит, что порт 53 освободился и сервис стартовал, но не замечает, что системный DNS у самого хоста сломан.
Запомните простое правило. Если systemd-resolved остаётся активным, но DNSStubListener выключен, /etc/resolv.conf обычно должен ссылаться не на stub-файл, а на файл с реальными DNS-серверами. Если же systemd-resolved полностью отключён, /etc/resolv.conf должен либо управляться другим механизмом, либо содержать корректные nameserver-записи вручную.
После любых правок проверьте:
getent hosts debian.org
resolvectl query debian.org
dig debian.org
ping -c 1 debian.org
Не все команды одинаково важны в каждой системе, но вместе они быстро показывают, работает ли резолвинг на уровне libc, на уровне resolved и на уровне прямого DNS-запроса.
Если после правок перестал работать
apt, почти всегда причина в том, что/etc/resolv.confостался привязан к127.0.0.53, хотя stub уже отключён, либо ссылается на локальный DNS, который ещё не слушает нужный адрес.
Как проверить, что всё настроено правильно
Хорошая проверка состоит из трёх уровней: порт, служба, резолвинг.
- Порт: кто слушает
53и на каких адресах. - Служба: запущен ли нужный демон без ошибок в журнале.
- Результат: может ли сам хост и клиенты получить DNS-ответ.
Минимальный набор команд после изменений:
ss -lnup '( sport = :53 )'
systemctl status systemd-resolved
systemctl status bind9
systemctl status dnsmasq
journalctl -u systemd-resolved -n 50 --no-pager
cat /etc/resolv.conf
getent hosts ubuntu.com
Разумеется, запускайте только те команды, которые относятся к вашему сервису. Смысл в том, чтобы подтвердить не одну точку, а всю цепочку. Иначе можно ошибочно решить, что конфликт устранён, хотя сервис просто поднялся на другом адресе и не обслуживает тот трафик, который вам нужен.
Типичные ошибки и как их избежать
Самая популярная ошибка — отключить systemd-resolved полностью там, где достаточно было лишь задать DNSStubListener=no. Это не всегда критично, но часто создаёт лишнюю ручную работу с сетью и resolv.conf.
Вторая ошибка — править /etc/resolv.conf вручную, не проверив, не перезаписывает ли его другой компонент: cloud-init, NetworkManager, netplan, dhclient или сам systemd-resolved. Если файл каждый раз возвращается в старое состояние, лечить надо источник генерации, а не только результат.
Третья ошибка — запускать локальный DNS-сервер и тут же направлять системный резолвинг на него, не проверив upstream-конфигурацию. Для dnsmasq, BIND9 и AdGuard Home это заканчивается либо таймаутами, либо рекурсией в самого себя.
Четвёртая ошибка — забыть про IPv6. Даже если конфликт виден на 127.0.0.53, ваш DNS-демон может пытаться дополнительно слушать ::1 или все IPv6-интерфейсы. Поэтому проверяйте не только IPv4-сокеты, но и общий список прослушивания.
Если параллельно на сервере крутятся веб-службы, контейнеры и несколько стеков приложений, полезно заранее разделять роли по сервисам и адресам. Это тот же принцип, который помогает и при настройке нескольких PHP-FPM pool в Nginx: чем прозрачнее схема, тем проще диагностика и сопровождение.
Какой вариант выбрать на практике
Если нужен короткий практический вывод, он такой.
- Для большинства случаев с
bind9,dnsmasqи AdGuard Home на Debian и Ubuntu достаточно отключитьDNSStubListenerвresolved.conf. - Полностью отключать
systemd-resolvedстоит только если вы точно понимаете, как дальше будет обслуживаться системный DNS. - Разнос по адресам полезен в нестандартных схемах, но усложняет сопровождение.
На сервере, где DNS-сервис играет важную роль для инфраструктуры, лучше выбирать конфигурацию с минимальным числом скрытых посредников. Чем понятнее цепочка «кто слушает 53-й порт, кто обслуживает локальный хост, кто ходит к upstream», тем проще сопровождение и аварийное восстановление.
Если вы разворачиваете собственный DNS, фильтрацию запросов, split-horizon или локальный рекурсор на отдельном сервере, особенно удобно делать это в изолированном окружении. В таких сценариях часто практичнее использовать отдельный VDS, чтобы DNS-служба не конфликтовала с уже работающим набором системных сервисов.
Короткий чек-лист для устранения конфликта
- Проверьте, кто слушает порт
53черезssилиlsof. - Убедитесь, что виноват
systemd-resolvedи адрес127.0.0.53. - Если нужен локальный DNS-сервис, задайте
DNSStubListener=noв/etc/systemd/resolved.conf. - Перезапустите
systemd-resolved. - Исправьте
/etc/resolv.confпод новую схему. - Запустите BIND9,
dnsmasqили AdGuard Home. - Проверьте не только статус сервиса, но и реальное разрешение имён на хосте.
Если пройти эти шаги именно в таком порядке, проблема port 53 busy в Debian и Ubuntu обычно решается быстро и без побочных эффектов. А главное — без ситуации, когда DNS-сервер вроде бы поднялся, но сам сервер после этого остался без DNS.


