ERR_SSL_PROTOCOL_ERROR: причины и решение
Что такое ERR_SSL_PROTOCOL_ERROR и что он значит
ERR_SSL_PROTOCOL_ERROR — ошибка, которую показывает браузер, когда не удаётся установить защищённое соединение по HTTPS. На русском она звучит примерно как «не удалось установить защищённое соединение», а в тексте самой страницы часто встречается фраза «сайт недоступен по https». Технически это означает: браузер и сервер начали TLS-рукопожатие, но не смогли договориться о параметрах шифрования или сервер ответил чем-то, что не является корректным TLS.
Важно понимать разницу между этой ошибкой и другими SSL-проблемами. Если сертификат истёк или подписан не для этого домена, браузер обычно показывает «срок действия сертификата истёк» или «не удалось проверить сертификат» — то есть рукопожатие состоялось, но сертификат не прошёл проверку. ERR_SSL_PROTOCOL_ERROR появляется раньше — на этапе самого рукопожатия, до проверки сертификата. Поэтому причины у неё другие.
Самые частые причины:
- На порту 443 слушает сервис, который не понимает TLS (обычный HTTP, SSH, почтовый сервер).
- Сайт вообще не слушает порт 443, а клиент принудительно заходит по HTTPS.
- Старая версия протокола (SSL 3.0, TLS 1.0), которую современные браузеры отключили.
- Расхождение между клиентом и сервером по cipher suites или версии TLS.
- Неправильная конфигурация виртуального хоста, когда под одним IP несколько доменов.
- Вмешательство антивируса, прокси или устаревший кеш браузера.
Разберём каждую причину, но сначала — как точно диагностировать, что происходит на вашей стороне.
Диагностика через openssl s_client
Главный инструмент диагностики — openssl s_client. Он вручную выполняет TLS-рукопожатие и показывает, на каком этапе всё ломается. Базовая команда:
openssl s_client -connect example.com:443
Разберём ключевые строки вывода при успешном соединении:
CONNECTED(00000003)
---
Certificate chain
0 s:CN = example.com
---
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
...
---
Verify return code: 0 (ok)
CONNECTED(00000003)— TCP-соединение с портом 443 установлено, сервер доступен.Protocol : TLSv1.3— согласованная версия протокола.Verify return code: 0 (ok)— сертификат прошёл проверку.
Если на каком-то из этапов проблема, вывод будет другим. Например, когда на порту 443 слушает не HTTPS, а что-то другое:
openssl s_client -connect example.com:443
CONNECTED(00000003)
write:errno=104
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 305 bytes
Здесь ключевая строка — SSL handshake has read 0 bytes and written 305 bytes. Клиент отправил данные рукопожатия, но сервер не ответил ни байта. Это классический признак того, что за портом 443 стоит не TLS-сервер, а что-то другое — обычный HTTP, SSH или вообще пустой порт. Ещё один характерный маркер — no peer certificate available: сервер не прислал сертификат, потому что до этого этапа рукопожатие не дошло.
Проверить, что именно отвечает на порту, можно, отправив обычный HTTP-запрос прямо в порт 443:
curl -k https://example.com -v
Если вместо TLS-ответа прилетает HTML или заголовок вроде Server: nginx без шифрования, а в логе curl видно error:1408F10B:SSL routines:ssl3_get_record:wrong version number, значит порт отдаёт не тот протокол.
Причина 1. На порту 443 не TLS-сервер
Самая распространённая причина ошибки ERR_SSL_PROTOCOL_ERROR. Симптомы и решения удобно свести в таблицу.
| Симптом в openssl | Что происходит на сервере | Решение |
|---|---|---|
SSL handshake has read 0 bytes |
На 443 слушает не TLS (HTTP, SSH, другой сервис) | Настроить HTTPS на нужном порту |
wrong version number |
Сервер отвечает на TLS-запрос обычным HTTP-текстом | Включить SSL-модуль/директиву listen 443 ssl |
no peer certificate available |
Рукопожатие оборвалось до отправки сертификата | Проверить, что за портом именно веб-сервер с TLS |
| Соединение висит и падает по таймауту | Порт 443 закрыт фаерволом, сервер молчит | Открыть порт, проверить listen в конфиге |
Самый частый сценарий — администратор настроил сайт только на HTTP (порт 80), а браузер или расширение принудительно подставляют HTTPS. В nginx это выглядит как отсутствие блока с listen 443 ssl:
server {
listen 80;
server_name example.com;
# нет listen 443 ssl — HTTPS не работает вовсе
}
Проверить, какие порты слушает nginx, можно так:
ss -tlnp | grep -E ':(80|443)'
Вывод покажет, слушается ли порт 443 и каким процессом. Если его нет — нужно добавить SSL-блок с корректным сертификатом и перезагрузить сервер.
Причина 2. Устаревший протокол TLS
Браузеры последовательно отключают старые протоколы. SSL 2.0 и SSL 3.0 давно выведены из эксплуатации, TLS 1.0 и 1.1 тоже отключены в большинстве современных браузеров. Если сервер настроен только на эти версии, клиент получает ERR_SSL_PROTOCOL_ERROR при попытке соединения.
Проверить, какие версии TLS поддерживает ваш сервер, можно прямым запросом к каждой версии:
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
Если сервер поддерживает версию, рукопожатие пройдёт и в выводе появится Protocol : TLSv1.2 или TLSv1.3. Если версия отключена, команда завершится с ошибкой вида:
error:1425F102:SSL routines:ssl_choose_client_version:unsupported protocol
Строка unsupported protocol означает, что сервер не принял запрошенную версию. Настроить поддерживаемые версии в nginx можно директивой:
ssl_protocols TLSv1.2 TLSv1.3;
Оставлять TLS 1.0 и 1.1 включёнными не стоит — это не только источник ошибок, но и уязвимость. Современный минимум — TLS 1.2, а лучше только TLS 1.3, если аудитория позволяет.
Причина 3. Расхождение cipher suites
Ещё одна причина сбоя на этапе рукопожатия — несовпадение наборов шифров. Браузер предлагает список поддерживаемых cipher suites, сервер выбирает один из них. Если пересечение пустое, рукопожатие падает.
Проверить, какие шифры предлагает ваш сервер, можно так:
openssl s_client -connect example.com:443 -cipher 'DEFAULT' 2>/dev/null | grep -E 'Cipher|Protocol'
Вывод покажет, какой шифр в итоге согласован. Если сервер возвращает no cipher match или рукопожатие обрывается при принудительном запросе конкретного шифра — пересечение с клиентом пустое.
Частая ошибка настройки — указать в конфиге устаревший или слишком узкий список шифров. В nginx стоит использовать современный набор и не перегружать конфиг ручными списками без необходимости:
ssl_ciphers HIGH:!aNULL:!MD5;
Если вы не уверены в своём списке, лучше опереться на готовые рекомендации по современным шифрам, чем выдумывать собственный набор — слишком строгий список ровно так же ломает соединение, как и слишком старый.
Причина 4. SNI и несколько доменов на одном IP
Когда на одном IP-адресе размещено несколько HTTPS-сайтов, сервер определяет, какой сертификат отдавать, по полю SNI (Server Name Indication), которое клиент передаёт в начале рукопожатия. Если клиент не передаёт SNI или сервер не настроен на его обработку, сервер отдаёт «дефолтный» сертификат — и для сайта, чей домен не совпадает с этим сертификатом, рукопожатие может завершиться ошибкой.
Проверить, какой сертификат сервер отдаёт для конкретного домена, можно, явно указав имя через флаг -servername:
openssl s_client -connect example.com:443 -servername example.com
Разница между запросом с -servername и без него — ключ к диагностике. Если с -servername рукопожатие проходит и приходит правильный сертификат, а без — отдаётся чужой, значит конфигурация виртуальных хостов привязана к SNI корректно, но стоит проверить поведение для клиентов, которые SNI не передают (старые браузеры, некоторые API-клиенты).
Обратная ситуация: сервер вообще не настроен на работу с несколькими доменами и отдаёт один сертификат всем. Тогда для «лишнего» домена браузер покажет ошибку — либо про несовпадение имени, либо, в зависимости от конфигурации, про протокол. Лечится это корректной настройкой отдельных server-блоков в nginx с собственными server_name и сертификатами:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
Каждый домен должен иметь свой блок со своим сертификатом, а сервер должен уметь различать их по SNI.
Причина 5. Клиентские и промежуточные факторы
Иногда ошибка возникает не на сервере, а на пути между браузером и сервером. Это стоит исключить до того, как углубляться в серверную конфигурацию.
-
Устаревший кеш браузера. Браузер может помнить старую попытку соединения. Очистка кеша или проверка в режиме инкогнито помогает отличить эту причину от реальной.
-
Антивирус и системный прокси. Некоторые антивирусы перехватывают HTTPS-трафик для проверки и подставляют свой сертификат. Если рукопожатие ломается именно на машине пользователя, временное отключение защиты — быстрый способ проверить.
-
Системные часы. Если на клиенте сбито время, проверка сертификата даёт ошибку, которая иногда маскируется под проблемы протокола. Но чаще всего сбитые часы дают ошибку именно про сертификат, а не про протокол.
-
CDN или балансировщик. Если трафик идёт через CDN или балансировщик, рукопожатие может ломаться на их стороне. Стоит проверить, корректно ли там настроен сертификат и какой протокол они предлагают клиентам.
Отдельно стоит упомянуть ситуацию, когда сайт открывается у одних пользователей и не открывается у других. Это классический признак расхождения версий TLS или шифров: старые клиенты (например, встроенные браузеры старых устройств) не поддерживают современные протоколы. В таком случае помогает не понижение протокола до небезопасного, а объяснение пользователям необходимости обновить устройство или браузер.
Как проверить сайт снаружи
Серверная диагностика через openssl s_client показывает картину с самой машины. Но проблема может быть видна только снаружи — из-за фаервола, CDN или геораспределения. Поэтому после локальных проверок стоит посмотреть на сайт внешним инструментом.
Для быстрой проверки доступности по HTTPS и корректности TLS-настройки подходит проверка SSL-сертификата у UptimeChecker. Она выполняет запрос из внешней точки и показывает, что видит клиент снаружи: устанавливается ли соединение, действителен ли сертификат, корректна ли цепочка. Это удобно для того, чтобы отделить «проблема на сервере» от «проблема в сети конкретного пользователя».

