Коротко. В русском поиске «УЦ» означает две разные вещи: удостоверяющий центр, который выпускает TLS-сертификаты для сайтов (НУЦ Минцифры, он же Russian Trusted CA), и аккредитованный УЦ электронной подписи (КриптоПро, токен, Госуслуги). К сертификату сайта относится только первое. Главная практическая проблема российских TLS-сертификатов — цепочка доверия: корня нет в стандартных хранилищах, и ставить его надо не только в браузер, но и на сервер.
Сначала разведём два разных «УЦ» — иначе вы читаете не ту статью
Запросы «удостоверяющий центр» и «цепочка сертификатов УЦ» приводят людей с двумя совершенно разными задачами. Одни хотят, чтобы у их сайта в адресной строке был замок и https://. Другие пришли за электронной подписью, чтобы сдать отчётность или подписать договор. Слова совпадают, технологии — нет. Найдите свою строку в таблице и не тратьте время на чужую половину.
| Что вам нужно | Какой это УЦ | Куда идти |
|---|---|---|
Замок и https:// в адресной строке вашего сайта | УЦ для web-TLS — выпускает серверные сертификаты. В России это НУЦ Минцифры, он же Russian Trusted CA | Это ваша статья. Проверить готовый сертификат — SSL-чекер |
| Браузер пишет, что сертификат сайта не является доверенным | web-TLS: проблема в цепочке доверия, а не в сертификате | Ваша статья + разбор ошибки ERR_CERT_AUTHORITY_INVALID |
| Ваш сервер или скрипт падает при обращении к российскому API | web-TLS, но проблема на стороне клиента: нет корня в системном хранилище | Ваша статья, раздел про установку корня на сервер |
| Подписать декларацию, отчётность, договор, участвовать в торгах | Аккредитованный УЦ электронной подписи (ЭП, в обиходе ЭЦП) | Не эта статья. Нужен УЦ ФНС либо аккредитованный коммерческий УЦ, средство подписи (КриптоПро CSP и аналоги) и носитель — Рутокен, JaCarta |
| Войти на Госуслуги или в личный кабинет налоговой по подписи | ЭП | Не эта статья: плагин браузера, драйвер токена, сертификат подписи |
| Поднять TLS с ГОСТ-алгоритмами | Отдельная история на стыке двух миров | Требует ГОСТ-криптографии с обеих сторон соединения; обычный браузер без дополнительного ПО такое соединение не установит |
Если вы пришли за электронной подписью, ни одна openssl-команда ниже вам не пригодится. Сертификат ЭП живёт на токене и в хранилище криптопровайдера, а не на веб-сервере, и в адресной строке браузера он не появляется никогда. Дальше в статье — только про TLS-сертификаты сайтов.
Почему их вообще путают
Путаница не на пустом месте. Оба объекта — сертификаты X.509. Оба выпускает организация, которая по-русски называется «удостоверяющий центр». У обоих есть срок действия, отпечаток, издатель и цепочка до корня. Совпадает даже словарь: «отозвать сертификат», «продлить сертификат», «цепочка доверия».
Расходятся они в трёх местах, и этого достаточно:
- Назначение внутри сертификата. У серверного TLS-сертификата в расширении Extended Key Usage стоит
serverAuth. У сертификата подписи — назначения, связанные с подписанием документов. Веб-сервер не примет сертификат подписи как серверный, и наоборот. - Кто его читает. TLS-сертификат читает браузер и любой HTTP-клиент — curl, мобильное приложение, чужой сервер. Сертификат ЭП читает криптопровайдер в момент подписания файла.
- Где он хранится. TLS-сертификат лежит файлом на сервере рядом с приватным ключом. Сертификат ЭП — как правило, на аппаратном носителе, откуда приватный ключ принципиально не выгружается.
Что говорит закон — и чего в этой статье нет
Электронная подпись опирается на закон об электронной подписи (63-ФЗ) — именно он вводит понятия аккредитованного УЦ и квалифицированной подписи. TLS-сертификаты сайтов этим законом напрямую не регулируются: сайт с международным сертификатом не становится от этого «незаконным», а с российским — «одобренным».
Состав аккредитованных УЦ, порядок получения сертификатов и технические требования меняются. Номеров приказов, дат вступления в силу, сумм и сроков аккредитации в этой статье намеренно нет — они устаревают быстрее самого текста. Перед любыми действиями сверяйтесь с официальным источником: сайтом ведомства или самого удостоверяющего центра.

