DNS в Linux: резолвинг, /etc/hosts, resolv.conf
Каждый запрос к сайту начинается с превращения имени в IP-адрес. Разберём, как именно Linux резолвит имена и где это чинить, когда «DNS сломался».
DNS-резолвинг — процесс преобразования доменного имени (
example.com) в IP-адрес. В Linux за него отвечает цепочка: локальный файл/etc/hosts, настройки/etc/resolv.confи (на современных системах) службаsystemd-resolved.
Зачем это на практике
«Сайт не открывается» в половине случаев — это проблема не сети, а DNS: пинг по IP идёт, а по имени нет. Уметь руками проверить резолвинг, прописать тестовую запись в /etc/hosts и понять, какой резолвер реально используется, — навык, который экономит часы. Особенно это важно при разработке: подменить домен на локальный сервер, отладить балансировщик, проверить новую запись DNS до того, как она «разъедется» по миру.
Как резолвится имя: порядок источников
Когда программа хочет узнать IP для example.com, она спрашивает не сразу DNS-сервер. Порядок источников задаёт строка hosts: в файле /etc/nsswitch.conf:
grep ^hosts /etc/nsswitch.conf
hosts: files dns
Здесь files означает «сначала загляни в /etc/hosts», и только потом dns — «спроси DNS-сервер». Поэтому запись в /etc/hosts всегда побеждает настоящий DNS — это и инструмент отладки, и источник коварных багов.
Файл /etc/hosts: ручные записи
Простой текстовый файл «IP — имена». Добавим запись, чтобы myapp.local вёл на локальную машину:
cat /etc/hosts
127.0.0.1 localhost 127.0.1.1 my-laptop 127.0.0.1 myapp.local api.myapp.local
Теперь любой запрос к myapp.local пойдёт на 127.0.0.1, минуя интернет. Это удобно для локальной разработки и для временной блокировки домена (направить его на 0.0.0.0). Изменения в /etc/hosts вступают в силу мгновенно, без перезапуска служб.
Файл /etc/resolv.conf: какие DNS-серверы спрашивать
Если в /etc/hosts имени нет, система идёт к DNS-серверам из /etc/resolv.conf:
cat /etc/resolv.conf
nameserver 127.0.0.53 search lan options edns0 trust-ad
Строки nameserver перечисляют DNS-серверы (их спрашивают по порядку), search lan добавляет суффикс к коротким именам (server1 → server1.lan). Важная деталь современных систем: nameserver 127.0.0.53 — это не настоящий внешний сервер, а локальная заглушка systemd-resolved.
systemd-resolved: локальный кэширующий резолвер
systemd-resolved — служба, которая принимает DNS-запросы на
127.0.0.53, кэширует ответы и сама ходит к настоящим upstream-серверам, прописанным отдельно.
Поэтому на Ubuntu редактировать /etc/resolv.conf руками обычно бесполезно — его перезаписывает служба. Реальные настройки и кэш смотрят так:
resolvectl status # какие upstream-DNS и для каких интерфейсов
resolvectl query example.com # резолв через systemd-resolved
resolvectl statistics # размер и попадания кэша
sudo resolvectl flush-caches # сбросить DNS-кэш
Команда resolvectl flush-caches — частый ответ на «изменил DNS-запись, а старый IP всё ещё подставляется»: помог сбросить локальный кэш.
Инструменты диагностики: dig, host, nslookup
Чтобы спросить DNS напрямую, минуя кэш системы, есть три инструмента. Самый информативный — dig:
dig example.com # A-запись (IPv4)
dig +short example.com # только сам IP, без шума
dig example.com MX # почтовые серверы домена
dig @8.8.8.8 example.com # спросить конкретный сервер (Google)
host example.com # коротко и человекочитаемо
nslookup example.com # классика, есть почти везде
В выводе dig ключевая секция — ANSWER SECTION; там же поле TTL (сколько секунд запись можно кэшировать). Приём dig @8.8.8.8 отвечает на вопрос «это мой локальный резолвер врёт или запись действительно такая» — вы спрашиваете публичный сервер напрямую и сравниваете.
Типы записей и обратный резолвинг
DNS хранит не только IPv4-адреса. Полезно знать основные типы записей, потому что одно имя может вести себя по-разному в зависимости от того, что запрашивают:
| Запись | Что означает |
A | IPv4-адрес имени |
AAAA | IPv6-адрес имени |
CNAME | псевдоним, ссылка на другое имя |
MX | почтовые серверы домена |
TXT | произвольный текст (SPF, верификация) |
PTR | обратная запись: IP в имя |
Обратный резолвинг (по IP узнать имя) делают так:
dig -x 93.184.216.34 # обратный резолв: IP в имя (PTR-запись)
host 93.184.216.34 # коротко, то же самое
dig example.com AAAA +short # IPv6-адрес, если он есть
Обратные записи важны для почты: многие почтовые серверы отвергают письма с хостов без корректного PTR. А CNAME объясняет, почему dig www.site.com иногда показывает сначала псевдоним, а потом уже реальный IP той записи, на которую он указывает.
Как это работает под капотом
Резолвинг имени для большинства программ делает функция getaddrinfo() из библиотеки glibc. Она читает /etc/nsswitch.conf, идёт по источникам (files, затем dns) и на этапе dns отправляет UDP-запрос на порт 53 ближайшему nameserver. Сам DNS устроен иерархически: корневые серверы знают, кто отвечает за .com, те — кто за example.com, и так до конкретной A-записи. systemd-resolved встаёт посередине как кэш: первый запрос идёт наружу, последующие отдаются мгновенно из памяти, пока не истечёт TTL. Важно: dig и nslookup ходят к DNS-серверу напрямую и НЕ читают /etc/hosts — поэтому их ответ может отличаться от того, что видят обычные программы.
Частые ошибки
- Правят
/etc/resolv.confна Ubuntu и удивляются, что настройки откатились. Файлом управляетsystemd-resolved; меняйте черезresolvectlили конфиг службы. - Забыли про кэш. Поменяли DNS-запись, а подставляется старый IP — нужен
resolvectl flush-caches(или просто ждать истечения TTL). - Думают, что
digпокажет результат как у браузера.digигнорирует/etc/hosts; если там есть запись, программы пойдут по ней, аdig— мимо. - Тестовая строка в
/etc/hostsосталась навсегда. Классический баг: домен в проде «не туда ходит», потому что год назад вписали его в hosts для отладки.
Итоги
- Порядок резолвинга задаёт
/etc/nsswitch.conf: обычно сначала/etc/hosts, потом DNS. /etc/hostsпобеждает настоящий DNS и работает мгновенно — удобно для отладки, опасно как забытая запись.- На современных системах резолвер —
systemd-resolvedна127.0.0.53; смотреть черезresolvectl status, кэш сбрасыватьresolvectl flush-caches. dig +short,host,nslookupспрашивают DNS напрямую (мимо/etc/hosts);dig @серверпроверяет конкретный DNS-сервер.