openclaw - ✅(Solved) Fix Feature: Add global HTTP proxy support via environment variables [1 pull requests, 3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#43821Fetched 2026-04-08 00:18:25
View on GitHub
Comments
3
Participants
3
Timeline
8
Reactions
0
Author
Timeline (top)
commented ×3referenced ×2subscribed ×2cross-referenced ×1

Add comprehensive HTTP proxy support for all network requests made by OpenClaw, configurable through standard environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY).

Root Cause

Add comprehensive HTTP proxy support for all network requests made by OpenClaw, configurable through standard environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY).

Fix Action

Fixed

PR fix notes

PR #43919: Fix/global proxy dispatcher

Description (problem / solution / changelog)

Summary

  • Problem: LLM inference requests time out when the gateway runs behind a proxy (HTTP_PROXY / HTTPS_PROXY / ALL_PROXY), because Node.js 22+'s globalThis.fetch (undici) does not read proxy env vars by default, and the upstream streamSimple in @mariozechner/pi-ai does not accept a dispatcher parameter.
  • Why it matters: Users in corporate firewalls, and other restricted networks cannot use OpenClaw for LLM inference at all — the only working path (curl -x) proves the proxy itself is fine.
  • What changed: Added applyGlobalProxyDispatcher() in src/infra/net/global-proxy.ts that calls setGlobalDispatcher(new EnvHttpProxyAgent()) early in gateway startup (after dotenv loading), making all globalThis.fetch calls proxy-aware. Added ALL_PROXY / socks5:// / socks5h:// normalization in src/infra/net/proxy-env.ts. 17 unit tests.
  • What did NOT change (scope boundary): No modifications to existing Telegram, WhatsApp, media-understanding, or web-tools proxy log.

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #20549
  • Closes #43821
  • Related #43629, #27228, #30075
  • Complements #43248 (merged) — see Relationship with #43248 below

User-visible / Behavior Changes

  • When HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY env vars are set, LLM inference requests now route through the proxy instead of timing out.
  • [net/global-proxy] global undici dispatcher set to EnvHttpProxyAgent (via ...) log line appears at startup when proxy is active.
  • ALL_PROXY with socks5:// or socks5h:// is rewritten to http:// for undici compatibility (most local proxy tools like Clash/V2Ray accept HTTP CONNECT on the same port).
  • NO_PROXY / no_proxy exclusions are respected — localhost services (Ollama, browser control, canvas host) are not affected.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? Yes — existing globalThis.fetch calls are now routed through the user-configured proxy when env vars are set. No new outbound calls are introduced.
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: The proxy dispatcher only activates when the user explicitly sets proxy env vars. EnvHttpProxyAgent respects NO_PROXY exclusions, so internal/localhost traffic is unaffected. If EnvHttpProxyAgent construction fails (e.g. malformed URL), the error is logged and the gateway continues with direct connections.

Repro + Verification

Environment

  • OS: macOS (Darwin 25.2.0), also affects Linux
  • Runtime/container: Node.js 22+
  • Model/provider: Any (Google Gemini, Anthropic, OpenAI-compatible)
  • Integration/channel (if any): All channels — the fix is at the global fetch layer
  • Relevant config (redacted): HTTP_PROXY=http://127.0.0.1:7897 HTTPS_PROXY=http://127.0.0.1:7897 ALL_PROXY=socks5://127.0.0.1:7897

Steps

  1. Be in a network where direct connections to LLM APIs are blocked (common in China, corporate firewalls)
  2. Start gateway: env HTTP_PROXY="http://127.0.0.1:7897" HTTPS_PROXY="http://127.0.0.1:7897" openclaw gateway
  3. Send any message that triggers LLM inference

Expected

  • LLM inference requests succeed through the proxy
  • [net/global-proxy] global undici dispatcher set to EnvHttpProxyAgent (via HTTP_PROXY) in startup log

Actual (before fix)

  • Repeated LLM request timed out errors, even though curl -x http://127.0.0.1:7897 https://generativelanguage.googleapis.com/... succeeds

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Unit tests (17 cases, all passing):

✓ sets global dispatcher when HTTPS_PROXY is set
✓ sets global dispatcher when HTTP_PROXY is set
✓ sets global dispatcher when ALL_PROXY is set
✓ rewrites socks5:// ALL_PROXY to http:// for EnvHttpProxyAgent compatibility
✓ rewrites socks5h:// ALL_PROXY to http:// for EnvHttpProxyAgent compatibility
✓ passes http:// ALL_PROXY as-is
✓ passes all_proxy (lowercase) as explicit httpProxy/httpsProxy
✓ prefers lowercase all_proxy over uppercase ALL_PROXY
✓ does not pass explicit options when HTTP_PROXY is also set alongside ALL_PROXY
✓ does not pass explicit options when HTTPS_PROXY is set (no ALL_PROXY fallback needed)
✓ sets global dispatcher when lowercase proxy vars are set
✓ is a no-op when no proxy env var is set
✓ only applies once even if called multiple times
✓ skips if a proxy-like dispatcher is already installed
✓ does not skip if existing dispatcher is not proxy-like
✓ handles EnvHttpProxyAgent constructor failure gracefully

