Код curl 35 означает сбой TLS-рукопожатия, а 60 — отказ при проверке сертификата сервера. В актуальном списке кодов curl отдельного 51 нет: старые инструкции с «51 = имя не совпало» нельзя механически применять к современной версии. Читайте полный текст ошибки и проверяйте сертификат, имя, цепочку и локальное хранилище доверия отдельно.

Слово «SSL» в сообщениях curl часто обозначает современный TLS. Одного номера недостаточно: одинаковый exit 60 может возникнуть из-за просроченного сертификата, неверного имени или недоверенной цепочки. А код 35 может быть вызван настройками клиента, сервера либо промежуточного прокси. Поэтому первым делом зафиксируйте версию curl и полный stderr. Официальный список exit codes и таблица libcurl позволяют сверить смысл для установленной версии.
Снимите воспроизводимый вывод
curl --version
curl -vI --connect-timeout 5 --max-time 20 https://example.com/ 2>&1 | tail -40
printf 'exit=%s\n' "${PIPESTATUS[0]}"
# Без конвейера: curl -sS -o /dev/null https://example.com/; echo "$?"
Команда с tail в bash требует PIPESTATUS[0], иначе вы получите exit-код tail. Снимайте вывод в контролируемой среде: verbose-лог может раскрывать URL и заголовки с секретами. Сравните запрос с проверкой через openssl s_client, чтобы видеть предъявленную цепочку и SNI.

Разделите сбой рукопожатия и проверки сертификата
| Код | Этап | Первая проверка | Типичные причины |
|---|---|---|---|
| 35 | TLS-рукопожатие | Версия TLS, SNI, прокси и подробный stderr | Несовместимые протоколы или шифры, разрыв соединения |
| 60 | Проверка сертификата | Имя, срок, цепочка и CA-хранилище | Истёкший срок, чужое имя, недоверенный издатель |
| 51 | Историческая нумерация | Версия curl и её документация | В текущем официальном перечне отдельного 51 нет |
В нашем контролируемом прогоне curl 8.12.1 с OpenSSL 3.5.8 адрес expired.badssl.com вернул 60 с сообщением certificate has expired, а wrong.host.badssl.com — тоже 60, но о несовпадении имени. Принудительное ограничение клиента до TLS 1.0 при запросе enterno.io дало 35 и локальное no protocols available. Последний опыт доказывает лишь несовместимость настроек в этой локальной сборке: нельзя по нему заявить, что сервер отклонил TLS 1.0.
Если проверка имени не проходит, посмотрите SAN сертификата и имя URL; IP-адрес и доменное имя не взаимозаменяемы. Если не строится цепочка, сравните сертификаты сервера с доверенными CA клиента. Практические варианты настройки описаны в руководстве curl по сертификатам. Для проверки сайта снаружи используйте SSL-проверку, но ошибку конкретного контейнера воспроизводите внутри него: там могут отличаться доверенные CA и версия библиотеки.
Исправляйте причину, а не отключайте проверку
Для 60 обновите истёкший сертификат, исправьте SAN/URL, добавьте недостающий intermediate на сервере либо установите доверенный корневой сертификат в клиентскую среду. Для внутреннего CA используйте --cacert /path/to/ca.pem или системное хранилище по правилам вашей платформы. -k/--insecure может помочь доказать, что проблема именно в проверке доверия, но оставлять его в рабочем скрипте нельзя: клиент перестаёт удостоверять сервер.
Для 35 сначала проверьте, не запретили ли вы сами нужную версию TLS флагами; затем сравните рукопожатие с openssl s_client -connect host:443 -servername host, конфигурацию прокси и журнал TLS-терминатора. Не меняйте набор шифров на сервере по одному коду без сообщений с обеих сторон. Если сбой затрагивает только один маршрут, сравните DNS-адрес и маршрут через прокси с диагностикой DNS. Полное время этапов удобно измерить по формату curl -w.
Как сделан материал
Смысл кодов сверен с актуальными страницами curl. Три отрицательных и один успешный запрос выполнены из одной среды; версия, команды, stderr и exit-коды сохранены в data.json рядом с черновиком. Тестовые адреса взяты с BadSSL. Это проверка поведения указанной сборки, а не измерение распространённости ошибок на сайтах. Поиск SerpAPI и Wordstat использован для выбора формулировок, значения спроса в выводы о TLS не переносились.
Частые вопросы
Почему обе ошибки сертификата дали 60?
Современная сборка curl объединяет несколько причин отказа в проверке сертификата под этим кодом. Различие показывает текст ошибки.
Что делать с инструкцией про код 51?
Сверьте её с версией установленного curl. В текущей официальной таблице отдельного 51 нет; опирайтесь на фактический exit и stderr.
Можно ли использовать -k для постоянного мониторинга?
Нет. Он скрывает ошибки доверия и имени, из-за которых мониторинг должен подавать сигнал.
Код 35 всегда означает неисправность сервера?
Нет. Сбой может быть вызван локальной политикой TLS клиента или промежуточным узлом. Смотрите обе стороны рукопожатия.