Перейти к содержанию

Codex: как исправить self signed certificate in certificate chain

Клиент Codex читает CODEX_CA_CERTIFICATE, процессы Node — NODE_EXTRA_CA_CERTS, curl в песочнице — собственный файл. Отключать проверку сертификатов не нужно.

A
••9 мин чтения•Инструменты AI-разработки
Изометрическая стопка слоёв цепочки сертификатов: верхний красный слой — корень цепочки без доверия, нижний — сертификат сервера chatgpt.com

Сообщение self signed certificate in certificate chain в Codex почти никогда не означает, что вы сами что-то подписали. Оно говорит о сети: цепочка сертификатов, которую получил процесс, заканчивается корневым сертификатом, которого нет в его хранилище доверенных. На рабочем ноутбуке это обычно корневой сертификат корпоративного прокси, который проверяет HTTPS-трафик и переподписывает его сертификатом компании.

Исправление состоит из двух действий: получить этот корневой сертификат в формате PEM и передать его той настройке, которую читает именно упавший процесс. Для Codex CLI это выглядит так:

bash
export CODEX_CA_CERTIFICATE="$HOME/certs/corp-root-ca.pem"
codex login

Если ошибка появилась не в самом Codex, а в настольном приложении, MCP-сервере или в команде, которую Codex запустил в песочнице, эта переменная может не помочь: у каждого из этих процессов свой источник доверия. Отключать проверку сертификатов (NODE_TLS_REJECT_UNAUTHORIZED=0, curl -k) не нужно ни в одном из случаев.

Какой процесс выдал ошибку и какую настройку он читает

Сначала найдите, где именно вы увидели текст ошибки: от этого зависит, какая настройка её уберёт.

Где появилась ошибкаКакой процесс не доверяет цепочкеЧто настроить
codex login, запросы и WebSocket в Codex CLIСобственный клиент CodexCODEX_CA_CERTIFICATE, если её нет — SSL_CERT_FILE
MCP-сервер, подключённый по urlHTTP-клиент MCP внутри CodexТе же CODEX_CA_CERTIFICATE / SSL_CERT_FILE
MCP-сервер, запущенный через command (npx, node)Отдельный процесс NodeNODE_EXTRA_CA_CERTS в окружении этого сервера
Remote Control в настольном приложении, в журнале SELF_SIGNED_CERT_IN_CHAINNode-слой приложенияПо сообщению пользователя на macOS — запуск с NODE_USE_SYSTEM_CA=1
curl: (60) SSL certificate problem: self signed certificate in certificate chain в команде, которую выполнил Codexcurl внутри песочницыЯвный файл: CURL_CA_BUNDLE или --cacert
npm install и другие Node-инструменты, запущенные CodexПроцесс Node внутри песочницыNODE_EXTRA_CA_CERTS, переданная через политику окружения
Четыре карточки: Codex CLI и MCP по url читают CODEX_CA_CERTIFICATE, MCP-сервер через command — NODE_EXTRA_CA_CERTS, настольное приложение — NODE_USE_SYSTEM_CA=1, команды в песочнице — CURL_CA_BUNDLE

Первые две строки опираются на документацию и код Codex, третья и шестая — на документацию Node.js. Четвёртая и пятая описаны только в открытых обращениях пользователей в репозитории openai/codex, сопровождающие их не подтверждали; подробности — в соответствующих разделах ниже.

Что означает self signed certificate in certificate chain

Это ошибка проверки цепочки с кодом 19 в OpenSSL: сервер предъявил цепочку, которая упирается в самоподписанный корневой сертификат, а клиент этого корневого сертификата не знает. Самоподписан любой корневой сертификат, в том числе публичных удостоверяющих центров; разница в том, что публичные заранее лежат в хранилище доверенных, а корпоративный — нет.

В корпоративной сети причина чаще всего одна: прокси или агент безопасности выполняет инспекцию HTTPS. Он принимает соединение с chatgpt.com или api.openai.com, проверяет содержимое и отдаёт вашему компьютеру тот же ответ, но с сертификатом, выпущенным корневым CA организации. Браузер при этом работает, потому что ИТ-служба добавила корневой сертификат в системное хранилище. Процесс, который системное хранилище не читает, видит незнакомый корневой сертификат и прерывает соединение.

Реже встречаются другие причины: антивирус с проверкой HTTPS, собственный шлюз или MCP-сервер с сертификатом частного CA, нестандартный базовый URL. Похожее сообщение self-signed certificate без слов про цепочку (код 18) — другой случай: самоподписан сам сертификат сервера, а не корень цепочки.

Кто переподписал соединение: проверка через openssl s_client