Если внешняя проверка тоже показывает сбой, значит проблема точно на стороне сервера или инфраструктуры перед ним, и стоит вернуться к разделам о портах и протоколах.
Чек-лист решения ERR_SSL_PROTOCOL_ERROR
Соберём последовательность действий, которая покрывает большинство случаев:
- Определить, воспроизводится ли ошибка у всех или только у одного пользователя.
- Исключить клиентские факторы: инкогнито, очистка кеша, отключение антивируса, проверка системного времени.
- Проверить порт 443:
ss -tlnp | grep ':443'— слушается ли он. - Прогнать рукопожатие:
openssl s_client -connect example.com:443— на каком этапе обрыв. - Если
handshake has read 0 bytes— на порту не TLS, чинить конфигурацию веб-сервера. - Проверить версии протоколов:
openssl s_client -connect example.com:443 -tls1_2. - Проверить шифры: не слишком ли узкий список в конфиге.
- Проверить сайт снаружи через внешний инструмент проверки SSL.
- После исправления перезагрузить веб-сервер и перепроверить рукопожатие.

Отдельно отметим связь с соседней проблемой — истёкшим сертификатом. ERR_SSL_PROTOCOL_ERROR и «срок действия сертификата истёк» — разные ошибки на разных этапах, но их часто путают. Если браузер пишет именно про срок действия, а не про протокол, начните со статьи про истёкший SSL-сертификат — там разобраны первые действия именно для этого случая.
Итог
ERR_SSL_PROTOCOL_ERROR — ошибка этапа рукопожатия, и в большинстве случаев её причина находится на сервере: не тот протокол на порту 443, отключённый TLS или несовпадение шифров. Диагностика через openssl s_client почти всегда показывает точное место обрыва — нужно лишь уметь читать вывод.
Чтобы такие проблемы не заставали врасплох, стоит регулярно проверять сайт внешним инструментом: проверка SSL-сертификата покажет, что видит клиент снаружи, ещё до того, как ошибку заметят посетители. Если соединение внезапно сломалось, а раньше работало, проверьте и срок действия сертификата — его истечение тоже может проявляться похожими симптомами, хотя технически это другая ошибка.