Claude Media
Claude CodeでCNTLMプロキシ経由が接続拒否になるときの切り分け

Claude CodeでCNTLMプロキシ経由が接続拒否になるときの切り分け

WindowsでCNTLMを通すとVS Code拡張は動くのにCLIだけConnection refusedになる報告があります。症状の整理と、PowerShellでの切り分け手順をまとめます。

Claude CodeでCNTLMプロキシ経由が接続拒否になるときの切り分け

WindowsでCNTLMを使う社内プロキシ環境では、Claude Codeの扱いが公式の説明から少しずれます。VS Code拡張は動くのにターミナルのCLIだけ「Connection refused」で止まる報告があり、原因は特定されていません。この記事は、その報告の中身と、手元で原因を絞り込む手順を扱います。

CNTLMはClaude Codeから見るとただのHTTPプロキシ

CNTLMは、NTLM認証を要求する社内プロキシの前に置く、ローカルの中継プログラムです。クライアントは127.0.0.1の待ち受けポートへ普通のHTTPプロキシとして接続し、NTLMの認証は中継側が肩代わりします。

Claude Codeの公式ドキュメントは、NTLMやKerberosのような高度な認証を要するプロキシについて、対応する認証方式を持つLLMゲートウェイの利用を検討するよう書いています。ネットワーク設定のページにCNTLMの記載はありません。

つまりCNTLMを挟む構成は、Claude Codeが直接NTLMを話す形ではなく、「ローカルの素のHTTPプロキシをHTTPS_PROXYで指す」形になります。設定の書き方自体は、通常のプロキシと変わりません。

報告されている症状

GitHubのissue 98367(2026年9月30日起票、open、コメントなし)に、次の構成が報告されています。

issue 98367

報告された環境と症状

  • 環境

    Windows 11 Enterprise、Claude Code v2.1.267、PowerShell。CNTLMが127.0.0.1:3128で待ち受けています。

  • 動くもの

    VS Code拡張は、claudeCode.environmentVariablesにプロキシを設定すると接続できます。Invoke-WebRequestに-Proxyを付けてapi.anthropic.comを叩くと、404が返ります。

  • 動かないもの

    同じ端末・同じ環境変数でclaudeを起動すると、再試行10回のあとに「Connection refused — a firewall or proxy may be blocking it」で止まります。

報告者はHTTP_PROXYとHTTPS_PROXYにhttp://127.0.0.1:3128を入れ、社内CAのバンドルをNODE_EXTRA_CA_CERTSに指定し、Test-NetConnectionでポートの疎通も確かめています。NODE_TLS_REJECT_UNAUTHORIZED=0も試して変わりませんでした。報告者の見立ては「CLIがプロキシ変数を使っていない、あるいは拡張と別の接続経路を使っている」です。

issueには、直近で動いていた版の記載がありません。回帰かどうかの欄は「はい」ですが、原因や修正版は示されていません。以下の手順は、この報告に当てはまるかを手元で確かめるためのもので、原因を断定するものではありません。

「Connection refused」の文言から分かること

Claude Codeの接続エラーは、失敗の種類ごとに文言が分かれています。

表示意味
Connection refused — a firewall or proxy may be blocking it意味TCP接続そのものが拒否された
Couldn't connect through your proxy (ERR_PROXY_TUNNEL)意味プロキシはあるが、トンネルを拒否された
Can't reach the API server (ENOTFOUND)意味名前解決に失敗した
Connection dropped (ECONNRESET)意味接続が途中で切れた

報告のメッセージは1行目、つまり接続の拒否です。プロキシに届いたうえで認証や許可で弾かれたなら、2行目のERR_PROXY_TUNNELが出る作りになっています。ここから考えられる分岐は2つです。

  • プロキシへ向かっていない: プロキシ変数がclaudeのプロセスに届かず、api.anthropic.comへ直接つなぎに行って拒否されている
  • プロキシのポートで拒否されている: 向き先は正しいが、そのアドレスとポートで待ち受けがない

どちらかを分けるのが、次の手順の目的です。NODE_TLS_REJECT_UNAUTHORIZEDやNODE_EXTRA_CA_CERTSはTLSの段階の設定なので、TCP接続が拒否される段階の問題には効きません。

PowerShellで切り分ける手順

1. プロキシが生きているかを、curlで直接確かめる

PowerShellではcurlがInvoke-WebRequestの別名になるため、curl.exeと拡張子付きで呼びます。-xでプロキシを指定すると、CNTLM経由の経路が通るかを、Claude Codeを使わずに確認できます。

curl.exe -x http://127.0.0.1:3128 -I https://api.anthropic.com
Test-NetConnection 127.0.0.1 -Port 3128

ここで失敗するなら、Claude Code以前の問題です。CNTLMの起動状態と待ち受けアドレスを見直します。報告者のように成功するなら、プロキシ自体は無実です。

2. 失敗する端末で、変数が見えているかを確かめる

環境変数は、設定したあとに開き直した端末にしか届きません。claudeを起動するのと同じウィンドウで確認します。

$env:HTTPS_PROXY
$env:HTTP_PROXY
$env:NO_PROXY
$env:ANTHROPIC_BASE_URL

