Skip to content
← Все статьи

Неполная цепочка SSL-сертификата: как найти и исправить incomplete chain

Неполная цепочка SSL-сертификата: как найти и исправить incomplete chain

Incomplete certificate chain — это ситуация, когда сервер отдаёт только собственный листовой сертификат, без промежуточных (intermediate). Настольные браузеры часто умеют «дотягивать» цепочку из своего кеша, но мобильные клиенты, старые библиотеки, curl, Java-приложения и API документацию-клиенты этого не делают — и отваливаются с ошибкой «unable to get local issuer certificate». В статье разберём, как диагностировать проблему и правильно собрать fullchain.

Почему цепочка важна

Цепочка доверия — это иерархия сертификатов от вашего листового до корневого CA, которому доверяет клиент. Обычно она выглядит так:

Root CA (встроен в trust store клиента)
  └─ Intermediate CA 1
      └─ Intermediate CA 2 (опционально)
          └─ Leaf (ваш сертификат на example.com)

Клиент должен суметь дойти от вашего листового сертификата до какого-то корневого, которому он доверяет. Если сервер не отдаёт intermediate — клиент не может построить путь. Root CA в цепочке отправлять не обязательно (и не рекомендуется) — клиенты его и так знают.

Симптомы неполной цепочки

  • Chrome на десктопе работает, Safari на iPhone — нет.
  • curl падает с «unable to get local issuer certificate».
  • Java-приложение: PKIX path building failed.
  • Python requests: [SSL: CERTIFICATE_VERIFY_FAILED].
  • Telegram-бот не принимает webhook, хотя сертификат валиден.
  • SSL Labs выдаёт оценку B с пометкой «Chain issues: Incomplete».

Диагностика

Первая проверка:

openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null 2>/dev/null \
    | grep "^-\|^ *s:\|^ *i:"

Правильный вывод должен содержать минимум две записи s: (subject) и i: (issuer):

s:CN=example.com
i:C=US, O=Let's Encrypt, CN=R3
s:C=US, O=Let's Encrypt, CN=R3
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1

Если есть только один блок s:/i: — цепочка неполная. Также протестируйте через SSL Checker enterno.io или SSL Labs — они чётко скажут «chain issues».

Исправление: собрать fullchain.pem

Для Let's Encrypt всё уже готово — используйте fullchain.pem, он уже содержит leaf + intermediate:

# Правильно
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

# Неправильно (только leaf)
ssl_certificate /etc/letsencrypt/live/example.com/cert.pem;

Для коммерческих CA вы получаете архив с несколькими файлами: cert.crt (ваш), intermediate.crt, иногда root.crt. Объедините leaf и intermediate в правильном порядке:

cat cert.crt intermediate.crt > fullchain.crt
# Ваш leaf — первым, intermediate — вторым
# root НЕ добавляйте

Если intermediate несколько, порядок: leaf → intermediate ближе к leaf → intermediate выше → и т.д. Перепутали порядок — клиент всё равно получит ошибку.

Конфигурация в nginx и Apache

nginx:

ssl_certificate     /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;

Apache:

SSLCertificateFile      /etc/apache2/certs/cert.crt
SSLCertificateKeyFile   /etc/apache2/certs/privkey.key
SSLCertificateChainFile /etc/apache2/certs/intermediate.crt
# Или (Apache 2.4.8+) leaf+intermediate в одном файле:
SSLCertificateFile      /etc/apache2/certs/fullchain.pem

После изменений: nginx -t && systemctl reload nginx / apachectl configtest && systemctl reload apache2.

Где взять intermediate, если его потеряли

Все современные CA публикуют intermediate-сертификаты. Способы получить:

  1. Сайт CA: у Let's Encrypt — letsencrypt.org/certificates, у Sectigo, DigiCert — аналогичные страницы.
  2. AIA (Authority Information Access): внутри сертификата есть URL на intermediate. Достанем его:
    openssl x509 -in cert.crt -noout -text | grep "CA Issuers"
    # CA Issuers - URI:http://r3.i.lencr.org/
    curl http://r3.i.lencr.org/ | openssl x509 -inform DER -out intermediate.pem
  3. crt.sh: найдите свой сертификат на crt.sh, там будет ссылка на issuer.

Автоматизация и предотвращение

  • Используйте certbot/acme.sh — они всегда генерируют fullchain.pem.
  • В CI-пайплайне добавьте проверку: openssl verify -untrusted intermediate.pem leaf.pem.
  • После деплоя делайте smoke-тест через curl без -k с чистого Docker-образа (например, alpine:latest) — он не содержит локальных доверенных цепочек.
  • Настройте Enterno.io Monitors — он проверяет целостность цепочки при каждой проверке и предупреждает, если после renewal чейн развалился.

Связанные проблемы

Если исправили цепочку, но ошибки остались, посмотрите:

  • Handshake failed — возможно, проблема в TLS cipher suites 2026 или SNI.
  • Expired certificate — проверьте сроки всех узлов цепочки (intermediate тоже имеют expiry).
  • Устаревшие root CA у клиента — например, ISRG Root X1 был добавлен в Android только в версии 7.1.1; старые устройства нуждаются в cross-sign.

Часто задаваемые вопросы

Включать ли root CA в fullchain.pem?

Нет. Клиент и так имеет его в trust store. Отправка root увеличивает размер handshake и ничего не добавляет.

Что делать с cross-signed intermediate для старых Android?

Используйте «long chain» от Let's Encrypt, где intermediate подписан старым DST Root CA X3. По умолчанию certbot использует короткую цепочку с ISRG Root X1 — для Android < 7.1.1 нужно форсировать --preferred-chain "ISRG Root X1".

Почему Chrome работает, а Python requests — нет?

Chrome может дотянуть intermediate из кеша AIA Fetching. Python requests использует certifi bundle, который содержит только root. Нужен полный fullchain на сервере.

Как быстро проверить с мобильного?

Используйте онлайн-сервис или сторонний SSL/TLS проверку-проверщик, который не использует ваш десктопный кеш. SSL Checker enterno.io проверяет из своего окружения — это эквивалентно «чистому клиенту».

Заключение

Incomplete chain — тихая проблема: на десктопе не видно, а мобильные пользователи и API-интеграции ломаются. Правильное решение — один раз собрать корректный fullchain.pem и поставить автомониторинг целостности. SSL Checker от enterno.io проверит цепочку за 15 секунд, а Monitors будет делать это каждые 5 минут круглосуточно. Также см. ошибки даты сертификата и handshake failed.

Path validation — RFC 5280, §6. Let's Encrypt chains — letsencrypt.org/certificates. Тест — SSL Labs.

Проверьте ваш сайт прямо сейчас

Проверить →
Другие статьи: SSL
SSL
HSTS и HSTS Preload: полное руководство по принудительному HTTPS
15.04.2026 · 181 просм.
SSL
Просроченный SSL-сертификат: как исправить ошибку NET::ERR_CERT_DATE_INVALID
15.04.2026 · 139 просм.
SSL
Self-signed certificate: когда использовать и как избежать предупреждений
15.04.2026 · 87 просм.
SSL
Слабые cipher suites: как найти и отключить небезопасные шифры TLS
15.04.2026 · 195 просм.