Хостинг от ERA Host
EraHost - бесплатный домен, дешевый хост
личный кабинет
служба поддержки
USD
Menu

Ошибки SSL-сертификата в браузере: причины и диагностика

Читать 32 мин.
08.09.2026

Браузер может показать предупреждение о проблеме SSL по десяткам разных причин: сертификат просрочен, выпущен не для того имени, сервер отдаёт неполную цепочку, DNS ведёт на старый IP, а на VPS отвечает соседний виртуальный хост. Внешне всё выглядит одинаково — вместо сайта пользователь получает страницу «Подключение не защищено» или код вида NET::ERR_CERT_....

Поэтому начинать с перевыпуска сертификата — плохая стратегия. Если браузер попадает на другой сервер или Cloudflare показывает свой edge-сертификат, новый файл на VPS вообще ничего не изменит. Сначала нужно выяснить две вещи: к какому узлу подключился клиент и какой сертификат он фактически получил через порт 443.

Диагностику удобнее вести сверху вниз: браузер, DNS, CDN или reverse proxy, IP:443, TLS/SNI, виртуальный хост, сертификат и его цепочка, затем конфигурация Nginx или Apache. Такой порядок быстро отсеивает рабочие уровни и не заставляет менять несколько настроек одновременно.

Команды ниже рассчитаны прежде всего на Linux, VPS и серверы с Nginx или Apache. Владельцу сайта без SSH-доступа всё равно пригодится первая половина проверок: код браузера, сведения о сертификате, DNS и сравнение результата с другого устройства или сети.

Что означает конкретная ошибка SSL в браузере и с чего начинать проверку

Точный код ошибки уже заметно сужает поиск. Фраза «SSL не работает» почти бесполезна для диагностики, а NET::ERR_CERT_DATE_INVALID или NET::ERR_CERT_COMMON_NAME_INVALID сразу указывает, какой параметр проверять первым.

Chrome, Edge и другие Chromium-браузеры используют одни обозначения, Firefox — другие. Формулировки могут отличаться, поэтому важнее определить класс проблемы: срок действия, имя домена, доверие к центру сертификации или сам TLS-handshake.

Ошибка Что проверять первым Инструмент
NET::ERR_CERT_DATE_INVALID Срок сертификата и часы на устройстве Браузер, OpenSSL
NET::ERR_CERT_COMMON_NAME_INVALID Имя сайта и SAN сертификата Браузер, OpenSSL
NET::ERR_CERT_AUTHORITY_INVALID Цепочка доверия и тип сертификата OpenSSL
SEC_ERROR_UNKNOWN_ISSUER Intermediate CA и fullchain OpenSSL
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT Не используется ли self-signed сертификат Браузер, OpenSSL
ERR_SSL_PROTOCOL_ERROR TLS-handshake и сервис на порту 443 OpenSSL, ss, логи веб-сервера

Дальнейшая ветка обычно определяется сразу. Ошибка DATE ведёт к датам сертификата и системным часам. NAME — к SAN, SNI и DNS. AUTHORITY — к цепочке и доверенному CA. PROTOCOL — к порту 443, TLS и конфигурации сервиса.

Перед изменениями откройте сведения о сертификате в браузере и запишите домен, издателя, даты действия и код ошибки. Если проблема проявляется только у одного пользователя, полезнее получить скриншот страницы предупреждения и сведений о сертификате, чем сообщение «у меня красный замок».

Сначала снимаем симптом, потом меняем конфигурацию. Один точный тест здесь полезнее пяти случайных действий.

Почему NET::ERR_CERT_DATE_INVALID появляется даже у недавно установленного сертификата

NET::ERR_CERT_DATE_INVALID означает, что браузер не принимает временной интервал действия сертификата. Сертификат может быть уже просрочен, ещё не вступить в действие либо время на компьютере пользователя сильно отличается от реального.

Как проверить Not Before и Not After

У сертификата есть два временных ограничения: notBefore и notAfter. Первое показывает, с какого момента сертификат действителен, второе — когда его действие заканчивается. Проверить сертификат, который сервер отдаёт сейчас, можно так:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates

Типичный вывод содержит две строки:

notBefore=Sep  1 00:00:00 2026 GMT
notAfter=Nov 30 23:59:59 2026 GMT

Если notAfter уже в прошлом, причина найдена. Если даты нормальные, проверьте часы устройства, на котором появляется ошибка. Именно клиент сравнивает текущее время с периодом валидности сертификата.

Почему после продления браузер может видеть старый сертификат