Regression tests pass with zero regressions:

  • src/infra/net/proxy-fetch.test.ts — 7/7 passed
  • src/infra/net/fetch-guard.ssrf.test.ts — 9/9 passed

Startup log confirming proxy activation:

2026-03-13T14:56:08.218+08:00 [net/global-proxy] global undici dispatcher set to EnvHttpProxyAgent (via HTTP_PROXY)

Human Verification

  • Verified scenarios:
    • Built and installed locally via npm link (OpenClaw 2026.3.13, commit 2b46c4c)
    • Started gateway with env OPENCLAW_DISABLE_BONJOUR=1 HTTP_PROXY="http://127.0.0.1:7897" HTTPS_PROXY="http://127.0.0.1:7897" ALL_PROXY="socks5://127.0.0.1:7897" openclaw gateway run --force
    • Confirmed [net/global-proxy] global undici dispatcher set to EnvHttpProxyAgent (via HTTP_PROXY) in startup log
    • Gateway started successfully, all channels connected, subagent dispatch unaffected
    • Localhost services (browser control on :18791, canvas host) remain accessible without proxy interference
  • Edge cases checked:
    • socks5h:// protocol variant (was broken by original regex, now fixed)
    • ALL_PROXY-only configuration (no HTTP_PROXY/HTTPS_PROXY set)
    • Idempotent re-invocation (safe to call multiple times)
    • Cooperative skip when another proxy dispatcher is already installed
    • Graceful failure on malformed proxy URL
  • What I did not verify:
    • Windows-specific behavior (lowercase vs uppercase env var precedence)
    • SOCKS-only proxy endpoints that do not accept HTTP CONNECT on the same port

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No — uses existing standard proxy env vars (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY)
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Remove the applyGlobalProxyDispatcher() call in src/gateway/server.impl.ts (single line). Or simply unset proxy env vars — the function is a no-op without them.
  • Files/config to restore: src/gateway/server.impl.ts (remove import + call)
  • Known bad symptoms reviewers should watch for: If a SOCKS-only proxy does not accept HTTP CONNECT, the rewrite from socks5:// to http:// will cause connection failures. Users would see fetch errors instead of timeouts.

Risks and Mitigations

  • Risk: SOCKS5-to-HTTP rewrite assumes the proxy accepts HTTP CONNECT on the same port.
    • Mitigation: This is true for all major local proxy tools (Clash, V2Ray, Shadowsocks, Surge). For truly SOCKS-only endpoints, the connection will fail at connect time with a clear error, which is still better than silently timing out.
  • Risk: Global dispatcher affects all globalThis.fetch calls process-wide.
    • Mitigation: This is intentional — the whole point is to cover streamSimple which only uses globalThis.fetch. EnvHttpProxyAgent respects NO_PROXY so internal traffic is excluded. The function is cooperative (skips if a proxy dispatcher is already installed) and idempotent.

Comparison with existing open PRs

PRApproachLimitations
#33990ProxyAgent in server-startup.tsDoes not respect NO_PROXY; modifies Telegram code
#42320EnvHttpProxyAgent in undici-global-dispatcher.tsOnly covers embedded runner path, not startup/heartbeat/web-search
#41455Similar to #42320Excludes ALL_PROXY; only covers embedded runner

Files changed

  • src/infra/net/global-proxy.ts — New module: applyGlobalProxyDispatcher() + test reset helper
  • src/infra/net/global-proxy.test.ts — 17 unit tests
  • src/infra/net/proxy-env.ts — Added resolveAllProxyFallbackOptions(), SOCKS protocol normalization (builds on resolveEnvHttpProxyUrl / hasEnvHttpProxyConfigured from #43248)
  • src/gateway/server.impl.ts — Import and call applyGlobalProxyDispatcher() after readConfigFileSnapshot()

Relationship with #43248

#43248 (merged 2026-03-11) added ensureGlobalUndiciEnvProxyDispatcher() in undici-global-dispatcher.ts, called inside the embedded runner's runEmbeddedAttempt(). This PR complements it with two things #43248 does not cover:

#43248 (merged)This PR
Injection pointrunEmbeddedAttempt() — per-run, embedded runner onlystartGatewayServer() — once at gateway startup, covers all fetch paths
CoverageModel traffic via embedded runnerAll globalThis.fetch: LLM inference, heartbeat, web search, usage tracking, etc.
ALL_PROXY supportNo — explicitly excludedYes — resolveAllProxyFallbackOptions() bridges undici's EnvHttpProxyAgent gap
SOCKS protocolNoYes — socks5://, socks5h://, socks4:// rewritten to http://
dotenv timingN/A (runs after config is loaded)Explicitly placed after readConfigFileSnapshot() so .env-defined proxy vars are visible

This PR reuses the resolveEnvHttpProxyUrl and hasEnvHttpProxyConfigured helpers that #43248 added to proxy-env.ts, and adds resolveAllProxyFallbackOptions() on top for the ALL_PROXY/SOCKS gap.

Changed files

  • src/gateway/server.impl.ts (modified, +9/-0)
  • src/infra/net/global-proxy.test.ts (added, +276/-0)
  • src/infra/net/global-proxy.ts (added, +120/-0)
  • src/infra/net/proxy-env.ts (modified, +114/-0)

Code Example

export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.local,.internal
openclaw gateway run
RAW_BUFFERClick to expand / collapse

Feature Request

Summary

Add comprehensive HTTP proxy support for all network requests made by OpenClaw, configurable through standard environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY).

