Claude Code Network Config: Proxies, mTLS and Domains

At minimum api.anthropic.com, claude.ai, claude.com, platform.claude.com, and registry.npmjs.org if you install through npm or use npx-launched MCP servers. platform.claude.com is needed even for claude.ai sign-ins because OAuth token exchange, refresh and revocation go there. The Datadog telemetry hosts and the Chrome and artifact hosts are optional.
Background agents run under a per-user supervisor process that outlives your shell and inherits the environment of whichever shell cold-started it — and an OS-installed supervisor gets no shell environment at all. Put network variables in the env block of a settings file instead; that is the only configuration that reaches every background session.
No. Claude Code respects the standard HTTPS_PROXY, HTTP_PROXY and NO_PROXY variables, including lowercase variants, but SOCKS proxies are not supported. For proxies requiring advanced authentication such as NTLM or Kerberos, use an LLM gateway service that supports your authentication method.
Only the proxy URL is validated at startup — an unparseable value stops launch with an error naming the variable. Everything else fails later on a request. Run claude --debug and look for the CA certs and mTLS load lines in the debug file. In /status, the mTLS rows appear only when files loaded, but the CA row shows the path without checking it.
Session streaming uses server-sent events over HTTPS, and a proxy in the path must not buffer responses. A buffering proxy holds the stream until it has enough to forward, the byte-level watchdog sees no bytes arriving, and the request is aborted and retried — with no error that points at buffering as the cause.