Файл на сервере мог успешно обновиться, но это ещё не доказывает, что веб-сервер его загрузил. Например, автоматическое продление Let's Encrypt записало новый fullchain.pem, а последующий reload Nginx завершился ошибкой. Рабочие процессы продолжают обслуживать соединения со старой конфигурацией.

Обычно путаница начинается именно здесь: в панели уже виден новый сертификат, а через 443 всё ещё приходит старый serial. Сертификат на диске и сертификат в сокете — не всегда одно и то же.

Нужно ли проверять время на VPS

Для проверки сертификата браузером критичнее часы клиентского устройства. Время VPS само по себе не изменяет notBefore и notAfter, но сильный рассинхрон способен мешать автоматическому выпуску, обновлению сертификатов и другим операциям вокруг TLS.

date
timedatectl

Если срок сертификата нормальный, часы клиента правильные, а браузер всё равно показывает DATE_INVALID, проверьте сертификат непосредственно на порту 443. Там нередко и находится старый экземпляр.

Почему браузер пишет, что SSL-сертификат выпущен не для этого домена

NET::ERR_CERT_COMMON_NAME_INVALID обычно означает, что имя в адресной строке не входит в список имён сертификата. Второй сценарий — сертификат сам по себе правильный, но запрос попал в чужой виртуальный хост и сервер отдал сертификат соседнего сайта.

example.com и www.example.com проверяются отдельно

Сертификат для example.com не обязан автоматически покрывать www.example.com. Чтобы оба варианта работали, оба имени должны присутствовать в Subject Alternative Name, если их не покрывает подходящий wildcard.

Посмотреть SAN можно в браузере либо через OpenSSL:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -ext subjectAltName

Если установленная версия OpenSSL не поддерживает вывод отдельного extension, используйте полный просмотр:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -text

В полном выводе нужен блок X509v3 Subject Alternative Name. Сравнивать нужно именно имена SAN с hostname в адресной строке.

Как работает wildcard-сертификат

Имя Покрывает ли *.example.com
www.example.com Да
shop.example.com Да
example.com Нет
a.b.example.com Нет

Wildcard закрывает один уровень поддоменов. Если нужен и корневой домен, его добавляют в сертификат отдельным SAN.

Что происходит при открытии сайта по IP

Если в сертификате указано example.com, открытие https://203.0.113.10/ приведёт к несовпадению имени. Для корректного подключения непосредственно по IP сам IP должен присутствовать в сертификате как соответствующий SAN. Для обычного сайта такой сценарий чаще всего не нужен.

Если SAN содержит правильное имя, а браузер всё равно жалуется на домен, посмотрите subject фактически полученного сертификата. Если там другой сайт, копать выпуск сертификата уже нет смысла: проверяйте DNS, SNI, CDN и virtual host.

Почему браузер не доверяет сертификату: ERR_CERT_AUTHORITY_INVALID и SEC_ERROR_UNKNOWN_ISSUER

Сертификат может подходить домену и не быть просроченным, но Firefox всё равно показывает SEC_ERROR_UNKNOWN_ISSUER, а Chromium — ошибку доверия. В такой ситуации нужно смотреть не только leaf-сертификат сайта, но и цепочку, которую сервер отправляет клиенту.

Как выглядит нормальная цепочка сертификатов

Упрощённо путь доверия состоит из сертификата сайта, одного или нескольких intermediate CA и доверенного root CA. Корневой сертификат обычно уже находится в хранилище клиента, поэтому серверу его, как правило, отправлять не требуется.

Для Nginx файл, указанный в ssl_certificate, обычно содержит leaf-сертификат и нужные intermediate-сертификаты. У Let's Encrypt для этой задачи используется fullchain.pem.

Посмотреть, что реально передаёт сервер:

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

Как выглядит неполная цепочка в openssl

В выводе есть блок Certificate chain. Сокращённый пример нормальной структуры может выглядеть так:

Certificate chain
 0 s:CN = example.com
   i:CN = Intermediate CA
 1 s:CN = Intermediate CA
   i:CN = Root CA

Запись 0 — сертификат сайта. Следующая запись — intermediate, который подписал leaf. Названия CA здесь условные: у конкретного сертификата они будут другими.

Если сервер отправляет только позицию 0, а issuer leaf указывает на промежуточный CA, которого в переданной цепочке нет, fullchain нужно проверить особенно внимательно.

В конце s_client выводит результат проверки. При корректной цепочке и подходящем локальном trust store ожидается:

Verify return code: 0 (ok)

При проблеме можно увидеть, например:

verify error:num=20:unable to get local issuer certificate