Motivation

Many enterprise and restricted network environments require HTTP/HTTPS proxies for external internet access. Currently, OpenClaw does not respect standard proxy environment variables, making it difficult to deploy in such environments without manual proxy configuration for each service.

Proposed Solution

Implement global proxy support that:

  1. Reads standard proxy environment variables (HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy)
  2. Supports NO_PROXY bypass rules for local/internal services
  3. Uses undici's ProxyAgent for consistent proxy handling across all HTTP requests
  4. Automatically applies to web fetch, web search, and all external API calls
  5. Validates proxy URL format and logs warnings for misconfigurations

Benefits

  • Enterprise Compatibility: Works seamlessly in corporate proxy environments
  • Zero Configuration: Respects existing environment variable conventions
  • Consistent Behavior: All network operations honor proxy settings automatically
  • Debugging Friendly: Clear logging for proxy configuration issues
  • Standard Compliant: Follows Unix/Linux proxy environment variable conventions

Use Cases

  • Corporate networks requiring HTTP proxy for internet access
  • Deployments behind application-level proxies
  • Testing and debugging through proxy tools (Burp, Charles, etc.)
  • Geographically restricted content access
  • Network monitoring and traffic analysis

Implementation Details

The implementation includes:

  • src/infra/net/proxy.ts: Core proxy resolution and agent creation
  • src/infra/net/bootstrap.ts: Bootstrap logic for global proxy setup
  • src/infra/net/proxy.test.ts: Comprehensive test coverage
  • Integration with existing fetch infrastructure
  • Support for multiple proxy protocols (http, https, socks4, socks5)

Configuration Example

export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.local,.internal
openclaw gateway run

Alternatives Considered

  1. Per-service proxy configuration: Rejected due to complexity
  2. Config file only: Rejected to maintain consistency with standard tools
  3. No proxy support: Not viable for enterprise deployments

Additional Context

This feature is particularly important for:

  • Users in China/Great Firewall regions
  • Enterprise environments with mandatory proxy requirements
  • Educational institutions with network restrictions
  • Any deployment requiring traffic monitoring/filtering

The implementation is backward compatible and only activates when proxy environment variables are explicitly set.

extent analysis

Fix: Add Global HTTP/HTTPS Proxy Support (undici ProxyAgent)

1. Create a proxy helper (src/infra/net/proxy.ts)

// src/infra/net/proxy.ts
import { ProxyAgent } from 'undici';
import { URL } from 'url';
import { logger } from '../logger';

type ProxyConfig = {
  http?: ProxyAgent;
  https?: ProxyAgent;
  noProxy: Set<string>;
};

/**
 * Parse a proxy URL from env and return a ProxyAgent.
 * Returns undefined if the variable is missing or malformed.
 */
function buildAgent(envVar: string | undefined, protocol: 'http:' | 'https:'): ProxyAgent | undefined {
  if (!envVar) return undefined;
  try {
    const url = new URL(envVar);
    // undici only needs the full URL string
    return new ProxyAgent({ uri: url.toString(), connect: { timeout: 10_000 } });
  } catch (e) {
    logger.warn(`Invalid ${protocol} proxy URL "${envVar}": ${(e as Error).message}`);
    return undefined;
  }
}

/**
 * Build a singleton proxy configuration from the process environment.
 */
export const proxyConfig: ProxyConfig = (() => {
  const httpAgent = buildAgent(process.env.HTTP_PROXY ?? process.env.http_proxy, 'http:');
  const httpsAgent = buildAgent(process.env.HTTPS_PROXY ?? process.env.https_proxy, 'https:');

  const noProxyRaw = process.env.NO_PROXY ?? process.env.no_proxy ?? '';
  const noProxy = new Set(
    noProxyRaw
      .split(',')
      .map((s) => s.trim())
      .filter(Boolean)
  );

  logger.info('Proxy configuration loaded', {
    http: !!httpAgent,
    https: !!httpsAgent,
    noProxy: Array.from(noProxy),
  });

  return { http: httpAgent, https: httpsAgent, noProxy };
})();

/**
 * Decide which agent to use for a given request URL.
 * Returns undefined for direct connections.
 */
export function resolveAgent(target: string | URL): ProxyAgent | undefined {
  const url = typeof target === 'string' ? new URL(target) : target;

  // NO_PROXY handling – exact host or suffix match (".example.com")
  const host = url.hostname;
  for (const rule of proxyConfig.noProxy) {
    if (rule === host) return undefined;
    if (rule.startsWith('.') && host.endsWith(rule)) return undefined;
    if (rule === '*

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Feature: Add global HTTP proxy support via environment variables [1 pull requests, 3 comments, 3 participants]