Skip to content

fix: send all requests through the configured HTTP proxy - #10013

Draft
kuldeepsinh19 wants to merge 1 commit into
netlify:mainfrom
kuldeepsinh19:fix/3115-proxy-for-fetch
Draft

kuldeepsinh19 wants to merge 1 commit into
netlify:mainfrom
kuldeepsinh19:fix/3115-proxy-for-fetch

Conversation

@kuldeepsinh19

Copy link
Copy Markdown

Summary

Fixes #3115

On a network where the internet is only reachable through a proxy, even netlify status fails (see #3115 (comment)):

Warning: Error: Failed retrieving extensions for site : fetch failed.
    at getExtensions (@netlify/config/lib/api/site_info.js)
Warning: Failed to resolve config, falling back to offline resolution

--http-proxy (which defaults to HTTP_PROXY/HTTPS_PROXY) is only passed as an HttpsProxyAgent to the CLI's own Netlify API client. Every other request bypasses the proxy:

  1. Built-in fetch() ignores both the agent option and the proxy environment variables. It's used by @netlify/config (site extensions) and by about 35 of the CLI's own calls (deploy, logs, db, functions:create, live tunnel, …).
  2. http/https requests without an agent use Node's default global agent. That includes the separate Netlify API client @netlify/config creates for the site info (@netlify/api uses node-fetch). resolveConfig() has no option to pass an agent, so this can't be fixed by passing ours through.

When a proxy is configured, getAgent() now also sets:

  • an undici EnvHttpProxyAgent as the global dispatcher, for case 1;
  • https.globalAgent to an HttpsProxyAgent subclass that connects directly to hosts it shouldn't proxy, for case 2.

Both:

  • use the same proxy URL and --http-proxy-certificate-filename CA as the existing agent;
  • respect NO_PROXY/no_proxy, with the same matching rules as undici;
  • never proxy requests to the local machine (localhost, 127.0.0.1, [::1]), so the framework server and functions server in netlify dev are unaffected.

Nothing changes when no proxy is configured.

Notes:

  • undici was already in the lockfile (7.30.1, through cheerio) as a dev dependency. It's now a direct dependency at the same version, so the lockfile diff only drops "dev": true. I didn't use NODE_USE_ENV_PROXY/http.setGlobalProxyFromEnv() because they aren't available on all Node versions in engines (>=22.13.0).
  • Behavior change to call out: under netlify dev with a proxy configured, outgoing fetch()/https calls from function code that runs in the CLI's process also go through the proxy (except local and NO_PROXY hosts). That's what users behind a proxy need, but it's a change.
  • I left the existing API client agent (HttpsProxyAgentWithCA) as it is. It still doesn't apply NO_PROXY, as before. Its callback() override is never called with https-proxy-agent v8: agent-base only calls connect(). So --http-proxy-certificate-filename currently doesn't apply to that client. I'm happy to fix that in a follow-up.

Verification

I recreated the issue's network in a container: /etc/hosts points api.netlify.com and api.netlifysdk.com at a closed port, so they can only be reached through a logging proxy (which resolves them with real DNS). Then I ran HTTP_PROXY=… netlify status --debug with the built CLI and a dummy token:

main this PR
@netlify/config site info request to https://api.netlify.com/api/v1/sites/… failed, reason: connect ECONNREFUSED reaches the API (Unauthorized with the dummy token)
@netlify/config extensions not proxied proxied (CONNECT api.netlifysdk.com:443)
CLI API client proxied proxied

Tests in tests/unit/lib/http-agent.test.ts (with a local proxy that records requests):

  • After getAgent(), a global fetch() goes through the proxy. This fails on main.
  • After getAgent(), an https request without an agent (node-fetch) goes through the proxy. This fails on main.
  • Requests to localhost don't go through the proxy.
  • NO_PROXY hosts and their subdomains don't go through the proxy, for both fetch() and https.

npm run test:unit (846 tests), npm run typecheck, eslint (no new suppressions) and oxfmt --check pass. The new tests also pass on Node 22.13.0. I didn't run the integration suites.

This change was written with help from an AI coding assistant (Claude Code). I've reviewed every line and can explain any of it.


  • Open a bug/issue before writing your code (Proxy support is broken #3115)
  • Read the contribution guidelines
  • Update or add tests
  • Update or add documentation (no docs change needed)
  • Make sure the status checks below are successful

`--http-proxy` (which defaults to `HTTP_PROXY`/`HTTPS_PROXY`) was only
passed to the CLI's Netlify API client. Every other request bypassed the
proxy and failed on networks that require one:

- Node.js's built-in `fetch()` ignores both the `agent` option and the
  proxy environment variables. It's used by `@netlify/config` to fetch
  the site's extensions and by the CLI's own `fetch()` calls.
- `http`/`https` requests that don't set an agent, such as those made by
  the Netlify API client that `@netlify/config` creates to fetch the
  site info, use the default global agent.

When a proxy is configured, also install an undici `EnvHttpProxyAgent`
as the global dispatcher and a proxy agent as `https.globalAgent`. Both
use the same proxy URL and CA certificate, respect `NO_PROXY` (with the
same matching rules), and never proxy requests to the local machine.

Fixes netlify#3115
@coderabbitai

coderabbitai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proxy support is broken

1 participant