Это сильная подсказка, но не окончательный диагноз. OpenSSL проверяет цепочку с использованием собственного локального хранилища доверенных CA. Если на машине старый или урезанный trust store, ненулевой Verify return code ещё не доказывает, что все современные браузеры будут показывать ту же ошибку.

Как отделить ошибку сервера от проблемы локального trust store

Сначала посмотрите, сколько сертификатов сервер реально отправил и кто указан issuer у leaf. Затем убедитесь, что нужный intermediate присутствует в цепочке. После этого повторите тест с другой актуальной системой или независимым внешним TLS-проверяющим сервисом.

Если несколько современных клиентов независимо сообщают о недостающем issuer, а -showcerts показывает только leaf, проблема находится на сервере. Если сервер отдаёт полный chain, а ошибка остаётся только на старой машине, переходите к локальному хранилищу доверенных CA.

Иногда один браузер открывает сайт, а другой ругается именно потому, что первый уже знает промежуточный сертификат или умеет достроить цепочку другим способом. Поэтому «у меня открывается» не подтверждает правильный fullchain.

Если публичный сертификат валиден, а сервер просто не отправляет intermediate, перевыпускать сертификат обычно не требуется. Исправлять нужно цепочку, которую выдаёт веб-сервер.

Как проверить, какой SSL-сертификат сервер реально отдаёт пользователю

Самая полезная проверка при спорной SSL-ошибке — посмотреть сертификат непосредственно на порту 443. Панель управления показывает настройку. OpenSSL показывает, что реально получил TLS-клиент.

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

Параметр -servername передаёт имя сайта через SNI. Для сервера, где на одном IP размещено несколько HTTPS-сайтов, без этого параметра результат может быть совсем другим.

Чтобы получить только основные поля сертификата:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates -serial
  • subject — какому сертификату вы подключились;
  • issuer — кто его выпустил;
  • notBefore / notAfter — период действия;
  • serial — удобный идентификатор для сравнения старого и нового сертификата;
  • SAN — какие имена покрывает сертификат.

HTTPS-запрос целиком удобно проверить через curl:

curl -Iv https://example.com/

curl покажет IP подключения, TLS-сессию и HTTP-ответ. Если OpenSSL показывает ожидаемый сертификат, а curl подключается к другому IP, это уже повод вернуться к DNS, IPv6 или прокси.

Как точно сравнить сертификат на диске и сертификат через сеть

Когда даты и subject совпадают, но нужно убедиться, что это один и тот же сертификат, сравните SHA-256 fingerprint.

Для файла:

openssl x509 -in cert.pem -noout -fingerprint -sha256

Для сертификата на порту 443:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -fingerprint -sha256

Одинаковый fingerprint означает, что через сеть приходит именно тот сертификат, который вы проверили на диске. Разные значения — сервер, proxy или CDN отдаёт другой экземпляр.

Команда Что помогает проверить
openssl s_client TLS-handshake, сертификат, SNI, цепочку
curl -Iv IP подключения, TLS и HTTP-ответ
curl --resolve Конкретный сервер в обход DNS
dig A IPv4-адрес домена
dig AAAA IPv6-адрес домена
nginx -t Синтаксис и загрузку конфигурации Nginx
apachectl configtest Конфигурацию Apache

Полезная модель диагностики: файл сертификата на диске, сертификат в конфигурации веб-сервера и сертификат, полученный браузером, — три разные точки проверки. Совпасть должны все три.

Почему без SNI сервер показывает SSL-сертификат другого сайта

На одном IP может быть десять HTTPS-сайтов. Запустили openssl s_client по IP без имени — и получили сертификат соседнего домена. Паниковать рано: такой тест сам мог попасть в default vhost.

При TLS-соединении клиент передаёт hostname через Server Name Indication — SNI. Современные браузеры делают это автоматически, а ручная проверка без -servername может показать сертификат виртуального хоста по умолчанию.

Сравните подключение с SNI и без него

openssl s_client -connect 203.0.113.10:443

Теперь тот же IP, но с нужным hostname:

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

Если во втором случае появляется правильный сертификат, а в первом — чужой, сам HTTPS сайта может быть настроен нормально. Первый тест просто не передал SNI.

Если и с -servername example.com приходит сертификат соседнего сайта, проверяйте virtual host.

Что смотреть в Nginx

nginx -T

Найдите блок, который слушает 443 и содержит нужный server_name. В нём же проверьте ssl_certificate и ssl_certificate_key. Если одно имя описано в нескольких конфигурациях или домен попал в неожиданный default_server, результат может отличаться от того, что показывает панель управления.

Что смотреть в Apache

apachectl -S

