nginx: SSL_do_handshake() failed и ошибки TLS
Ошибки рукопожатия чаще всего означают несовместимость: клиент и сервер не договорились о версии протокола или наборе шифров. Отдельный частый случай — обращение обычным http к порту, на котором ждут TLS.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Клиент не поддерживает разрешённые версии протокола
После отключения устаревших версий старые клиенты и библиотеки не могут подключиться. В журнале — сообщение о неподдерживаемой версии.
-
Обращение по http к порту с TLS
Байты обычного запроса выглядят для TLS как мусор. Сообщение про «http request» в журнале nginx говорит именно об этом.
-
Нет общих наборов шифров
Жёсткий список шифров может не пересекаться с тем, что предлагает клиент.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Точная причина неудачного рукопожатия.
sudo tail -30 /var/log/nginx/error.log | grep -i sslЧто сервер предлагает и чем заканчивается рукопожатие.
echo | openssl s_client -connect localhost:443 -servername example.org 2>&1 | head -20Решение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- После отключения устаревших версий старые клиенты и библиотеки не могут подключиться. В журнале — сообщение о неподдерживаемой версии.
- Как проверить
-
Посмотрите разрешённые версии и ошибку.
sudo nginx -T 2>/dev/null | grep -E "ssl_protocols|ssl_ciphers" sudo tail -20 /var/log/nginx/error.log | grep -i ssl
- Как исправить
- Решите осознанно: либо клиент обновляется, либо вы временно разрешаете более старую версию. Возврат устаревших версий ослабляет защиту всех.
- Почему происходит
- Байты обычного запроса выглядят для TLS как мусор. Сообщение про «http request» в журнале nginx говорит именно об этом.
- Как проверить
-
Посмотрите точное сообщение.
sudo tail -20 /var/log/nginx/error.log | grep -i "http request"
- Как исправить
- Исправьте адрес на стороне клиента. Для удобства можно добавить обработку такого случая отдельным кодом ответа.
- Почему происходит
- Жёсткий список шифров может не пересекаться с тем, что предлагает клиент.
- Как проверить
-
Проверьте рукопожатие со стороны клиента.
echo | openssl s_client -connect localhost:443 -servername example.org 2>&1 | grep -E "Cipher|Protocol"
- Как исправить
- Расширьте список шифров до современного набора, не возвращая заведомо слабые.
Пример вывода
Клиент обратился по http к порту с TLS. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
2026/09/15 16:30:11 [info] 1121#1121: *90 SSL_do_handshake() failed (SSL: error:0A00010B:SSL routines::wrong version number) while SSL handshaking, client: <адрес>, server: 0.0.0.0:443
2026/09/15 16:31:02 [info] 1121#1121: *91 client sent plain HTTP request to HTTPS port while reading client request line
Связанные ошибки
- nginx: ошибки сертификата при запуске (SSL_CTX_use_PrivateKey) nginx не запускается из-за сертификата: не совпадает ключ, неполная цепочка, файл повреждён, нет прав на чтение ключа.
- certificate verify failed в журнале службы Проверка сертификата не прошла: истёк срок, неполная цепочка, неверное имя, нет доверенных корневых сертификатов.
- nginx: [emerg] host not found in upstream nginx не запускается: не разрешается имя узла из upstream или proxy_pass. Разбор порядка запуска и работы с именами.
- nginx: [emerg] open() failed при чтении конфигурации nginx не может открыть файл конфигурации, включённый через include, или файл сертификата. Разбор путей и прав.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- Automount: каталог монтируется не вовремя или отваливается Автомонтирование через .automount: как работает TimeoutIdleSec, почему ресурс отваливается и когда лучше обычный .mount.
- Broken pipe в журнале службы Запись в закрытый канал или соединение: клиент отключился, обработчик завершился, конвейер разорван.
- Cannot assign requested address при привязке Ошибка 99 при привязке: адрес не принадлежит машине или ещё не поднят. Разбор с network-online.target и ip_nonlocal_bind.
Где встречается чаще всего
Источники
- Документация nginx: настройка HTTPS
-
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено обращением curl по http к порту 443.