Что такое цепочка сертификатов УЦ — коротко
Сервер присылает клиенту листовой сертификат и, как правило, один-два промежуточных. Клиент пытается построить путь от листа вверх до корня, который уже лежит в его собственном хранилище доверия. Если путь не строится — соединение считается недоверенным, каким бы корректным ни выглядел сам сертификат.
Общее устройство цепочки, построение пути и типовые обрывы разобраны отдельно: неполная цепочка сертификатов. Дальше здесь — только российская специфика.
Ключевое правило: сертификат не бывает «валидным вообще». Он валиден относительно конкретного хранилища доверия конкретного клиента. У браузера, у curl, у Java-приложения и у вашего мобильного клиента это четыре разных хранилища, и они не синхронизируются между собой.
Российский корень доверия: почему браузер ругается на валидный сертификат
Сертификат, выпущенный НУЦ Минцифры, — это обычный X.509. Срок действия в порядке, домен в SAN совпадает, подпись корректна. Проблема ровно одна: корневой сертификат, которым эта цепочка заканчивается, не входит в корневые программы Mozilla, Chrome, Apple и Microsoft. Значит, «из коробки» его нет ни в Firefox, ни в Chrome, ни в macOS, ни в Windows, ни в большинстве Linux-дистрибутивов, ни в дефолтном образе Docker.
Клиенту неоткуда взять доверие к вершине цепочки — и он честно говорит об этом пользователю:
- Chrome и Chromium-браузеры —
ERR_CERT_AUTHORITY_INVALID. Подробный разбор именно этой ошибки: как её чинить. - Firefox —
SEC_ERROR_UNKNOWN_ISSUER. Firefox использует собственное хранилище и не смотрит в системное на Windows и Linux по умолчанию, так что установка корня в систему его не лечит. - curl и серверные клиенты —
SSL certificate problem: unable to get local issuer certificate, код выхода 60. - Java —
PKIX path building failed: unable to find valid certification path to requested target. - Python —
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate.
Все пять сообщений — про одно и то же: путь до доверенного корня не построен. Разными словами, потому что хранилища разные.
Что делает пользователь и что делает владелец сайта
Пользователь может поставить корневой сертификат себе — в систему или в браузер. Это его выбор и его действие, и вы им не управляете. Владелец сайта может сделать три вещи: отдавать полную цепочку, честно предупредить аудиторию с инструкцией по установке и — главное — заранее решить, какая доля аудитории этот корень никогда не поставит.
Часть российских браузерных сборок поставляет корень предустановленным — так делают, в частности, Яндекс.Браузер и Атом. Формулировка «часть сборок» здесь не осторожность ради осторожности: состав предустановленных корней меняется от версии к версии, и единственный надёжный способ узнать — открыть в конкретной сборке список доверенных корневых центров и поискать там строку Russian Trusted.
Не полагайтесь на «у всех уже стоит». Аудитория сайта — это не только десктопные браузеры. Это ещё мобильные приложения, платёжные шлюзы, агрегаторы, поисковые роботы, чужие серверные интеграции и ваши собственные скрипты. Каждый из них носит своё хранилище доверия, и ни к одному из них вы не приложите инструкцию «поставьте корень».
Чем российский сертификат отличается от международного
| Параметр | Российский УЦ (НУЦ Минцифры) | Международный CA |
|---|---|---|
| Корень доверия | национальный корень плюс промежуточный | корень в программах Mozilla, Chrome, Apple, Microsoft |
| Предустановка в клиентах | не гарантирована; часть российских сборок поставляет | практически везде «из коробки» |
| Формат | X.509, стандартные расширения | X.509, стандартные расширения |
| Проверка срока действия | стандартная, теми же командами | стандартная |
| Автоматизация выпуска и продления | как правило, выдача через портал, а не по ACME — привычный сценарий с certbot не работает | ACME повсеместно, продление в фоне |
| Публичные CT-логи | рассчитывать на попадание в публичные логи прозрачности не стоит | логирование фактически обязательно для доверия в Chrome |
| Инвентаризация через crt.sh и аналоги | может не находиться — ведите учёт сами | работает |
| Кому подходит | российской аудитории и контурам, где вы контролируете хранилища доверия | универсальной и международной аудитории |
Про алгоритмы важное уточнение. Российский TLS-сертификат и ГОСТ-криптография — не синонимы. Сертификаты НУЦ выпускаются в обычном X.509 с распространёнными алгоритмами подписи, и именно поэтому обычный браузер принимает их сразу, как только появляется корень. Проверить, что у вас на руках, можно за одну команду:
# алгоритм подписи и параметры ключа в конкретном сертификате
openssl x509 -in russian_trusted_root_ca.cer -inform DER -noout -text \
| grep -E 'Signature Algorithm|Public Key Algorithm|Public-Key'
# то же самое для сертификата, который реально отдаёт сервер
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -text | grep -E 'Signature Algorithm|Issuer:|Subject:'
Если в выводе видны ГОСТ-алгоритмы, вы имеете дело не с обычным web-TLS, а с ГОСТ-контуром — и тогда одного корня в хранилище будет мало, потребуется криптопровайдер на клиенте.
Установка корневого сертификата на сервер, а не в браузер
Самая дорогая ошибка в этой теме — считать, что российский корень нужен только конечным пользователям. На практике первым ломается не браузер, а ваш собственный сервер. Браузер хотя бы показывает человеку понятное окно с предупреждением; серверная интеграция просто падает в лог, часто молча и часто ночью.
Что ломается типично:
- cron-скрипт, который забирает курс валют или справочник с российского портала;
- PHP-интеграция с банковским или платёжным API;
- Python-выгрузка отчётов по HTTPS;
- Java-коннектор к системе ЭДО или к внутреннему сервису;
- вебхуки, которые вы отправляете на адрес контрагента с российским сертификатом;
- сборка в CI, которая тянет зависимость или артефакт с российского зеркала.
Симптом всегда один и тот же: unable to get local issuer certificate в логе. Браузер тут вообще ни при чём — у него своё хранилище, и то, что сайт открывается у вас на ноутбуке, ничего не говорит о сервере.
AlmaLinux, RHEL, Rocky, CentOS, Fedora
# кладём корневой И промежуточный в каталог якорей доверия
sudo cp russian_trusted_root_ca.cer /etc/pki/ca-trust/source/anchors/
sudo cp russian_trusted_sub_ca.cer /etc/pki/ca-trust/source/anchors/
# пересобираем системный бандл (принимает и PEM, и DER)
sudo update-ca-trust extract
# проверяем, что якорь реально попал в извлечённое хранилище
trust list --filter=ca-anchors | grep -i -B2 'Russian Trusted'
# запасной способ проверки — поиск по собранному бандлу
grep -c 'BEGIN CERTIFICATE' /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
Каталог source/anchors/ принимает файлы и в PEM, и в DER — конвертировать заранее не обязательно. Команда update-ca-trust без аргументов делает то же, что update-ca-trust extract.
Debian и Ubuntu
# сюда кладут ТОЛЬКО PEM и ТОЛЬКО с расширением .crt — иначе файл молча игнорируется
sudo cp russian_trusted_root_ca.pem /usr/local/share/ca-certificates/russian_trusted_root_ca.crt
sudo cp russian_trusted_sub_ca.pem /usr/local/share/ca-certificates/russian_trusted_sub_ca.crt
sudo update-ca-certificates
# если файл пришёл в DER — сначала конвертируем
openssl x509 -inform DER -in root.cer -outform PEM -out russian_trusted_root_ca.crt
# проверяем
awk -v cmd='openssl x509 -noout -subject' \
'/BEGIN/{c=cmd} c{print | c} /END/{close(c); c=0}' \
/etc/ssl/certs/ca-certificates.crt | grep -i 'russian'
Здесь два подводных камня, на которых теряют время чаще всего. Первый: update-ca-certificates подхватывает только файлы с расширением .crt. Файл с именем root.pem или root.cer будет лежать в каталоге и не делать ничего — никакой ошибки вы не увидите. Второй: содержимое должно быть в PEM, DER под именем .crt тоже не сработает. Успешный запуск печатает строку вида 1 added, 0 removed — если там ноль, значит ничего не установилось.
Alpine и контейнеры
# внутри контейнера на Alpine
apk add --no-cache ca-certificates
cp russian_trusted_root_ca.crt /usr/local/share/ca-certificates/
update-ca-certificates
# в Dockerfile — чтобы фикс пережил пересборку образа
# COPY russian_trusted_root_ca.crt /usr/local/share/ca-certificates/
# RUN update-ca-certificates
Установка корня внутри работающего контейнера живёт ровно до первого пересоздания. Кладите сертификат в образ через COPY в Dockerfile либо монтируйте каталог с бандлом снаружи. Иначе интеграция сломается в самый неудобный момент — при плановом обновлении образа, когда никто не будет искать причину в сертификатах.