Команда показывает виртуальные хосты и помогает увидеть, какой VirtualHost обслуживает имя и порт. На Debian/Ubuntu вместо apachectl также используется apache2ctl.

После правки снова проверяйте соединение с правильным -servername. Для нужного hostname должен приходить его сертификат. Если так и есть, ветку SNI можно закрывать.

Как DNS может привести к правильному домену, но неправильному SSL-сертификату

SSL может быть безупречно настроен на нужном VPS, но пользователь всё равно увидит старый или чужой сертификат, если DNS отправляет его на другой узел. Сертификат в таком случае вообще не виноват.

Проверьте A и AAAA отдельно

dig example.com A
dig example.com AAAA
dig www.example.com A
dig www.example.com AAAA

Если A уже указывает на новый VPS, а забытая AAAA всё ещё ведёт на старый сервер, клиенты с рабочим IPv6 могут получать совершенно другой сайт и сертификат. На устройствах без IPv6 ошибка при этом не воспроизводится.

Ситуация после миграции выглядит знакомо: A уже исправили, сайт у администратора открывается, а часть пользователей продолжает жаловаться. AAAA в таком случае стоит проверить раньше кеша браузера.

Проверьте HTTPS отдельно по IPv4 и IPv6

Одного dig недостаточно, если нужно увидеть реальное HTTPS-подключение по каждому стеку.

curl -4 -Iv https://example.com/
curl -6 -Iv https://example.com/

Если IPv4 проходит нормально, а IPv6 получает другой сертификат или вообще не устанавливает TLS, проблема уже локализована. Проверяйте AAAA, IPv6-адрес сервера, firewall и HTTPS-конфигурацию на этом адресе.

Корневой домен и www тоже могут расходиться

example.com и www.example.com — отдельные DNS-имена. Один адрес может идти через Cloudflare, второй напрямую на VPS. Один может иметь свежий сертификат, второй — старый.

curl -Iv https://example.com/
curl -Iv https://www.example.com/

В начале соединения curl показывает адрес назначения. Если он не совпадает с ожидаемой инфраструктурой, разбираться с Nginx на нужном VPS пока рано.

Симптом Куда смотреть Почему
Часть пользователей видит старый сертификат A и AAAA IPv4 и IPv6 могут вести на разные серверы
example.com работает, www — нет DNS и SAN для обоих имён Это разные hostname
На телефоне ошибка есть, на ПК нет Сеть, IPv6, DNS Маршрут может отличаться
Сертификат принадлежит другому серверу IP назначения Запрос приходит не туда

После изменения DNS учитывайте TTL и кеш резолверов, но не списывайте любое несоответствие на «DNS ещё обновляется». dig, curl -4, curl -6 и проверка конкретного IP позволяют увидеть состояние маршрутов прямо сейчас.

Почему после переноса сайта или смены сервера продолжает открываться старый SSL-сертификат

После миграции типичный симптом выглядит так: новый VPS уже обслуживает сайт, сертификат на нём свежий, но периодически браузер показывает прежний сертификат. В этой ситуации почти всегда нужно искать второй узел, который всё ещё участвует в обработке запросов.

Им может оказаться старый IP в DNS, забытая AAAA-запись, CDN, балансировщик, второй backend или сам новый сервер, который не перечитал обновлённый сертификат.

Проверяйте серверы в обход DNS

Одна из самых полезных команд при миграции — curl --resolve:

curl --resolve example.com:443:203.0.113.10 https://example.com/ -Iv

Она заставляет curl подключиться к указанному IP, но сохраняет hostname example.com для HTTPS и SNI. Так можно проверить конкретный сервер, не меняя публичный DNS и локальный hosts.

Например, отдельно проверьте старый и новый адрес:

curl --resolve example.com:443:198.51.100.20 https://example.com/ -Iv
curl --resolve example.com:443:203.0.113.10 https://example.com/ -Iv

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

После обновления файлов проверьте reload

Для Nginx:

nginx -t
systemctl reload nginx

Для Apache:

apachectl configtest
systemctl reload apache2

Имя сервиса Apache зависит от дистрибутива: встречаются apache2 и httpd. Не копируйте команду перезапуска вслепую — сначала посмотрите фактическое имя службы.

После reload повторите внешний openssl s_client. Если serial и даты изменились, новый сертификат действительно вышел в сеть. Именно этот тест отделяет «файл заменили» от «пользователи уже получают новый сертификат».

Почему SSL ломается при использовании Cloudflare, CDN или reverse proxy

В браузере сертификат может быть совершенно нормальным, а Cloudflare при этом не устанавливает HTTPS до VPS. В такой ситуации смотреть только сертификат в Chrome почти бесполезно: браузер и origin участвуют в двух разных TLS-соединениях.