ANTHROPIC_BASE_URLに値があると、リクエストの宛先がそちらに変わります。死んだローカルアドレスを指す値が残っていると、プロキシ設定とは無関係に接続拒否になります。この罠はConnection refusedの原因と切り分けで詳しく扱っています。

3. Claude Codeが読んだプロキシを、/statusで見る

claudeを起動し、/statusのProxy行を見ます。公式ドキュメントによると、この行は有効なプロキシのURLを示し、解釈できない値は「無効で無視された」と表示されます。ここが空なら、変数はclaudeのプロセスに届いていません。http://127.0.0.1:3128が出ていれば、向き先は正しく読まれています。

4. デバッグログで接続の失敗を見る

claude --debug-file $env:TEMP\claude-debug.txt

--debug-fileを付けると、ログの出力先を指定できます。付けない場合は~/.claude/debug/<session-id>.txtに書かれます。公式ドキュメントが挙げる確認行は、証明書の読み込みを示すCA certs: Appended extra certificates from NODE_EXTRA_CA_CERTSのような行です。社内CAのバンドルが読めているかは、ここで分かります。

変数の置き場所を、シェルから設定ファイルへ移す

VS Code拡張が動いた設定は、環境変数をシェルではなく拡張の設定に書く形でした。CLI側でも同じ発想で、変数を~/.claude/settings.jsonのenvブロックに置けます。公式ドキュメントは、ネットワーク関連の変数をこのブロックに置けると説明しています。シェルの継承に頼らないので、端末ごとの差が出にくくなります。

{
  "env": {
    "HTTPS_PROXY": "http://127.0.0.1:3128",
    "HTTP_PROXY": "http://127.0.0.1:3128",
    "NO_PROXY": "localhost,127.0.0.1"
  }
}

書き換えたあとはclaudeを起動し直し、/statusのProxy行で反映を確かめます。バックグラウンドエージェントを使う場合は、シェルのexportだけでは届かないことがあり、公式ドキュメントも設定ファイルへの記載を勧めています。プロキシ周りの設定全体はClaude Codeのプロキシ設定にまとめています。

変数が複数あるときの優先順位に注意する

プロキシ変数は大文字だけでなく小文字も読まれます。公式ドキュメントによると、Claude Codeはhttps_proxy、HTTPS_PROXY、http_proxy、HTTP_PROXYの順で、最初に設定されているものを使います。

社内の配布設定や過去の試行で、小文字のhttps_proxyが別のアドレスで残っていると、新しく設定したHTTPS_PROXYより先に採用されます。報告者は大文字の2変数を確認していますが、小文字の変数についての記載はありません。手順2の確認に、小文字も加えておくと漏れがありません。

Get-ChildItem Env: | Where-Object Name -like "*proxy*"

この1行で、大文字小文字を問わずプロキシ関連の変数が一覧できます。値が2種類見つかったら、使われる側の順位を上の表記順で確かめます。

また、プロキシのURLにhttp://のようなスキームを付けず127.0.0.1:3128とだけ書くと、起動時に変数名つきのエラーで止まります。今回の症状は起動後の接続拒否なので、こちらとは別の問題です。

バージョンを上げて、同じ症状かを見直す

issueの環境はv2.1.267です。changelogには、その後の版で次のような修正が入っています。

  • v2.1.292: HTTPS_PROXYを設定していると、Claude Code自身のAPIリクエスト(サインインなど)でNO_PROXYが無視される不具合を修正

この修正がissueの症状と同じ原因かは、記載がありません。ただし、プロキシ周りの修正は版を追って入っています。claude --versionで版を確かめ、古ければ更新してから、上の手順をもう一度試す価値があります。

それでも直らないとき

手順1が成功し、手順3でProxy行も正しいのにCLIだけが失敗する場合は、issue 98367と同じ状況です。次の2点を持ち寄ると、報告が前に進みやすくなります。

  • claude --versionと、/statusのProxy行の表示
  • デバッグログの接続失敗の行(ホスト名やユーザー名は伏せる)

当面の回避策としては、公式ドキュメントの案内どおり、NTLMなどの認証をゲートウェイ側で受けるLLMゲートウェイを立てる方法があります。社内に既存のゲートウェイがあるなら、ANTHROPIC_BASE_URLでそこを指す形です。

よくある質問

CNTLMの設定ファイルはどう書けばよいですか

CNTLM自体の設定は、Claude Codeの公式ドキュメントの範囲外です。Claude Code側に必要なのは、CNTLMが待ち受けているアドレスとポートをHTTPS_PROXYに書くことだけです。

VS Code拡張で動くのに、CLIで動かないのはなぜですか

報告では、拡張はclaudeCode.environmentVariablesに設定した変数で動いています。CLI側は端末の環境変数を使うので、変数がclaudeのプロセスに届いているかを/statusで確かめるのが最初の一手です。

まとめ

CNTLMを挟む構成では、Claude Codeは通常のHTTPプロキシと同じ扱いで、ドキュメントにCNTLM固有の手順はありません。「Connection refused」が出たら、curl.exe -xでプロキシの生死を、/statusのProxy行でClaude Codeが何を読んだかを確かめると、「プロキシに向かっていない」と「向かった先で拒否された」を分けられます。issue 98367の原因は未特定なので、直らない場合は版とログを添えて報告するのが確実です。

この記事を共有:XはてブLinkedIn