Рантаймы со своим хранилищем: Java, Node.js, Python
Системная установка корня — необходимый шаг, но не достаточный. Часть популярных рантаймов принципиально не смотрит в системное хранилище. Это и есть источник классического «на сервере curl работает, а приложение падает».
| Клиент | Использует системное хранилище | Что делать дополнительно |
|---|---|---|
| curl, wget | да | достаточно системной установки |
| PHP (cURL и потоки OpenSSL) | обычно да | проверить curl.cainfo и openssl.cafile в php.ini: если там прописан свой бандл, дополнять надо его |
| Go на Linux | да | достаточно системной установки |
| .NET на Linux | да | достаточно системной установки |
| Java (JVM) | нет — свой файл cacerts | импорт через keytool |
| Node.js | нет — вкомпилированный список корней | переменная NODE_EXTRA_CA_CERTS |
| Python: requests, httpx | нет — бандл certifi | SSL_CERT_FILE, REQUESTS_CA_BUNDLE или явный параметр verify |
| Python: ssl, urllib | обычно да | берёт пути OpenSSL, отдельных действий не требует |
| Браузер | Chrome и Edge — да; Firefox — нет | для Firefox корень ставится в его собственное хранилище |
Java: импорт в cacerts
# Java 9 и новее: хранилище лежит в $JAVA_HOME/lib/security/cacerts
sudo keytool -importcert -trustcacerts -noprompt \
-alias russian-trusted-root \
-file /etc/pki/ca-trust/source/anchors/russian_trusted_root_ca.cer \
-keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit
# проверяем, что алиас появился
keytool -list -keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit \
| grep -i russian
Пароль по умолчанию — changeit; если его меняли, подставьте свой. В Java 8 путь другой: $JAVA_HOME/jre/lib/security/cacerts. И главное: обновление JDK перезаписывает cacerts целиком, вместе с вашим импортом. Если сервис критичен, держите отдельный truststore и подключайте его флагом -Djavax.net.ssl.trustStore — тогда апдейт JDK ничего не сломает.
Node.js и Python
# Node.js: переменная читается один раз при старте процесса, только PEM
NODE_EXTRA_CA_CERTS=/etc/ssl/certs/russian_trusted_root_ca.pem node app.js
# Python: где лежит бандл certifi, который использует requests
python3 -c "import certifi; print(certifi.where())"
# правильный способ — не править файл certifi, а указать свой бандл
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
python3 -c "import requests; print(requests.get('https://example.ru').status_code)"
Не дописывайте корень прямо в файл certifi. Первое же обновление пакета сотрёт правку, и падение вернётся без единого изменения в вашем коде — искать причину будут долго. Задавайте бандл переменной окружения в unit-файле сервиса или в переменных контейнера.
Как НЕ надо проверять установку: грабля с gosuslugi.ru
Не проверяйте установку корня запросом на gosuslugi.ru. Портал ограничивает обращения с адресов дата-центров, и вашcurlс сервера получит отказ, который выглядит как проблема с сертификатом, хотя сертификат и хранилище в полном порядке. Берите для проверки ресурс, который не режет адреса ЦОД, — напримерsberbank.ru.
Эта ошибка стоит нескольких часов, потому что она выглядит убедительно: вы только что поставили корень, идёте проверять на самый очевидный государственный сайт и получаете отказ. Дальше человек начинает переустанавливать сертификат, пересобирать бандл и искать опечатку в пути — а проблема совсем в другом слое.
Разделитель простой: смотрите, дошло ли дело до TLS-хендшейка вообще.
| Что вы видите | TLS-хендшейк | Диагноз |
|---|---|---|
SSL certificate problem: unable to get local issuer certificate, код выхода curl 60 | не завершён | корня нет в хранилище или клиент читает не то хранилище |
SSL certificate problem: certificate has expired, код выхода 60 | не завершён | истёк сертификат сервера; к установке корня отношения не имеет |
| Пришёл HTTP-ответ 403, 429 или страница с проверкой, код выхода curl 0 | завершён успешно | сертификат в порядке, вас ограничили по IP или завернул WAF |
Connection timed out или Connection reset, код выхода 28, 35 или 56 | не начался или оборвался | сеть, фильтрация, отсутствие egress — не сертификат |
openssl s_client печатает Verify return code: 0 (ok), а приложение всё равно ругается | завершён | разные хранилища: openssl взял системное, приложение — своё (Java, Node.js, certifi) |
# 1. только TLS, без HTTP: проверяем сертификат и путь доверия
echo | openssl s_client -connect sberbank.ru:443 -servername sberbank.ru 2>/dev/null \
| grep -E 'Verify return code|subject=|issuer='
# 2. подробный лог curl: видно, на каком шаге всё оборвалось
curl -sv -o /dev/null https://sberbank.ru 2>&1 \
| grep -Ei 'SSL certificate|issuer|subjectAltName|HTTP/'
# 3. код выхода curl — самый быстрый разделитель: 0 против 60
curl -sS -o /dev/null https://sberbank.ru; echo "curl exit=$?"
Логика чтения: если openssl s_client дошёл до строки Verify return code — TLS отработал, и дальше вопрос уже не про сертификат. Если curl вернул 0 и вы получили HTTP-код, пусть даже 403, — сертификат тем более принят, потому что HTTP-ответ невозможен без завершённого хендшейка.
Диагностика цепочки: openssl s_client и Verify return code
# сколько сертификатов реально прислал сервер
echo | openssl s_client -connect example.ru:443 -servername example.ru -showcerts 2>/dev/null \
| grep -c 'BEGIN CERTIFICATE'
# кто кого подписал: subject и issuer по уровням цепочки
echo | openssl s_client -connect example.ru:443 -servername example.ru -showcerts 2>/dev/null \
| grep -E '^ *[0-9]+ s:|^ *[0-9]+ i:'
# итоговый вердикт проверки пути
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| grep 'Verify return code'
Что означают коды, которые встречаются в этой теме чаще других:
0 (ok)— путь построен от вашего системного хранилища. Всё хорошо именно на этой машине.20 (unable to get local issuer certificate)— для верхнего присланного сертификата не нашлось издателя в локальном хранилище.21 (unable to verify the first certificate)— как правило, сервер прислал только листовой сертификат.2 (unable to get issuer certificate)— то же семейство: издатель не найден.10 (certificate has expired)— истёк срок, к удостоверяющему центру отношения не имеет.19 (self signed certificate in certificate chain)— в цепочке самоподписанный сертификат.
Как отличить «нет промежуточного» от «нет корня»
Два разных диагноза с почти одинаковым текстом ошибки. Разделяются они за две команды.
- Посчитайте сертификаты в ответе сервера. Если
grep -c 'BEGIN CERTIFICATE'вернул 1 — сервер отдаёт только лист. Это ваша проблема как владельца сайта, и чинится она в конфиге сервера, а не у клиента. - Если сертификатов два и больше, а ошибка остаётся — значит, верхний присланный сертификат подписан корнем, которого нет в хранилище. Это чинится установкой корня на стороне клиента.
- Проверьте гипотезу в лоб — подставьте корень явно и посмотрите, изменится ли вердикт.
# явно указываем корневой сертификат файлом
echo | openssl s_client -connect example.ru:443 -servername example.ru \
-CAfile /etc/pki/ca-trust/source/anchors/russian_trusted_root_ca.cer 2>/dev/null \
| grep 'Verify return code'
Если с флагом -CAfile стало 0 (ok), а без него — нет, диагноз однозначный: сертификат и цепочка в порядке, корень просто не установлен в систему. Это самая быстрая проверка во всём разборе, и она снимает большую часть спорных случаев.
Если же сервер отдаёт только лист — вот как это чинится на стороне владельца сайта:
# nginx: ssl_certificate должен указывать на файл «лист + промежуточные»
cat leaf.crt sub_ca.crt > /etc/nginx/ssl/example.ru.fullchain.crt
nginx -t && systemctl reload nginx
# Apache: лист в SSLCertificateFile, промежуточные в SSLCertificateChainFile
apachectl configtest && systemctl reload httpd
Порядок в файле важен: сначала листовой сертификат, затем промежуточные снизу вверх. Корень в файл добавлять не нужно — он должен быть у клиента, а не в ответе сервера. Подробнее про сбор цепочки — в статье про неполную цепочку, а общий порядок проверки сертификата — в материале как проверить SSL-сертификат.