Браузер
   |
   | HTTPS
   v
Cloudflare / CDN
   |
   | HTTPS или HTTP — зависит от режима
   v
Origin VPS

Публичный сертификат относится к участку браузер → CDN. Сертификат на VPS — к участку CDN → origin. Ошибка на одном участке не доказывает проблему на другом.

Flexible, Full и Full (strict): где именно проверяется сертификат

Режим Браузер → Cloudflare Cloudflare → Origin Что происходит с сертификатом origin
Flexible HTTPS HTTP Для соединения с origin SSL-сертификат не используется
Full HTTPS HTTPS TLS используется, но строгая проверка валидности origin-сертификата не выполняется
Full (strict) HTTPS HTTPS Origin должен предъявить подходящий, непросроченный и доверенный для этого режима сертификат

Flexible иногда маскирует отсутствие рабочего HTTPS на VPS: посетитель видит HTTPS до Cloudflare, но Cloudflare идёт к сайту по HTTP. Это также может приводить к циклам редиректов, если приложение на origin постоянно пытается вернуть клиента на HTTPS.

Full уже требует TLS на origin, но сам факт установления HTTPS ещё не означает строгую проверку сертификата. В Full (strict) проблемы с именем, сроком или доверием origin-сертификата становятся критичными.

Что означают Cloudflare 525 и 526

Коды 525 и 526 относятся именно к Cloudflare и помогают разделить два типа проблем.

  • 525 SSL handshake failed — Cloudflare не смог завершить TLS-handshake с origin. Проверяйте порт 443, TLS-конфигурацию, SNI, поддерживаемые параметры соединения и состояние веб-сервера.
  • 526 Invalid SSL certificate — Cloudflare дошёл до проверки origin-сертификата, но не смог принять его как валидный в строгом режиме. Проверяйте срок, hostname, chain и тип сертификата.

Код 525 не означает автоматически «сертификат просрочен», а 526 не означает, что нужно менять edge-сертификат Cloudflare. Ошибка находится на участке CDN → origin.

Проверьте origin напрямую

Публичное соединение:

curl -Iv https://example.com/

Теперь тот же hostname непосредственно на IP origin:

curl --resolve example.com:443:203.0.113.10 https://example.com/ -Iv

Если через Cloudflare сайт работает, а прямой запрос к origin падает на TLS, edge можно временно вычеркнуть из списка подозреваемых. Если origin напрямую работает, а Cloudflare получает 525 или 526, сравнивайте требования режима Cloudflare с реальной TLS-конфигурацией VPS.

Отдельно смотрите hostname. Origin может отдавать валидный сертификат, но для другого домена. Без правильного SNI такая конфигурация легко проходит незамеченной при тесте только по IP.

Reverse proxy тоже может сломать TLS на внутреннем участке

Ещё один вариант — внешний Nginx принимает HTTPS нормально, но к backend обращается не тем протоколом. Например, upstream слушает обычный HTTP, а proxy пытается установить с ним HTTPS. Или наоборот.

Смысл такой конфигурации:

proxy_pass http://backend:8080;

и такой:

proxy_pass https://backend:8443;

совершенно разный. Если backend не поддерживает тот протокол, который указан в proxy, клиентская SSL-ошибка может быть лишь верхушкой проблемы. Сначала определите, на каком именно участке не собирается соединение.

Почему ERR_SSL_PROTOCOL_ERROR не всегда означает проблему сертификата

ERR_SSL_PROTOCOL_ERROR может появиться ещё до того, как браузер получил сертификат и начал проверять его срок или имя. Если TLS-handshake до peer certificate вообще не дошёл, перевыпуск SSL пока не следующий шаг.

Проверьте, есть ли слушающий процесс на 443

ss -lntp | grep ':443'

Если вывода нет, на сервере никто не слушает TCP/443. Если порт занят неожиданным процессом, сначала выясните, должен ли именно он обслуживать HTTPS.

Посмотрите, начинается ли TLS-handshake

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

При рабочем TLS OpenSSL показывает сертификат и параметры сессии. Если соединение ломается раньше, текст ошибки помогает определить следующий тест, хотя сам по себе не всегда даёт стопроцентный диагноз.

Как читать типовые ошибки openssl s_client