Прежде чем что-либо менять, посмотрите, чья подпись стоит в конце цепочки. Подставьте хост из текста ошибки или журнала; если его нет, начните с chatgpt.com:

bash
openssl s_client -connect chatgpt.com:443 -showcerts </dev/null

В выводе найдите блок Certificate chain. Каждая запись состоит из строки s: (кому выдан сертификат) и i: (кем выдан). Смотрите на i: последней записи:

  • название вашей компании или продукта безопасности — инспекция HTTPS подтверждена, нужен корневой сертификат именно этого издателя;
  • публичный удостоверяющий центр — трафик к этому хосту не переподписывается, причину ищите в другом хосте из ошибки или в самом процессе;
  • незнакомое название, которое не относится ни к компании, ни к известным вам средствам защиты, — не добавляйте его в доверенные, покажите вывод ИТ-службе.

Если выход в интернет возможен только через явный прокси, добавьте к команде -proxy хост:порт. Описание параметров — в документации OpenSSL по s_client.

Как получить корневой сертификат в формате PEM

Самый надёжный источник — ИТ-служба: попросите корневой сертификат корпоративного прокси файлом PEM. Если он уже установлен в системе, его можно выгрузить самостоятельно:

  • macOS: «Связка ключей» → связка «Система» → найдите сертификат с именем из строки i: → «Файл» → «Экспортировать объекты», формат .pem;
  • Windows: certmgr.msc → «Доверенные корневые центры сертификации» → «Сертификаты» → «Экспорт», формат «X.509 в кодировке Base-64».

Файл PEM — текстовый, начинается со строки -----BEGIN CERTIFICATE-----. Убедитесь, что в нём тот самый издатель:

bash
openssl x509 -in "$HOME/certs/corp-root-ca.pem" -noout -subject -issuer -enddate

У корневого сертификата subject и issuer совпадают, и это имя должно совпасть с i: последней записи из предыдущего шага.

Codex CLI: CODEX_CA_CERTIFICATE и SSL_CERT_FILE

Клиенту Codex достаточно пути к PEM-файлу в переменной окружения. В документации по аутентификации сказано: если сеть использует корпоративный TLS-прокси или частный корневой CA, задайте CODEX_CA_CERTIFICATE до входа; когда она не задана, Codex использует SSL_CERT_FILE.

macOS и Linux:

bash
export CODEX_CA_CERTIFICATE="$HOME/certs/corp-root-ca.pem"
codex login

Windows PowerShell:

powershell
$env:CODEX_CA_CERTIFICATE = "C:\certs\corp-root-ca.pem"
codex login

Чтобы настройка сохранялась между сеансами, добавьте строку export в ~/.zshrc или ~/.bashrc, а в Windows задайте переменную среды пользователя.

