Выберите продукт

ALPN и SNI в TLS: как сервер выбирает сертификат и протокол, и почему возникает mismatch certificate

Разбираем SNI и ALPN на практике: как сервер выбирает сертификат ещё на этапе TLS-рукопожатия, как согласуется HTTP/2 через ALPN, и как диагностировать mismatch certificate командами openssl s_client (с SNI и без него), чтобы быстро найти ошибку в nginx/Apache.
ALPN и SNI в TLS: как сервер выбирает сертификат и протокол, и почему возникает mismatch certificate

Когда на одном IP живут десятки сайтов, а браузер упорно показывает «не тот сертификат» или вместо HTTP/2 вы видите HTTP/1.1, почти всегда виноваты две части TLS-рукопожатия: SNI и ALPN. Первая сообщает серверу имя хоста ещё до выбора сертификата, вторая — согласовывает прикладной протокол (например, HTTP/2) поверх TLS.

Ниже — практический разбор: как происходит выбор сертификата (tls certificate selection), чем SNI отличается от HTTP-заголовка Host, как проверить поведение через openssl s_client, и что смотреть в конфигурациях nginx и Apache, чтобы убрать mismatch certificate.

Коротко: кто за что отвечает — SNI и ALPN

SNI (Server Name Indication) — расширение TLS, в котором клиент отправляет серверу имя хоста в момент TLS-рукопожатия. Сервер использует это имя, чтобы выбрать правильный сертификат и конфигурацию виртуального хоста на одном IP:порт.

ALPN (Application-Layer Protocol Negotiation) — расширение TLS, позволяющее клиенту предложить список протоколов (например, h2, http/1.1), а серверу — выбрать один. Так браузер понимает, будет ли соединение по HTTP/2 или останется на HTTP/1.1.

Запомните: SNI отвечает за «какой сайт/сертификат», ALPN — за «какой протокол поверх TLS».

На практике это обычно выглядит так:

  • ошибки по сертификату (mismatch) чаще связаны с SNI/выбором vhost по умолчанию;
  • отсутствие HTTP/2 чаще связано с ALPN или настройками/сборкой фронтенда.

Как реально выглядит выбор сертификата (tls certificate selection)

Ключевой момент: выбор сертификата происходит до того, как сервер увидит HTTP-запрос и заголовок Host. Сначала устанавливается TCP-соединение, затем клиент отправляет TLS ClientHello, в котором (если умеет) будут:

  • SNI: имя домена, к которому клиент обращается;
  • ALPN: список поддерживаемых прикладных протоколов.

Если SNI передано — сервер может выбрать сертификат для конкретного домена. Если SNI не передано — сервер обязан выбрать «сертификат по умолчанию» для этого IP:порт (default vhost), и именно его увидит клиент. Отсюда типовая картина: «у домена A сертификат домена B».

Почему SNI критично для мультисайтов на одном IP

На одном IP:443 можно обслуживать множество доменов. Но без SNI сервер не знает, какой именно домен запрашивают, и выдаёт дефолтный сертификат. В браузерах это почти не встречается (современные клиенты SNI поддерживают давно), но в интеграциях всё ещё всплывает: старые Java-рантаймы, устаревшие агенты мониторинга, некоторые встроенные устройства.

Почему ALPN влияет на HTTP/2 и gRPC

Браузер предпочитает h2, но если ALPN не согласован (сервер не объявляет h2 или не поддерживает), соединение останется на http/1.1. Для gRPC ALPN практически обязателен, потому что базовый транспорт — HTTP/2.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Схема TLS ClientHello с полями SNI и ALPN

Диагностика через openssl s_client: проверяем SNI и ALPN

Самый надёжный способ поймать mismatch certificate — посмотреть, какой сертификат сервер отдаёт с SNI и без SNI, и сравнить. На разных версиях OpenSSL поведение по умолчанию отличается, поэтому SNI лучше задавать явно через -servername.

Проверка сертификата с явным SNI

openssl s_client -connect example.com:443 -servername example.com -showcerts

Что смотреть в выводе:

  • subject= и issuer= у leaf-сертификата (первый сертификат в цепочке);
  • Verify return code (0 — ок; другое — проблемы с цепочкой/доверенным корнем);
  • SAN: ищите в тексте сертификата X509v3 Subject Alternative Name и убедитесь, что домен там есть.

Проверка «как будто клиент без SNI»

openssl s_client -connect example.com:443 -showcerts

Если сертификат здесь отличается от проверки с -servername, значит на IP:443 есть дефолтный виртуальный хост, и клиенты без SNI будут получать именно его сертификат. Это не всегда ошибка, но часто неожиданность для мониторинга и интеграций.

Проверка ALPN (договаривались ли о h2)

openssl s_client -connect example.com:443 -servername example.com -alpn h2 -brief

