Коротко. В 8 случаях из 10 ошибка SSL на сервере — это не просроченный или поддельный сертификат, а неполная цепочка доверия: на сервер загружен только сертификат домена без промежуточного (intermediate) сертификата. Из-за этого сайт нормально открывается в Chrome на десктопе, но выдаёт ошибку на части мобильных устройств, в почтовых клиентах и у ботов вроде проверки соцсетей. Диагностика через openssl s_client занимает 2 минуты, исправление в конфиге nginx — ещё 10-15, если под рукой правильный файл цепочки.
Какие ошибки бывают и что они означают на самом деле
Браузер сообщает об одной из нескольких разных проблем, и текст ошибки — первая подсказка, куда копать. NET::ERR_CERT_AUTHORITY_INVALID означает, что браузер не смог выстроить цепочку доверия до известного корневого центра — чаще всего из-за отсутствия промежуточного сертификата на сервере, реже — из-за самоподписанного сертификата на проде. NET::ERR_CERT_DATE_INVALID — сертификат просрочен либо (это частый и неочевидный вариант) на сервере сбито системное время, из-за чего проверка срока действия ломается даже на свежем сертификате. NET::ERR_CERT_COMMON_NAME_INVALID — сертификат выпущен на другой домен или не включает нужный поддомен (например, есть сертификат на example.ru, а сайт открывают по www.example.ru). ERR_SSL_PROTOCOL_ERROR обычно говорит не о самом сертификате, а о конфигурации сервера: порт 443 не слушает TLS-трафик или сертификат вообще не привязан к домену в конфиге.
Как устроена цепочка доверия
Браузер по умолчанию доверяет не сертификату сайта напрямую, а ограниченному списку корневых центров (root CA), встроенному в операционную систему или сам браузер. Сертификат сайта (leaf-сертификат) подписан не корневым центром напрямую, а промежуточным (intermediate CA) — это отдельный файл-звено, который связывает сертификат сайта с доверенным корнем. Когда сервер отдаёт браузеру только leaf-сертификат без промежуточного звена, часть браузеров достраивает цепочку сама через механизм AIA (Authority Information Access) и подгружает нужный файл из сети — это и объясняет, почему сайт «работает у одних и не работает у других»: Chrome на десктопе умеет так делать, старые версии Android, части почтовых клиентов и большинство серверных проверяющих скриптов — нет.
Как продиагностировать проблему за 2 минуты
Не нужно ничего устанавливать локально — команда работает в терминале на macOS/Linux и в WSL на Windows:
openssl s_client -connect example.ru:443 -servername example.ru -showcerts
В выводе важны две вещи. Первая — секция Certificate chain вверху: если там всего одна запись с индексом 0, значит промежуточный сертификат на сервер не загружен. Вторая — строка в самом низу вывода: Verify return code: 0 (ok) означает, что цепочка выстраивается корректно, любой другой код (например, 21 — unable to verify the first certificate) прямо указывает на проблему с цепочкой. Дополнительно быстро проверить редирект и заголовки помогает curl -vI https://example.ru — в выводе видно, отвечает ли сервер вообще на 443 порту и какой сертификат он предъявляет. Если нужен визуальный отчёт с оценкой конфигурации — подходит любой публичный SSL-чекер, который раскладывает цепочку по полочкам и явно помечает отсутствие intermediate-сертификата.
Самая частая причина: неполная цепочка в конфиге nginx
Директива ssl_certificate в nginx должна указывать не на файл с одним сертификатом домена, а на объединённый файл — сертификат домена плюс промежуточный сертификат подряд, в правильном порядке. У Let’s Encrypt такой файл называется fullchain.pem и создаётся автоматически, у платных сертификатов от других центров его часто приходится собирать вручную: скачать отдельно сертификат домена и intermediate-файл, который присылает центр сертификации, и склеить их в одном файле через cat domain.crt intermediate.crt > fullchain.pem. Рабочий пример конфигурации:
server {
listen 443 ssl;
server_name example.ru www.example.ru;
ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
}
Частая ошибка на этом шаге — указать путь к cert.pem вместо fullchain.pem: оба файла существуют в одной папке у Let’s Encrypt, разница только в том, что первый содержит только сертификат сайта, а второй — сертификат вместе с цепочкой. После правки конфига обязательны две команды: nginx -t проверяет синтаксис до применения, systemctl reload nginx подхватывает изменения без разрыва активных соединений (в отличие от restart).
Другие частые причины ошибки
Если цепочка выстраивается верно, а ошибка остаётся, стоит проверить по порядку: соответствие домена в сертификате (поле Common Name или SAN) фактическому адресу сайта — сертификат на example.ru не покрывает www.example.ru и любые другие поддомены, если явно не указан wildcard или отдельный SAN-пункт; системное время на сервере — команда timedatectl в Linux покажет расхождение, из-за которого валидный сертификат может выглядеть ещё не начавшим или уже закончившим действие; и не остался ли на 443 порту старый самоподписанный сертификат, который сервер отдаёт по умолчанию (default_server) вместо только что установленного — такое бывает, если новый серверный блок в nginx не помечен как основной для домена.
Когда чинить самому, а когда звать специалиста
Если ошибка сводится к неполной цепочке и есть доступ по SSH — это правки на 15-30 минут, которые не требуют глубоких знаний, достаточно аккуратно скопировать правильный путь к файлу и не забыть про nginx -t перед reload. Стоит звать администратора, если сервер обслуживает несколько сайтов с разными сертификатами через один и тот же IP (SNI-конфигурация с несколькими серверными блоками), если ошибка проявляется нестабильно (то есть, то нет — часто означает балансировщик нагрузки или CDN перед сервером с рассинхронизированными сертификатами на разных узлах), или если после правки конфигурация не проходит проверку nginx -t с непонятной ошибкой синтаксиса. В таких случаях быстрее и надёжнее отдать диагностику в техническую поддержку, чем разбираться методом проб на боевом сервере.
FAQ
Почему сайт открывается в Chrome, но не открывается в Safari или на телефоне?
Почти всегда это неполная цепочка сертификатов. Chrome на десктопе умеет самостоятельно достраивать цепочку через AIA-запрос, часть мобильных браузеров и приложений — нет, и показывает ошибку прямо. Решение — добавить на сервер промежуточный сертификат.
Сертификат обновили, а ошибка та же — в чём дело?
Чаще всего конфигурация сервера не перечитана: после замены файлов сертификата нужен nginx -t и systemctl reload nginx (или аналог для Apache), иначе веб-сервер продолжает отдавать старые данные из памяти. Второй частый вариант — браузер показывает закешированную версию страницы, стоит проверить в режиме инкогнито.
Как проверить сертификат, не заходя на сервер по SSH?
Команда openssl s_client -connect домен:443 -servername домен -showcerts работает с любого компьютера с доступом в интернет и не требует прав на сервере — она просто подключается к сайту так же, как это делает браузер, и показывает всю цепочку сертификатов, которую отдаёт сервер.
Что делать, если на сервере сбилось системное время?
Проверить командой timedatectl (Linux) и синхронизировать через NTP — обычно достаточно timedatectl set-ntp true или перезапуска службы ntp/chrony. Расхождение даже в несколько часов может сделать валидный сертификат «просроченным» или «ещё не начавшим действие» с точки зрения проверки браузера.
Можно ли исправить ошибку цепочки без простоя сайта?
Да. Правка файла сертификата и reload (не restart) nginx не разрывает уже установленные соединения и не создаёт заметного простоя — конфигурация подхватывается «на лету» для новых подключений.
Если ошибка SSL не поддаётся самостоятельной диагностике
Бесплатный аудит покажет, что именно не так с сертификатом на сервере и как это чинится в вашем конкретном случае.