Key Takeaway
Claude Code reads network settings from environment variables once at startup, so a running session never picks up later shell changes. Only the proxy URL is validated at launch — every other setting fails later on a request. Put these variables in a settings file rather than a shell export, or background agents will not see them.
A corporate proxy configuration that worked perfectly in my terminal did nothing at all for background agents, and it took an embarrassing amount of time to work out why. The supervisor process that hosts background sessions outlives the shell that started it, inherits whichever shell happened to cold-start it, and when installed as a service receives no shell environment at all. My export was reaching exactly one of the places I thought it was.
Enterprise network configuration for Claude Code is mostly a list of variables, and the interesting parts are the three behaviours around them: what actually gets validated when, where the variables have to live to reach everything, and how certificate rotation is picked up. This post covers the domain allowlist, the proxy and TLS variables, the verification path, and the streaming watchdogs that decide when a quiet connection is declared dead.
Two entries here catch out most first allowlists. The Console host is needed even for claude.ai sign-ins, because OAuth token exchange, refresh and revocation all go there — allow only the claude.ai host and authentication works until a token needs refreshing. And the npm registry is needed for plugin installs and any MCP server launched through the npm runner, not just for installing the CLI itself.
# The allowlist. Blocking any of these breaks something
# specific, and the error rarely names the host.
api.anthropic.com API requests, the WebFetch domain safety
check, feature flags, telemetry events
claude.ai claude.ai account authentication
claude.com sign-in page; pre-approved doc lookups
platform.claude.com Console auth AND OAuth token exchange,
refresh and revocation — so claude.ai
sign-ins need it too
mcp-proxy.anthropic.com claude.ai MCP connectors
downloads.claude.ai plugin executables, native installer
and auto-updater
registry.npmjs.org plugin installs, npx-launched MCP
servers, npm/bun installs of the CLI
storage.googleapis.com plugin install counts and metadata
raw.githubusercontent.com the changelog feed for release notes
code.claude.com documentation lookups only
# Optional, and safe to block:
bridge.claudeusercontent.com Claude in Chrome
*.frame.claudeusercontent.com Artifact content reads
http-intake.logs.us5.datadoghq.com operational telemetry
browser-intake-us5-datadoghq.com operational error reports
formulae.brew.sh Homebrew update checksSeveral entries are genuinely optional and safe to drop. The two Datadog intake hosts carry only operational telemetry and error reports, and a single variable disables both. The Chrome bridge and artifact content hosts are only needed for those features. Blocking the documentation host affects documentation lookups and nothing else. Deciding those deliberately gives you a much shorter list to defend.
The variables are standard and mostly boring, which makes the exceptions worth stating plainly: SOCKS proxies are not supported at all, proxies needing NTLM or Kerberos are best handled by an LLM gateway that speaks them rather than by Claude Code, and the operating-system certificate store is only readable on a runtime that exposes it — the native installer always does, npm installs need a recent enough Node.
# Standard variables. Lowercase variants also work; Claude
# Code uses the FIRST one set, in this order:
# https_proxy HTTPS_PROXY http_proxy HTTP_PROXY
HTTPS_PROXY=https://proxy.example.com:8080
NO_PROXY="localhost 192.168.1.1 example.com .example.com"
# Comma-separated also works. NO_PROXY="*" bypasses everything.
# SOCKS proxies are NOT supported.
# For NTLM or Kerberos, use an LLM gateway that speaks them.
# CA trust. Default is both, and reading the OS store needs a
# runtime with tls.getCACertificates — the native installer
# always has it, npm installs need Node 22.15 or later.
CLAUDE_CODE_CERT_STORE=bundled,system # default
NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem
# mTLS
CLAUDE_CODE_CLIENT_CERT=/path/to/client-cert.pem
CLAUDE_CODE_CLIENT_KEY=/path/to/client-key.pem
CLAUDE_CODE_CLIENT_KEY_PASSPHRASE="…"Enterprise TLS-inspection proxies such as Zscaler and CrowdStrike Falcon need no configuration at all, provided their root certificate is in the OS trust store and the runtime can read it. That last clause is the whole troubleshooting path: if inspection is breaking an npm-installed Claude Code and not a native-installed one, the certificate is fine and the Node version is the problem.
Claude Code re-reads the client certificate and key when it applies settings and when a request fails at the connection level, which is a deliberate design with consequences worth knowing:
Only one of these settings is validated when Claude Code reads it. A proxy URL it cannot parse stops launch with an error naming the variable to fix. Everything else — a wrong certificate path, an unreadable key — surfaces as a connection or certificate error on some later request, which is a much worse debugging experience and the reason to verify deliberately rather than by waiting.
# Only ONE of these settings is validated at startup: the
# proxy URL. A value it cannot parse — one missing the scheme,
# say — stops launch with an error naming the variable. Every
# other setting here fails later, on a request.
claude --debug
# Output goes to ~/.claude/debug/<session-id>.txt, NOT the
# terminal. Override with --debug-file <path>. Look for:
#
# CA certs: Appended extra certificates from NODE_EXTRA_CA_CERTS
# mTLS: Loaded client certificate from CLAUDE_CODE_CLIENT_CERT
# mTLS: Loaded client key from CLAUDE_CODE_CLIENT_KEY
/status
# Proxy the active URL; marked invalid if unparseable
# mTLS client cert/key appear ONLY when the files loaded, so a
# missing row means the load failed
# Additional CA cert(s) shows the path WITHOUT checking it loaded —
# confirm this one in the debug logThe status output is not uniformly trustworthy here, and it is worth knowing which rows to believe. The mTLS certificate and key rows appear only when the files actually loaded, so a missing row is meaningful. The additional CA certificate row shows the configured path without checking that the file loaded at all, so a present row proves only that you set the variable. Confirm that one in the debug log.
This is the failure I opened with, and it is structural rather than a bug. Background agents do not run inside the terminal that dispatched them: a per-user supervisor process starts on demand, outlives your shell, and hosts every background session. It inherits the environment of whichever shell started it first, and an OS-installed supervisor receives no shell environment at all.
So a proxy, CA path or mTLS variable exported only in your shell reaches background agents when that shell happened to cold-start the supervisor, and silently does not when a different one did. Every variable on this page can be set in the environment block of a settings file, and settings are the only configuration that reaches every background session on every machine. Use the shell for experiments and the settings file for anything real.
The same structural problem applies to a corporate launcher. The supervisor and its workers start Claude Code from a fixed path rather than looking it up on the path, so a wrapper you place earlier on the path is bypassed by every background agent. There is a dedicated setting for prefixing those processes with your launcher — and after deploying it, stop the running supervisor, because an already-running one keeps the launch configuration it started with.
Claude Code runs independent timers that abort a streaming response that has gone quiet, so a dead connection fails and retries rather than hanging forever. They watch different signals, which is why a stream can survive one and not another.
What each timer watches:
| Timer | Aborts when | Default |
|---|---|---|
| Event-level watchdog | No response events parse | 300 seconds, on every provider |
| Byte-level watchdog | No bytes arrive at all, including keep-alive pings | 180 seconds on the direct API, 300 elsewhere |
| Body idle timeout | No bytes for five minutes | Providers other than the direct API |
One constraint deserves flagging to whoever runs your proxy, because it produces a failure that looks like a Claude Code problem. Session streaming uses server-sent events over HTTPS, and a proxy in the path must not buffer responses. A buffering proxy holds the stream until it has enough to forward, the byte-level watchdog sees nothing arriving, and the request is aborted and retried — repeatedly, with no error that points at buffering.
The same class of subtlety applies to fast mode behind a gateway: its availability check still calls the Anthropic API rather than your gateway base URL. It does honour a configured HTTP proxy, so where a network block is the cause, an allowlist entry in the proxy is the fix. If the check presents a gateway-issued credential that Anthropic rejects, you get the same connectivity error and allowlisting will not help, because nothing is actually blocked.
The rule that would have saved me the afternoon is short: put network variables in a settings file, never in a shell profile, because settings are the only place that reaches every surface including the background supervisor. After that, verify with the debug log rather than the status output, remember that only the proxy URL fails fast, and tell whoever owns your proxy that it must not buffer — that one sentence prevents a class of failure that looks like something else entirely.
Sources & further reading