Если сервер поддерживает HTTP/2 и разрешает его на этом vhost, в кратком выводе появится согласованный протокол. Если нет — вы увидите выбор http/1.1 или отсутствие ALPN-согласования (зависит от OpenSSL и сервера).

Полезная привычка: фиксируйте, куда вы реально подключились

Иногда вы тестируете домен, который резолвится «не туда»: CDN, старый IP, другой пул балансировщика, разные ответы по AAAA/A. Чтобы исключить это, подключайтесь к конкретному IP, но сохраняйте нужное SNI:

openssl s_client -connect 203.0.113.10:443 -servername example.com -showcerts

Если вы работаете с фронтовыми прокси и сложной терминацией, полезно держать под рукой отдельный разбор по теме: как терминация TLS/HTTP на прокси влияет на SNI и ALPN.

Типовые причины mismatch certificate (и как их быстро отличить)

Под mismatch certificate обычно скрывается один из трёх сценариев:

  1. сервер отдал сертификат «чужого» домена;
  2. сертификат «почти тот», но домен отсутствует в SAN (например, есть www, но нет apex, или наоборот);
  3. сертификат правильный, но клиент попал на другой виртуальный хост из-за особенностей SNI/прокси/балансировщика.

1) Неправильный default server / default vhost

Если клиент не отправил SNI, сервер выбирает дефолтный хост. В nginx это часто связано с директивой default_server, в Apache — с порядком vhost’ов или отдельным default-конфигом. Симптом: без -servername OpenSSL показывает «левый» сертификат.

2) SNI есть, но конфиг совпал не с тем блоком

Такое бывает, когда:

  • в server_name (nginx) опечатка или неверная маска;
  • используются пересекающиеся шаблоны имён, и матчится «первый подходящий» серверный блок;
  • сертификат указан не в том месте, а соединение пришло в другой листенер (другой IP/порт/443 vs 8443 и т. п.).

3) На уровне балансировщика или прокси SNI/ALPN «не там»

Если TLS терминируется не на веб-сервере, а на прокси/балансировщике, то именно он должен разрулить SNI и объявить ALPN. А если TLS «пробрасывается» дальше (passthrough), прокси должен уметь маршрутизировать по SNI на TCP-уровне. Симптом: на бэкенде «всё правильно», но клиент видит чужой сертификат или не договаривается на h2.

4) Ошибка SAN: сертификат не покрывает нужное имя

Классика: сертификат только на www.example.com, а пользователи ходят на example.com (или наоборот). С точки зрения браузера это тоже mismatch. Верифицируйте SAN и при необходимости перевыпустите сертификат. Если нужен коммерческий вариант с понятной поддержкой и прогнозируемыми сроками выпуска, смотрите SSL-сертификаты.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Nginx: выбор сертификата по SNI и частые ошибки

В nginx логика простая: один IP:порт слушается директивой listen 443 ssl, а дальше выбор идёт по server_name. Сертификат задаётся директивами ssl_certificate и ssl_certificate_key внутри конкретного server-блока.

Минимальный пример двух сайтов на одном IP