Что стоит знать о поведении этой настройки (по описанию изменения #14239 в репозитории Codex, принятого 13 марта 2026 года):

  • она действует не только на вход: её учитывают исходящие HTTPS-запросы и защищённые WebSocket-соединения, включая облачные задачи и HTTP-клиент MCP;
  • порядок такой: CODEX_CA_CERTIFICATE, затем SSL_CERT_FILE, затем системные корневые сертификаты;
  • ваш файл добавляется к системным корневым, а не заменяет их, поэтому в нём достаточно одного корпоративного корня;
  • если файл не читается или повреждён, Codex выводит ошибку с именем переменной и путём — по ней видно, что настройка подхвачена.

Проверка результата: codex login завершается без ошибки, после чего короткий запрос в новом сеансе получает ответ. Если вместо этого вы видите сообщение о загрузке CA с путём к файлу, исправьте путь или формат файла.

Два случая, когда переменная не срабатывает:

  1. Старая сборка CLI. Сборки до этого изменения доверяли только системным корневым сертификатам; у пользователя версии 0.58.0 та же причина давала при входе сообщение Token exchange failed: error sending request for url (https://auth.openai.com/oauth/token ) — без слов про сертификат (обращение #6849). Обновите Codex и повторите. Остальные причины этого сообщения разобраны в материале про ошибку Token Exchange Failed в Codex и поиск этапа сбоя.
  2. Переменная задана не в том окружении. Она действует только на процесс, который её унаследовал: терминал, открытый до правки ~/.zshrc, или IDE, запущенная из Dock, о ней не знают. Перезапустите терминал; расширение IDE проверьте, запустив редактор из терминала, где переменная уже задана.

Вход по коду устройства (codex login --device-auth) проблему не обходит: он удобен на машинах без браузера, но обращается к тем же серверам по HTTPS и упирается в ту же проверку цепочки.

Настольное приложение: Remote Control и NODE_USE_SYSTEM_CA=1

Для настольного приложения официального описания работы с собственным CA в документации Codex нет, есть сообщение пользователя. В обращении #43489 от 7 сентября 2026 года (приложение 26.901.51231, macOS 26.6.1) описано следующее: в сети с инспекцией HTTPS функция Remote Control не подключается, в журнале остаются SELF_SIGNED_CERT_IN_CHAIN и строка [remote-control-transport] remote_control_websocket.connect_failed_before_open. При этом корневой сертификат компании доверен в системной связке ключей, а curl, OpenSSL и отдельно установленный Node проверяют цепочку успешно.

Автор обращения добился подключения, запустив приложение из терминала с переменной, которая заставляет Node читать системное хранилище:

bash
NODE_USE_SYSTEM_CA=1 /Applications/ChatGPT.app/Contents/MacOS/ChatGPT

Это наблюдение одного пользователя: обращение открыто, ответа сопровождающих в нём нет, и в следующих сборках поведение может измениться. Сама переменная документирована в справке Node.js: NODE_USE_SYSTEM_CA=1 подключает хранилище операционной системы — связку ключей в macOS, хранилище сертификатов Windows, стандартные каталоги OpenSSL в Linux. Там же описана NODE_EXTRA_CA_CERTS: она добавляет сертификаты из PEM-файла к встроенным корневым и читается один раз при старте процесса.

Читает ли Node-слой приложения CODEX_CA_CERTIFICATE и как приложение ведёт себя в Windows и Linux, в открытых источниках не описано. Если запуск с NODE_USE_SYSTEM_CA=1 не помогает, приложите к обращению в поддержку или к тому же issue строку из журнала и вывод openssl s_client. Когда приложение при этом ещё и теряет связь посреди работы, сначала сохраните состояние по инструкции «Codex постоянно переподключается: сохраните задачу и найдите причину».

MCP-серверы: подключение по url и отдельный процесс Node

У MCP-серверов два разных случая, и определяются они тем, как сервер описан в config.toml.

Сервер с ключом url вызывается HTTP-клиентом самого Codex. Этот клиент входит в список компонентов, на которые распространили CODEX_CA_CERTIFICATE и SSL_CERT_FILE, поэтому отдельной настройки не требуется: достаточно шага из предыдущего раздела. Так же решается ситуация, когда сервер развёрнут внутри компании и его сертификат выпущен частным CA: добавьте корень этого CA в тот же PEM-файл.

Сервер с ключом command — отдельный процесс. Если он написан на Node (типичный запуск через npx), то к внешним API он обращается сам и читает собственные настройки доверия. Передайте ему файл через таблицу env сервера, описанную в документации по MCP:

toml
[mcp_servers.docs]
command = "npx"
args = ["-y", "example-mcp-server"]

[mcp_servers.docs.env]
NODE_EXTRA_CA_CERTS = "/Users/you/certs/corp-root-ca.pem"

Имя сервера и пакета здесь условные, путь к файлу укажите абсолютный. NODE_EXTRA_CA_CERTS читается при старте, поэтому после правки перезапустите Codex. Если файл повреждён, Node ограничится предупреждением и продолжит работу без него — при повторной ошибке проверьте файл командой openssl x509 из раздела выше. Серверы на других языках читают свои настройки; для них ищите параметр CA в документации конкретного сервера.

curl: (60) и npm в командах, которые запускает Codex

Команды, запущенные Codex, работают в песочнице и в отфильтрованном окружении, поэтому могут падать даже тогда, когда та же команда в обычном терминале проходит.

Первая причина описана в обращении #11182 (9 февраля 2026 года, codex-cli 0.98.0, macOS). По разбору автора, системный curl на macOS для корневых сертификатов, которых нет в /etc/ssl/cert.pem, обращается к службе com.apple.TrustEvaluationAgent, чтобы проверить доверие по связке ключей. Песочница это обращение запрещает (отказ виден при запуске с --log-denials), и curl завершается с curl: (60) SSL certificate problem: self signed certificate in certificate chain. Обращение открыто, решения от сопровождающих в нём нет.

Обойтись без связки ключей можно штатным способом curl — указать файл с сертификатами явно. Обращение этот способ не проверяло, это стандартное поведение curl:

bash
curl --cacert "$HOME/certs/corp-bundle.pem" https://example.internal/health

или через переменную CURL_CA_BUNDLE. В отличие от настройки Codex, curl этим файлом заменяет набор доверенных сертификатов, а не дополняет его. Если часть хостов идёт мимо инспекции, соберите общий файл:

bash
cat /etc/ssl/cert.pem "$HOME/certs/corp-root-ca.pem" > "$HOME/certs/corp-bundle.pem"

Вторая причина — переменная не доходит до команды. Какие переменные окружения Codex передаёт запускаемым процессам, определяет shell_environment_policy в config.toml, поэтому export в вашей оболочке ещё не гарантирует, что npm или curl внутри Codex увидят значение. Надёжнее задать значения явно через ключ set этой политики:

toml
[shell_environment_policy]
set = { NODE_EXTRA_CA_CERTS = "/Users/you/certs/corp-root-ca.pem", CURL_CA_BUNDLE = "/Users/you/certs/corp-bundle.pem" }

NODE_EXTRA_CA_CERTS закрывает npm и остальные инструменты на Node. Остальные ключи политики и порядок их применения — в разделе о расширенной конфигурации; как устроены границы самой песочницы, разобрано в статье «Песочница Codex и config.toml: границы, подтверждения и сеть».

Проверка: попросите Codex выполнить curl -sS -o /dev/null -w "%{http_code}\n" https://registry.npmjs.org/ — в ответе должен быть код HTTP, а не ошибка 60.

Почему NODE_TLS_REJECT_UNAUTHORIZED=0 не исправляет ошибку

NODE_TLS_REJECT_UNAUTHORIZED=0, npm config set strict-ssl false, curl -k и --insecure не добавляют доверие к корпоративному сертификату — они выключают проверку целиком. Процесс после этого примет любой сертификат от любого узла на пути, а не только от прокси вашей компании. Документация Node.js прямо предупреждает, что значение 0 делает TLS-соединения уязвимыми для атаки «человек посередине».

Для Codex цена выше обычной: по этому соединению идут токены доступа (в ~/.codex/auth.json, который документация советует беречь как пароль), исходный код и результаты команд. Переменная, заданная в профиле оболочки, к тому же действует на все процессы Node, а не только на тот, что упал. Файл с корневым сертификатом решает ту же задачу и оставляет проверку включённой.

Две колонки: передача корневого сертификата через CODEX_CA_CERTIFICATE оставляет проверку включённой, NODE_TLS_REJECT_UNAUTHORIZED=0 выключает её и принимает любой сертификат

Когда остановиться и обратиться в ИТ-службу

Остановитесь и передайте вопрос ИТ-службе, если выполняется любое из условий:

  • корневого сертификата нет в системном хранилище и вам его не выдают;
  • издатель в выводе openssl s_client вам незнаком и не относится к компании;
  • сертификат передан нужному процессу, проверка файла проходит, а ошибка остаётся или сменилась отказом прокси;
  • политика компании запрещает менять настройки доверия на рабочем компьютере.

Обходить корпоративные средства защиты не нужно: у ИТ-службы есть два штатных решения — выдать корневой сертификат (и промежуточные, если они есть) или исключить нужные хосты из инспекции. Чтобы обращение решили с первого раза, приложите к нему:

  1. точный текст ошибки и место, где она появилась (CLI, приложение, MCP-сервер, команда в песочнице);
  2. хост из ошибки или журнала;
  3. строки s: и i: из вывода openssl s_client для этого хоста;
  4. версию Codex и операционной системы.

Файл ~/.codex/auth.json и переменные с ключами в обращение не вставляйте.

Короткие ответы об ошибке сертификата в Codex

Почему браузер и curl работают, а Codex выдаёт ошибку сертификата?

Потому что они читают разные хранилища. Браузер и системный curl используют хранилище операционной системы, куда ИТ-служба уже добавила корпоративный корень. Клиент Codex получает дополнительный корневой сертификат через CODEX_CA_CERTIFICATE, Node без NODE_USE_SYSTEM_CA=1 опирается на встроенный список, а команда в песочнице macOS может не дотянуться до связки ключей.

Нужно ли переустанавливать Codex или входить заново?

Переустановка доверие к сертификату не меняет. Повторный вход нужен только после того, как переменная задана: выполните codex login в том же терминале. Если Codex при запуске ждёт и завершается по тайм-ауту, а не ошибкой сертификата, смотрите разбор «Codex не загрузил cloud config bundle за 15 секунд: что проверить».

Почему ошибка сертификата появляется в Codex дома, без прокси?

Проверьте издателя той же командой openssl s_client. Вне корпоративной сети цепочку обычно переподписывает антивирус с проверкой HTTPS либо ошибка относится к вашему собственному шлюзу или MCP-серверу с сертификатом частного CA. В первом случае экспортируйте корневой сертификат антивируса, во втором — корень вашего CA, и передайте файл так же, как описано выше.