Учебник веб-разработки
Разделы учебника
На этой странице

XI. DevOps

DNS и TLS: как браузер находит и проверяет сервер

Оглавление · HTTP · Reverse proxy

Задача: проследить путь от URL до защищённого соединения и локализовать сбой. Нужны основы HTTP и процессов. Рассматриваем обычный HTTPS по TCP; HTTP/3 использует QUIC и разобран в следующей главе.

URL задаёт несколько независимых вещей

Для https://media.example.invalid/photos/sky.webp?size=small схема задаёт HTTPS, имя — media.example.invalid, стандартный порт — 443, путь — /photos/sky.webp, query — size=small. Fragment после # обычно остаётся в браузере и не входит в HTTP-запрос. Домен example.invalid вымышленный; это не рабочий сайт.

Исходник схемы
flowchart TD
  URL["URL: схема, имя, порт, путь"] --> DNS["Получить адрес для имени"]
  DNS --> TCP["Соединиться с адресом и портом"]
  TCP --> TLS["TLS: проверить сервер и согласовать ключи"]
  TLS --> HTTP["HTTP: имя сайта, метод, путь, заголовки"]
  HTTP --> Response["Ответ: статус, заголовки, тело"]

Браузер может использовать кеши и существующее соединение; схема показывает ответственность этапов, а не обязательный новый обмен для каждого изображения. DNS-ответ не подтверждает, что порт открыт. TCP-соединение не подтверждает сертификат. Успешный TLS не проверяет содержание страницы.

DNS — распределённое пространство имён

DNS хранит записи разных типов. A задаёт IPv4-адрес, AAAA — IPv6, CNAME — другое имя, NS — серверы зоны; TXT используется, например, при подтверждении управления доменом. DNS не задаёт HTTP-путь и обычно не выбирает сервис по порту URL. Авторитетный сервер отвечает за зону, recursive resolver ищет ответ для клиента и кеширует его. Root и TLD помогают найти сервер зоны, а не обслуживают сайт. Модель DNS, RFC 1034.

Исходник схемы
sequenceDiagram
  participant Client as Клиент
  participant Resolver as Recursive resolver
  participant Authority as Авторитетный сервер зоны
  Client->>Resolver: Запись A для site.example.invalid?
  Note over Resolver: При cache miss найти сервер зоны через делегации
  Resolver->>Authority: Запись A для имени?
  Authority-->>Resolver: Адрес и TTL
  Resolver-->>Client: Ответ из найденной записи
  Note over Resolver: Следующий запрос может обслужить кеш

TTL ограничивает время обычного кеширования записи; это не единый таймер «распространения DNS» во всём интернете. При смене адреса часть клиентов ещё использует старый ответ. Снижение TTL после изменения не сокращает уже выданный старый TTL. NXDOMAIN обозначает отсутствие имени, а пустой ответ конкретного типа не обязательно означает отсутствие самого имени. Отрицательные ответы тоже могут кешироваться. Отрицательное кеширование, RFC 2308.

Для чтения записей своего учебного домена:

dig site.example.invalid A
dig site.example.invalid AAAA

Смотрите status, ANSWER и сервер, который ответил. +short удобен для адресов, но скрывает часть диагностического контекста. Успех A при неверном AAAA может давать разные результаты у IPv4- и IPv6-клиентов. Это не повод удалять IPv6 наугад: сначала проверьте, куда он ведёт и доступен ли сервис этим путём.

Внутренняя Docker-сеть разрешает имена сервисов отдельно от публичного DNS. Имя web:3000 удобно Caddy внутри Compose, но браузер пользователя его не знает. Запись внешнего домена в DNS не создаёт контейнер или маршрут Caddy.

TLS устанавливает защищённый канал

TLS согласует параметры и ключи, обеспечивает конфиденциальность и целостность обмена и обычно аутентифицирует сервер сертификатом. Клиент проверяет цепочку доверия, срок и соответствие имени сертификату. Сервер доказывает владение приватным ключом; сертификат содержит публичный ключ. Сам сертификат не является общим секретом. TLS 1.3, RFC 8446.