Что это значит для владельца сайта
Выбор удостоверяющего центра — это не техническое, а продуктовое решение. Технически оба варианта работают одинаково; отличается только то, сколько ваших пользователей увидят предупреждение.
Когда российский сертификат оправдан
- Аудитория целиком российская, и вы готовы держать понятную инструкцию по установке корня.
- Внутренний или корпоративный контур: вы управляете рабочими станциями и можете раскатать корень централизованно.
- Международный CA по каким-либо причинам недоступен для вашей организации или домена.
- Сервис уже требует от пользователя установки дополнительного ПО — тогда корень встраивается в ту же инструкцию без нового трения.
Когда не оправдан
- Есть зарубежная аудитория, партнёрские интеграции или платёжные шлюзы.
- Продукт — публичный API, который дёргают чужие серверы: корня у них не будет, а повлиять на их хранилище вы не сможете в принципе.
- Сайт живёт на органическом поиске: часть роботов и внешних проверялок просто не дойдёт до контента.
- Вы не готовы держать поддержку по сценарию «поставьте корень» — это постоянная нагрузка, а не разовая.
Правило простое: чем больше у сайта потребителей, чьё хранилище доверия вы не контролируете, тем дороже обходится нестандартный корень. Для публичного API это почти всегда неприемлемо, для внутреннего портала — почти всегда нормально.
Двойная выдача: международный плюс российский
Идея звучит логично: пусть сервер отдаёт российский сертификат тем, у кого есть корень, и международный всем остальным. На практике так не получится, и причину стоит понимать до того, как вы начнёте это проектировать.
Клиент в TLS-хендшейке не сообщает серверу, каким корням он доверяет. Он присылает имя домена в расширении SNI и список поддерживаемых алгоритмов — и всё. Сервер физически не может выбрать сертификат «по наличию корня у клиента», потому что этих данных у него нет. Несколько директив ssl_certificate в nginx выбирают сертификат по типу ключа, RSA или ECDSA, а не по доверию клиента.
Значит, двойная выдача на практике — это всегда разные точки входа, а не автоматика внутри одного сервера:
- Разные хосты. Основной домен под международным сертификатом, отдельный поддомен или зеркало — под российским, с явной ссылкой и объяснением.
- Разные адреса по географии. DNS отдаёт разным пользователям разные IP, на каждом фронте свой сертификат. Работает, но добавляет целый слой инфраструктуры и новый класс инцидентов.
- Разные каналы. Публичный сайт — международный сертификат, внутренние и партнёрские интеграции — российский. Обычно это самый дешёвый и самый честный вариант.
Срок действия и мониторинг истечения
Истёкший сертификат рвёт защищённое соединение независимо от того, какой УЦ его выпустил. Но у российских сертификатов риск пропустить продление выше по двум причинам: обычно нет ACME с автопродлением в фоне, и обычно нет записи в публичных CT-логах, по которым многие незаметно для себя инвентаризуют свой парк сертификатов. То есть отваливаются сразу два привычных страховочных механизма.
# срок действия, издатель и субъект одной командой
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -dates -subject -issuer
# истечёт ли в ближайшие 14 дней: код возврата 1 — да, 0 — нет
echo | openssl s_client -connect example.ru:443 -servername example.ru 2>/dev/null \
| openssl x509 -noout -checkend 1209600
Команду с -checkend удобно ставить в cron и завязывать на неё уведомление: она возвращает готовый код возврата, парсить даты не нужно.
На enterno.io SSL-монитор проверяет срок по расписанию и присылает алерт заранее — по умолчанию за 14 дней предупреждение и за 3 дня критический уровень. Настраивается в разделе мониторинга, уведомления уходят в Telegram и на почту.
Важный нюанс именно для российских сертификатов: разделяйте в мониторинге «истекает» и «не доверен». Внешний чекер, у которого нет вашего корня, покажет ошибку доверия — и она замаскирует настоящий срок действия. Смотрите на дату из сертификата отдельно от вердикта проверки пути, иначе вы получите ложную тревогу вместо реального предупреждения за две недели.
Смежные материалы: мониторинг SSL-сертификатов и что делать, если сертификат уже истёк.

