Selective proxy bypass routing

Proxy environment variables make automation convenient, but one broad NO_PROXY value can silently send traffic outside the intended proxy path. That can expose the client network, break regional testing, bypass monitoring, or make production behavior differ from CI.

The goal is not to bypass as much as possible. It is to define the smallest direct-access list that the application genuinely requires, then verify it with the exact runtime and version used in production.

What NO_PROXY does

HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY select a proxy. NO_PROXY or no_proxy lists destinations that should be contacted directly. A typical value is a comma-separated set of hosts, domain suffixes, IP addresses, and—in clients that support them—ports or CIDR networks.

export HTTPS_PROXY="$PROXY_ENDPOINT"
export NO_PROXY="localhost,127.0.0.1,.internal.example,10.0.0.0/8"

The example uses placeholders and private ranges. Keep working credentials in a protected secret store, not in shell files or documentation.

Exact host versus domain suffix

An exact hostname should bypass only that host. A domain suffix can affect every subdomain. Client implementations differ in how they interpret a leading dot and whether a bare domain also matches subdomains, so never assume identical behavior across curl, Python, Go, Java, browsers, and containers.

Test all three cases explicitly:

  • the parent domain;
  • one expected subdomain;
  • one unrelated lookalike domain.

Avoid broad fragments that could match more hosts than intended. Normalize capitalization and trailing dots before comparing results.

Ports matter

Some runtimes allow host:port entries, while others match only the hostname. A service might need direct access on one internal port but proxy access on another. Verify behavior with the actual library instead of treating a configuration copied from another language as portable.

Document whether the destination URL uses a default or explicit port. Redirects can also move a request to a different host or port and change the bypass decision.

IP addresses and CIDR

Modern curl versions support numeric IP addresses and CIDR ranges in NO_PROXY. A private network such as 10.0.0.0/8 can be concise, but it is also a large bypass. Use the narrowest subnet possible and confirm that the deployed curl version supports CIDR matching.

IPv6 literal handling also varies. curl expects numerical IPv6 entries without URL brackets in NO_PROXY. Zone identifiers, mapped addresses, and hostname-to-IP resolution can complicate comparisons. Test IPv4 and IPv6 separately.

DNS changes the result

A hostname rule is not always equivalent to an IP rule. The client may compare the hostname before resolution, or it may evaluate a resolved address depending on the library. A hostname can also resolve differently in local development, CI, and production.

Record the original hostname, chosen address family, and final route without logging credentials. When a destination uses frequently changing addresses, prefer a precise hostname rule if the runtime supports the required semantics.

Security risks of broad bypasses

An overbroad NO_PROXY can:

  • expose the source network to destinations expected to see only a proxy exit;
  • bypass corporate inspection or egress controls;
  • let untrusted input select a direct destination;
  • make SSRF protections inconsistent;
  • cause geographic tests to use the client location;
  • create different behavior between workers.

Treat proxy bypass lists as security configuration. Review changes, assign an owner, and do not accept wildcard entries without a documented reason.

A repeatable validation workflow

1. Inventory required direct destinations

List internal APIs, metadata services, health endpoints, loopback addresses, and private networks that truly cannot use the proxy. Remove entries added only to silence an old error.

2. Build a route matrix

For each rule, test an intended match, an intended non-match, the parent domain, a subdomain, IPv4, IPv6, and any relevant port.

3. Observe the route

Use redacted verbose logs, proxy access logs, or a controlled test endpoint. The authoritative signal is whether the proxy received the request—not merely whether the request succeeded.

4. Test every runtime

Run the matrix in curl, application code, containers, CI workers, and browser automation where applicable. Environment-variable casing and precedence can differ by platform.

5. Add regression tests

Turn the matrix into automated tests. Fail deployment if a destination unexpectedly switches between proxy and direct routing.

Common mistakes

Setting NO_PROXY=*

An asterisk commonly disables proxy use for all destinations. Use it only for deliberate diagnostics in a controlled environment, never as a routine fix.

Assuming uppercase and lowercase are identical

Precedence varies. curl treats lowercase http_proxy specially, while other clients may prefer uppercase or platform-specific settings. Remove conflicting duplicates.

Copying one language's syntax to another

Python, Go, curl, Java, and browser tooling do not guarantee identical suffix, port, IPv6, or CIDR behavior. Validate per client.

Testing success instead of route

A request can succeed both directly and through the proxy. Confirm the actual path using proxy logs or controlled network observation.

Production checklist

  • Every bypass entry has an owner and reason.
  • Domain rules are tested against expected and lookalike hosts.
  • Port-specific behavior is verified.
  • CIDR ranges are minimal and supported by the deployed client.
  • IPv4 and IPv6 are tested separately.
  • Uppercase and lowercase variables do not conflict.
  • Redirect destinations are included in tests.
  • Credentials never appear in configuration output.
  • Route tests run in development, CI, and production-like environments.
  • Use complies with applicable law, target terms, and organizational policy.

For controlled proxy routing and regional testing, review the available configuration information on 98IP. Keep bypasses narrow, observable, and covered by regression tests.

Research basis: curl environment and --noproxy documentation; Python urllib.request proxy documentation; Go proxy environment implementation documentation. Source names are listed without external links.