Вывод или симптом Что подозревать Следующая проверка
wrong version number На ожидаемом TLS-участке может отвечать plain HTTP или proxy/backend использует неправильный протокол Проверить listener и схему proxy
Connection refused Порт не слушается либо соединение отклоняется до приложения ss -lntp, firewall, состояние сервиса
no peer certificate available Handshake завершился до получения сертификата Логи веб-сервера и TLS-конфигурация
handshake failure Общая ошибка согласования TLS, SNI или серверной конфигурации Повторить тест с SNI, проверить логи и настройки TLS
unexpected eof Удалённая сторона оборвала соединение раньше ожидаемого Проверить proxy, backend и журнал сервиса

wrong version number особенно полезен как подсказка, когда HTTPS случайно направили на обычный HTTP-порт. Похожая проблема возникает, если reverse proxy пытается говорить с upstream по HTTPS, хотя backend принимает только HTTP.

Проверьте конфигурацию и журнал

Для Nginx:

nginx -t
systemctl status nginx
journalctl -u nginx --since "15 minutes ago"

Для Apache:

apachectl configtest
systemctl status apache2
journalctl -u apache2 --since "15 minutes ago"

Формулировки зависят от версии и дистрибутива, но в журнале можно встретить сообщения о невозможности загрузить сертификат, ошибке чтения файла, несовпадающем ключе или занятом порту. Например:

cannot load certificate
BIO_new_file() failed
key values mismatch
bind() to 0.0.0.0:443 failed

Это не шаблон, который обязан появиться именно в таком виде. Смотрите сообщения рядом с моментом старта или reload сервиса и путь к файлу, на который указывает ошибка.

Если OpenSSL получает peer certificate и handshake завершается, а браузер продолжает показывать ERR_SSL_PROTOCOL_ERROR, проверьте промежуточные proxy, другую сеть и клиентское устройство. Если s_client тоже не устанавливает TLS, проблема уже воспроизводится вне браузера.

Какие ошибки конфигурации Nginx и Apache чаще всего ломают HTTPS

Когда DNS указывает на правильный сервер, а сертификат на диске существует, следующий уровень — конфигурация веб-сервера. Здесь чаще всего встречаются неверные пути, неправильный fullchain, несовпадающий приватный ключ и сертификат либо неуспешный reload.

Nginx: сначала configtest, потом reload

nginx -t

Успешный результат выглядит примерно так:

syntax is ok
test is successful

Только после успешной проверки:

systemctl reload nginx

Если nginx -t возвращает ошибку, reload делать бессмысленно. Исправьте строку, которую указывает Nginx, затем повторите тест.

Для анализа активной конфигурации:

nginx -T

Команда помогает увидеть случаи, когда нужный server_name описан дважды или сертификат подключается из другого файла, чем ожидалось.

Apache: проверьте конфигурацию и VirtualHost

apachectl configtest
apachectl -S

Первая команда проверяет конфигурацию, вторая показывает структуру виртуальных хостов. Если нужный домен привязан не к тому VirtualHost *:443, браузер может получить сертификат другого сайта.

Как проверить, что приватный ключ относится к этому сертификату

Проблема особенно вероятна после ручного копирования файлов между серверами. Для RSA раньше часто сравнивали modulus, но универсальнее сравнить публичные ключи.

Для сертификата:

openssl x509 -in cert.pem -pubkey -noout | \
openssl pkey -pubin -outform PEM | sha256sum

Для приватного ключа:

openssl pkey -in privkey.pem -pubout -outform PEM | sha256sum

Хеши должны совпасть. Если они разные, этот приватный ключ не соответствует сертификату.

Не выводите содержимое приватного ключа в тикет, чат или публичный лог. Для диагностики достаточно проверки соответствия и прав доступа к файлу. Команды с приватным ключом выполняйте только на доверенном сервере.

Почему файл обновился, а сайт продолжает отдавать старый сертификат

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

  1. проверить новые файлы;
  2. выполнить configtest;
  3. сделать reload;
  4. проверить внешний порт 443 через OpenSSL.

Последний пункт и подтверждает, что изменение дошло до клиента.

Почему ошибка SSL видна только на одном компьютере или только в одном браузере

Если сайт нормально открывается на нескольких независимых устройствах, а предупреждение стабильно появляется на одном ноутбуке, сервер всё равно стоит проверить извне, но основная ветка поиска уже смещается к клиенту и его сети.

Проверка Если ошибка остаётся Что это подсказывает
Другой браузер на том же ПК Да Вероятнее системная или сетевая причина
Другой ПК в том же Wi-Fi Да Проверить сеть, DNS, proxy
Телефон в том же Wi-Fi Да Проблема может быть общей для сети
Телефон через мобильную сеть Нет Проверять домашнюю/офисную сеть и DNS
Несколько независимых устройств и сетей Да Вероятнее сервер, DNS или CDN