Симптом, причина, проверка, фикс
| Симптом | Вероятная причина | Проверка | Фикс |
|---|---|---|---|
| Сайт открывается в Яндекс.Браузере, но не в Chrome | корень есть только в части сборок | найти Russian Trusted в списке доверенных корней каждого браузера | инструкция по установке корня; для публичного сайта — пересмотреть выбор УЦ |
curl на сервере: unable to get local issuer certificate | корня нет в системном бандле | trust list или поиск по ca-certificates.crt | update-ca-trust или update-ca-certificates |
curl работает, Java-сервис падает с PKIX path building failed | у JVM собственный cacerts | keytool -list с грепом по alias | keytool -importcert в cacerts или отдельный truststore |
Python: CERTIFICATE_VERIFY_FAILED, хотя curl проходит | requests читает certifi, а не систему | python3 -c "import certifi; print(certifi.where())" | задать SSL_CERT_FILE и REQUESTS_CA_BUNDLE |
| После обновления образа контейнера всё сломалось снова | корень ставили внутри работающего контейнера | заглянуть в каталог якорей внутри нового контейнера | перенести установку в Dockerfile |
| После обновления JDK Java снова не доверяет | апдейт перезаписал cacerts | keytool -list — алиаса нет | повторный импорт либо свой truststore через флаг JVM |
Verify return code: 21, сертификат в ответе один | сервер отдаёт только лист | grep -c 'BEGIN CERTIFICATE' | собрать fullchain и перечитать конфиг веб-сервера |
| С сервера 403, с ноутбука 200 | ограничение по адресам ЦОД, а не сертификат | сравнить код выхода curl: 0 против 60 | тестировать на ресурсе, который не режет ЦОД |
| Сертификат «не найден» в crt.sh | выпуск не логируется в публичных CT | сверить с реальным ответом сервера через s_client | вести реестр сертификатов самостоятельно |
Как проверить на enterno.io
- SSL-чекер — цепочка, издатель, срок действия, протокол и набор шифров. Первое, что стоит открыть: поле issuer сразу показывает, российский это корень или международный.
- Разбор ошибок SSL — если браузер уже показывает конкретный код ошибки.
- Сканер безопасности — заголовки, HSTS, редирект на HTTPS и смешанный контент.
- Мониторинг — SSL-монитор со сроком действия, предупреждение за 14 дней и критический алерт за 3 дня, уведомления в Telegram.
- Проверка HTTP-заголовков — цепочка редиректов с http на https и что реально отдаёт сервер.
Смежные разборы: не удаётся проверить сертификат сервера, типы сертификатов DV, OV и EV, самоподписанные сертификаты, доступность сайта из России и из-за рубежа.
Частые вопросы
Российский УЦ и УЦ электронной подписи — это одно и то же?
Нет. Это разные организации, разные сертификаты и разные технологии, совпадает только русское слово «удостоверяющий центр». УЦ для web-TLS выпускает серверные сертификаты для сайтов. Аккредитованный УЦ электронной подписи выдаёт сертификаты для подписания документов — они работают с криптопровайдером и токеном и на веб-сервер не ставятся.
Мне выдали сертификат электронной подписи на токене — можно поставить его на сайт?
Нет. У сертификата подписи другое назначение в расширении Extended Key Usage, приватный ключ не выгружается с носителя, и веб-сервер такой сертификат как серверный не примет. Для сайта нужен отдельный TLS-сертификат с назначением serverAuth.
Почему curl на сервере ругается, а в браузере сайт открывается?
Потому что это два разных хранилища доверия. В вашем браузере корень уже есть — сам поставил или пришёл вместе со сборкой. На сервере системный бандл никто не трогал. Ставьте корень на сервер отдельно и проверяйте, не использует ли ваш рантайм собственное хранилище.
Достаточно ли поставить только корневой сертификат, без промежуточного?
Если сервер сам присылает промежуточный — да, корня достаточно. Если не присылает, клиенту неоткуда его взять. Надёжнее сделать два действия сразу: положить в якоря и корень, и промежуточный, и одновременно починить fullchain на сервере, чтобы не зависеть от настроек каждого клиента.
Как понять, что корень реально попал в системное хранилище?
На RHEL-подобных: trust list --filter=ca-anchors с грепом по имени. На Debian и Ubuntu — поиск по собранному файлу /etc/ssl/certs/ca-certificates.crt. Самая надёжная проверка — сравнить openssl s_client с флагом -CAfile и без него: если с флагом вердикт 0 (ok), а без флага нет, корень в системе не установлен.
Стоит ли ставить российский сертификат на публичный API?
Как правило, нет. Публичный API вызывают чужие серверы, чьи хранилища доверия вы не контролируете и не можете исправить. Каждый такой клиент увидит ошибку проверки пути, а починить её сможет только своими руками. Для публичных интеграций это дорогое решение.
Помогут ли CT-логи отследить выпуск российского сертификата?
Рассчитывать на это не стоит. Требование логировать выпуск в публичных логах прозрачности связано с корневыми программами браузеров, и для сертификатов вне этих программ оно не действует. Инвентаризацию через crt.sh и аналогичные сервисы придётся заменить собственным реестром и мониторингом по факту ответа сервера.
Чеклист
- Определили, какой именно УЦ вам нужен: web-TLS для сайта или электронная подпись для документов.
- Понимаете, какая доля вашей аудитории и каких интеграций не имеет российского корня.
- Сервер отдаёт полную цепочку: листовой сертификат плюс промежуточные, счётчик
BEGIN CERTIFICATEбольше единицы. - Корневой и промежуточный сертификаты установлены в системное хранилище на всех серверах, которые ходят к российским сервисам.
- Установка корня зафиксирована в Dockerfile или в конфигурации образа, а не сделана руками внутри работающего контейнера.
- Проверены рантаймы со своим хранилищем: Java, Node.js, Python с requests.
- Проверку установки делали не на gosuslugi.ru, а на ресурсе, который не ограничивает адреса дата-центров.
- Умеете отличать код выхода curl 60 от HTTP 403 при коде выхода 0.
- Есть мониторинг срока действия с алертом минимум за две недели, и он отделяет «истекает» от «не доверен».
- Продление занесено в календарь: автопродления по ACME здесь, как правило, нет.
Проверьте свой сертификат и цепочку прямо сейчас: запустите SSL-проверку на enterno.io и включите мониторинг срока действия с алертами в Telegram. Если браузер уже показывает ошибку — начните с разбора кодов SSL-ошибок.