server {
    listen 443 ssl default_server;
    server_name _;

    ssl_certificate /etc/ssl/default/fullchain.pem;
    ssl_certificate_key /etc/ssl/default/privkey.pem;

    return 444;
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/ssl/example/fullchain.pem;
    ssl_certificate_key /etc/ssl/example/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Почему полезен «явный» default: если какой-то клиент пришёл без SNI или с мусорным именем, вы не отдаёте случайно сертификат живого сайта и не создаёте путаницу в логах и алертах.

Как быстро понять, какой серверный блок обслужил TLS-запрос

Для HTTP-запросов помогают $host и $server_name, но для TLS-рукопожатия важнее имя из SNI — переменная $ssl_server_name. Её удобно писать в access_log (если переменная доступна в вашей версии).

Если вы одновременно приводите в порядок TLS и «обвязку» сайта, не забудьте про базовую гигиену ответов: настройка HTTP security headers в nginx и Apache.

Примеры конфигурации nginx и Apache для SNI и выбора сертификата

Apache: что важно понимать про SSL vhost на 443

В Apache SNI работает через name-based virtual hosts на *:443 (или на конкретном IP:443). В современных версиях достаточно описать <VirtualHost *:443> блоки и указать сертификаты внутри каждого, но порядок и «дефолтность» всё ещё имеют значение.

Пример: два SSL vhost

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com

    SSLEngine on
    SSLCertificateFile /etc/ssl/example/cert.pem
    SSLCertificateKeyFile /etc/ssl/example/key.pem
    SSLCertificateChainFile /etc/ssl/example/chain.pem

    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

<VirtualHost *:443>
    ServerName other.example

    SSLEngine on
    SSLCertificateFile /etc/ssl/other/cert.pem
    SSLCertificateKeyFile /etc/ssl/other/key.pem
    SSLCertificateChainFile /etc/ssl/other/chain.pem
</VirtualHost>

Если клиент без SNI, Apache отдаст сертификат первого объявленного vhost для этого адреса:порта. Поэтому порядок конфигов и наличие «осознанного дефолта» важны так же, как и в nginx.

ALPN на практике: почему HTTP/2 «не включился», хотя TLS работает

Ситуация: сертификат правильный, HTTPS работает, но в DevTools вы видите HTTP/1.1. Это не всегда проблема, но если вы ожидаете HTTP/2 (или он нужен для gRPC), проверяйте ALPN.

Частые причины отсутствия h2

  • веб-сервер/сборка не поддерживает HTTP/2 (в nginx — отсутствие модуля, в Apache — не включён mod_http2);
  • HTTP/2 включён только для части vhost’ов или только на одном из листенеров;
  • TLS терминируется на прокси, который не объявляет h2 в ALPN или форсирует http/1.1 к клиенту;
  • редкий случай: слишком жёсткие ограничения по TLS-версиям/параметрам приводят к несовместимости с конкретным клиентом.

Как отличить проблему ALPN от проблемы приложения

ALPN определяется в момент TLS. Если через openssl s_client вы не можете согласовать h2, никакая настройка приложения «выше» (заголовки, редиректы, роутинг) это не исправит: сначала чинится TLS-конфигурация и поддержка протокола на фронте.

Чеклист: что проверить, если SNI/ALPN ведут себя странно

  1. DNS и IP: вы тестируете тот же адрес, куда ходят пользователи? Сверьте A/AAAA и фактический IP на балансировщике/сервере.
  2. Сертификат с SNI: openssl s_client -servername должен отдавать правильный leaf и цепочку.
  3. Сертификат без SNI: убедитесь, что дефолтный vhost не вводит в заблуждение мониторинг и интеграции.
  4. SAN: покрывает ли сертификат apex, www и нужные поддомены.
  5. Матчинг vhost: в nginx проверьте server_name и наличие default_server; в Apache — порядок SSL vhost на 443.
  6. ALPN: тестируйте -alpn h2 и фиксируйте, что выбрано.
  7. Точка терминации: где именно заканчивается TLS — на веб-сервере или на прокси/балансировщике?

Практический сценарий: «чужой сертификат» ругается только мониторинг

Частый кейс: браузеры всё показывают правильно, а мониторинг (или старый клиент) ругается на «чужой» сертификат. Почти всегда это проверка, которая подключается к IP:443 без SNI (например, мониторинг ходит по IP, а не по доменному имени).

Что делать:

  • настроить мониторинг так, чтобы он подключался по доменному имени и отправлял SNI;
  • иметь осознанный default vhost на 443 (с отдельным сертификатом-заглушкой или политикой «не обслуживаем»), чтобы проверки «без имени» не путали картину;
  • если обязаны поддерживать клиентов без SNI — выделить отдельный IP для критичного домена или объединить имена под одним сертификатом (если это допустимо по архитектуре).

Вывод

SNI и ALPN — две вещи, которые незаметны, пока всё работает, и крайне заметны, когда что-то пошло не так. SNI определяет, какой сертификат и конфигурацию выберет сервер, а ALPN — согласует протокол (например, HTTP/2). Если вы видите mismatch certificate, начинайте со сравнения выдачи сертификата в openssl s_client с параметром -servername и без него, затем проверяйте дефолтный vhost и шаблоны имён в nginx/Apache.

Если вам нужно разнести много проектов по изоляции (разные версии ПО, разные TLS-политики, отдельные IP, собственные прокси) — иногда проще вынести сайты на отдельные инстансы. В таком случае пригодится VDS, чтобы жёстко разделить окружения и исключить сюрпризы с default vhost на общем фронтенде.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: конфликт systemd-resolved DNSStubListener на 127.0.0.53 с dnsmasq, Unbound и BIND OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: конфликт systemd-resolved DNSStubListener на 127.0.0.53 с dnsmasq, Unbound и BIND

Если локальный DNS в Debian или Ubuntu не стартует с ошибкой address already in use, причина часто в systemd-resolved и DNSStubLis ...
Debian/Ubuntu: как исправить NFS mount.nfs: access denied by server while mounting OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить NFS mount.nfs: access denied by server while mounting

Ошибка mount.nfs: access denied by server while mounting в Debian и Ubuntu обычно указывает на проблему на стороне NFS-сервера: не ...
Debian/Ubuntu: как устранить конфликт systemd-resolved DNSStubListener с BIND9, dnsmasq и AdGuard Home OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как устранить конфликт systemd-resolved DNSStubListener с BIND9, dnsmasq и AdGuard Home

Если в Debian или Ubuntu DNS-сервер не стартует из-за ошибки port 53 busy, часто причина в systemd-resolved с локальным слушателем ...