Сравните не только ошибку, но и сам сертификат

На рабочем и проблемном устройстве откройте сведения о сертификате и сравните issuer, serial и срок действия. Если serial различается, устройства фактически получают разные сертификаты. Это уже не «особенность браузера» — нужно искать различие в DNS, IPv4/IPv6, proxy или HTTPS inspection.

Если serial одинаковый, но только один клиент считает сертификат недоверенным, проверяйте локальный trust store, системное время и ПО, которое вмешивается в HTTPS.

Сначала проверьте системное время

Неверные дата, время и часовой пояс способны превратить нормальный сертификат в «просроченный» или «ещё не действующий». Это одна из немногих локальных причин, которую можно исключить за минуту.

Антивирус и корпоративный proxy могут подменять сертификат

Некоторые средства HTTPS inspection расшифровывают соединение локально и выпускают для посещаемого сайта собственный сертификат. Браузер должен доверять локальному корневому CA такого продукта. Если доверие сломалось, пользователь увидит ошибку, хотя публичный сертификат сайта полностью исправен.

Посмотрите issuer на проблемном компьютере. Если вместо ожидаемого публичного CA там указано название антивирусного продукта, корпоративного шлюза или внутреннего центра сертификации, направление поиска меняется сразу: соединение перехватывается между браузером и сайтом.

Старое устройство может не доверять нормальной цепочке

На давно не обновлявшейся ОС или в старом браузере хранилище корневых сертификатов может отличаться от современного. В такой ситуации актуальные устройства открывают сайт нормально, а старое получает UNKNOWN_ISSUER или похожую ошибку.

Сначала убедитесь, что сервер действительно отдаёт полный chain. Если с серверной стороны всё корректно и проблема воспроизводится только на устаревшем клиенте, бесконечно перестраивать fullchain под одно устройство не стоит — проверяйте обновления ОС, браузера и доверенных CA.

DNS, IPv6 и HSTS — разные ветки

Два устройства в одной сети не обязательно идут к сайту одинаковым маршрутом. Одно использует IPv6, другое — IPv4; одно получает корпоративный DNS, другое — публичный. Здесь полезны curl -4 и curl -6, если они доступны на проблемной системе.

HSTS тоже способен влиять на поведение браузера, например принудительно отправлять запрос на HTTPS, но HSTS сам по себе не делает валидный сертификат недействительным. Не смешивайте проблему принудительного HTTPS с ошибкой доверия, имени или срока сертификата.

После сравнения устройства, сети и самого сертификата обычно остаётся одна ветка. Вот её и нужно исправлять.

Как за 10 минут определить, где именно возникает ошибка SSL

Большинство типовых SSL-проблем можно локализовать короткой последовательностью проверок. Задача не в том, чтобы выполнить все команды подряд, а в том, чтобы найти первое место, где реальный результат отличается от ожидаемого.

  1. Запишите точный код браузера. DATE_INVALID, COMMON_NAME_INVALID, AUTHORITY_INVALID и PROTOCOL_ERROR ведут в разные ветки диагностики.
  2. Откройте сертификат в браузере. Сверьте имя, issuer, serial и даты действия.
  3. Проверьте SAN. Убедитесь, что в сертификате есть именно тот hostname, который открыт в адресной строке.
  4. Получите сертификат через OpenSSL. Так вы увидите то, что сервер реально отдаёт через 443.
  5. Проверьте цепочку. Используйте -showcerts, посмотрите Certificate chain и результат verify.
  6. Проверьте A и AAAA. Все адреса должны вести в актуальную инфраструктуру.
  7. При странной разнице между клиентами сравните IPv4 и IPv6. Используйте curl -4 и curl -6.
  8. Если серверов несколько, используйте curl --resolve. Это отделяет DNS от состояния конкретного узла.
  9. При наличии CDN разделите edge и origin. Для Cloudflare учитывайте режим Flexible, Full или Full (strict).
  10. Проверьте SNI и virtual host. Особенно если сервер показывает сертификат соседнего домена.
  11. Если TLS не стартует, проверьте порт 443 и логи. До сертификата handshake может вообще не дойти.
  12. Запустите configtest Nginx или Apache. После исправления выполните reload.
  13. Повторите проверку извне. Не закрывайте задачу только потому, что сайт открылся в одном браузере.

Минимальный набор команд

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

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

curl -Iv https://example.com/

curl -4 -Iv https://example.com/
curl -6 -Iv https://example.com/

dig example.com A
dig example.com AAAA

curl --resolve example.com:443:203.0.113.10 \
  https://example.com/ -Iv