Исходник схемы
sequenceDiagram
  participant Browser as Клиент
  participant Caddy as TLS-сервер Caddy
  Browser->>Caddy: ClientHello: параметры, SNI, ALPN
  Caddy-->>Browser: Параметры, сертификат и доказательство владения ключом
  Note over Browser: Проверить имя, доверие и обмен
  Browser->>Caddy: Завершить handshake
  Browser->>Caddy: HTTP внутри защищённого канала

Схема опускает детали криптографии. SNI сообщает желаемое серверное имя при handshake, до обычного HTTP-запроса; оно помогает выбирать сертификат на общем IP. HTTP Host или :authority затем задаёт адресата HTTP-запроса. Изменение Host после подключения к IP не подменяет имя для проверки сертификата. SNI, RFC 6066. ALPN согласует прикладной протокол, например h2 или http/1.1. ALPN, RFC 7301.

HTTPS подтверждает защищённое соединение с проверенным именем. Оно не гарантирует, что владелец сайта добросовестен, данные верны или пользователь имеет право читать CMS. Аутентификация пользователя и авторизация операций остаются задачей приложения. При TLS termination в Caddy канал до браузера защищён; отдельное соединение Caddy → web в нашем Compose использует HTTP внутри сети. Это разные участки.

Сертификат тоже имеет жизненный цикл

Для публичных имён Caddy автоматически получает и обновляет сертификаты через ACME и добавляет перенаправление HTTP → HTTPS. Требуются подходящие DNS-записи, доступность портов для выбранной проверки и постоянное writable-хранилище Caddy. Явный адрес http:// в локальной конфигурации отключает automatic HTTPS для него. Caddy Automatic HTTPS.

HTTP-01 доказывает управление через специальный HTTP-путь на порту 80; TLS-ALPN-01 — через специальный TLS-обмен на 443; DNS-01 — через TXT-запись. Возможность обычного GET страницы не равна прохождению каждой ACME-проверки. DNS-01 требует отдельной интеграции; в проект её не добавляем. ACME-проверки Let's Encrypt.

В Atmanki compose сохраняет /data Caddy в named volume caddy_data. Удаление контейнера и удаление этого тома имеют разные последствия. Ошибка выпуска или обновления сертификата диагностируется по DNS, доступности и логам Caddy; отключение проверки TLS у клиента не исправляет сервер.

Проверяйте по слоям

СимптомСледующий вопросЧего вывод пока не доказывает
Имя не найденоКакой resolver и какой тип записи?Состояние приложения
Адрес получен, connect timeoutДоступны ли маршрут, порт, firewall?Неверный сертификат
Ошибка сертификатаКакое имя, срок, цепочка и время клиента?Ошибка React
TLS успешен, HTTP 502Какой upstream выбран и доступен?Отказ DNS клиента
HTML 200, изображение 404Каков URL, rewrite, bucket и key?Отказ всего TLS-входа

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

Для своего домена используйте ограниченное ожидание и обычный GET:

curl --connect-timeout 5 --max-time 15 --fail --silent --show-error \
  --output /dev/null --write-out 'status=%{http_code} version=%{http_version}\n' \
  https://site.example.invalid/api/health

Команда с вымышленным именем ожидаемо не проверяет реальный VPS. curl -I делает HEAD, а не GET; используйте тот метод, который входит в контракт проверки. Не добавляйте -k: он отключает проверку сертификата и ослабляет вывод опыта. Опции curl.

Упражнение

Для двух клиентов один домен даёт разные адреса. Нарисуйте источники ответов и кеши, затем предложите проверку. Во втором случае подключение к IP успешно, но сертификат не подходит URL: какие имена участвуют в DNS, SNI и HTTP? Не меняйте записи production ради опыта. Дальше — прокси и транспорт HTTP.