ss -lntp | grep ':443'

nginx -t

apachectl configtest

Как читать результаты как одну цепочку

Браузер показывает старый сертификат. dig A уже возвращает новый IP, но dig AAAA показывает старый IPv6. Причина найдена на уровне DNS. В Nginx нового VPS пока копать нечего.

Другой вариант: DNS полностью правильный, но OpenSSL с -servername получает сертификат соседнего домена. Поиск смещается к SNI и virtual host.

Третий сценарий: сервер отдаёт правильный leaf, но openssl s_client -showcerts не показывает нужный intermediate. Исправляйте fullchain.

И ещё один вариант: OpenSSL вообще не получает peer certificate. Значит, проблема находится раньше — порт 443, TLS-listener, reverse proxy или конфигурация веб-сервера. Перевыпуск сертификата здесь пока ничего не решает.

Правило диагностики: не меняйте пять настроек сразу. После каждого теста должна отпасть хотя бы одна гипотеза или появиться конкретный следующий уровень проверки.

Когда сертификат уже исправлен, но нужно проверить HTTPS целиком

Исчезновение предупреждения в одном Chrome ещё не означает, что HTTPS полностью исправлен. У сайта могут отдельно обслуживаться example.com, www.example.com, IPv4, IPv6, поддомены и CDN. Каждый маршрут способен привести к другой TLS-конфигурации.

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

  • https://example.com/;
  • https://www.example.com/;
  • рабочие поддомены;
  • IPv4 и IPv6, если опубликована AAAA-запись;
  • origin напрямую, если перед сайтом стоит CDN;
  • редирект с HTTP на HTTPS.

Редиректы удобно проверить через:

curl -I http://example.com/
curl -I https://example.com/

Первый запрос в типовой конфигурации должен перенаправить посетителя на HTTPS, второй — вернуть нормальный HTTP-ответ уже через TLS. Сам по себе 200, 301 или 302 ещё ничего не доказывает: смотрите, куда ведёт Location и нет ли цикла.

Затем повторите проверку сертификата:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates -serial

Для сайта с IPv6 полезно отдельно выполнить:

curl -4 -Iv https://example.com/
curl -6 -Iv https://example.com/

Если используется CDN, проверьте публичный edge и origin раздельно. Для Cloudflare в строгом режиме убедитесь, что origin-сертификат соответствует hostname, не просрочен и собирает корректную цепочку.

Контрольная точка Что должно совпасть
example.com Правильный сертификат, SAN и срок
www.example.com Имя присутствует в сертификате или корректно редиректится
IPv4 Актуальный сервер или CDN
IPv6 Актуальный сервер и тот же рабочий HTTPS
CDN edge Действующий публичный сертификат
Origin Рабочий TLS согласно режиму CDN
Certificate chain Передаются нужные intermediate-сертификаты
HTTP → HTTPS Нет цикла и переход ведёт на правильный hostname

Закрывать такую задачу лучше после внешней контрольной проверки, а не после сообщения «у меня уже открылось». Если браузер, OpenSSL и curl независимо получают ожидаемый сертификат, DNS ведёт на актуальные узлы, IPv4 и IPv6 не расходятся, цепочка доверия собирается, а остальные hostname не выпадают из HTTPS, проблему можно считать действительно устранённой.

Вопросы и ответы
Новый файл мог появиться на сервере, но Nginx или Apache не перечитал конфигурацию. Также запрос может идти на старый IP, IPv6-адрес или CDN. Сравните сертификат на 443 через OpenSSL.
Чаще всего AAAA-запись ведёт на другой сервер или HTTPS на IPv6 настроен иначе. Сравните результаты curl -4 -Iv и curl -6 -Iv для того же домена.
Cloudflare отдельно устанавливает TLS-соединение с origin. При ошибках 525 или 526 проверяйте порт 443, SNI, срок, hostname и цепочку сертификата на VPS.
Hostname в адресной строке не совпадает с именами SAN сертификата либо сервер отдаёт сертификат другого virtual host. Проверьте SAN, DNS и SNI.
Причина может быть в системном времени, локальном trust store, антивирусном HTTPS inspection, proxy, DNS или различии IPv4/IPv6. Сравните issuer и serial сертификата на двух устройствах.
Используйте openssl s_client -connect example.com:443 -servername example.com. Для сравнения со сертификатом на диске можно проверить subject, serial, даты или SHA-256 fingerprint.
Да. Если A, AAAA или www ведут на старый либо чужой сервер, браузер получит сертификат именно этого узла. Проверяйте DNS и конкретные IP отдельно.
Рекомендуемые статьи