Skip to content

NO_PROXY Bypass Rules in curl, Requests and HTTPX

Find why a request skips your proxy. Compare NO_PROXY behavior in curl, Requests and HTTPX, with a local reproduction and safe configuration checks.

Mobileproxies.orgUpdated 4 min read

NO_PROXY tells supporting clients which destinations should bypass an environment-configured proxy. Matching and precedence vary by client. curl can bypass an explicitly configured proxy when NO_PROXY matches; Python clients also distinguish environment settings from explicit proxy arguments. Check the process that sends the failing request.

A working request may have skipped the proxy

A regional test that reports your normal IP can still return HTTP 200. One possible cause is a bypass rule matching the destination. The same rule may be intentional for a local health endpoint, so deleting every bypass setting can break other requests.

Record the exact request hostname, whether the proxy came from an environment variable or an explicit client argument, and the client version. Inspect the process that makes the request: a terminal, worker and container may inherit different settings. A browser result does not establish the configuration of your Python worker.

python
import os

for name in (
    'http_proxy', 'https_proxy', 'all_proxy', 'no_proxy',
    'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY',
):
    value = os.environ.get(name)
    state = 'unset' if value is None else ('empty' if value == '' else 'set')
    print(f'{name}: {state}')

This inventory prints presence only. Review the actual bypass rules privately in your process configuration; proxy variable values can contain passwords. It does not detect operating-system proxy settings.

Do not assume the same rules across clients

curl documents http_proxy in lowercase and accepts HTTPS_PROXY and ALL_PROXY. On platforms with case-sensitive environment variables, the uppercase HTTP_PROXY form is deliberately ignored. Use consistent casing in your deployment rather than defining conflicting uppercase and lowercase values. Inspect the application's own documentation before copying a shell configuration into it.

ClientConfiguration detail that changes the diagnosis
curlNO_PROXY can bypass a proxy supplied through --proxy or a configuration file. --noproxy overrides the environment list; an empty value disables that bypass for the invocation.
RequestsThe default environment integration reads proxy and bypass variables. An explicit per-request proxy mapping can remain in use even when the environment bypass list matches.
HTTPXEnvironment configuration is enabled by default. trust_env=False disables it. Set an explicit proxy when you want a fixed proxy route; do not assume an environment bypass list rewrites explicit routing.

References: everything curl: proxy environment variables; Requests: proxies and environment configuration; Requests: bypass and proxy resolution implementation; HTTPX: environment variables; HTTPX: explicit proxy configuration

Write the narrowest rule your request needs

Start with an exact hostname or literal address, then test the destinations that should use the proxy and those that should bypass it. Keep localhost and 127.0.0.1 distinct in your test cases. Avoid a wildcard unless direct routing for all requests is the intended result.

curl documents comma-separated host and domain matches, * for all destinations, and IP ranges in CIDR notation from version 7.86.0. Those details are not a universal grammar for every client. HTTPX also documents URL entries in NO_PROXY. A hostname, host-and-port rule or IP range copied between clients needs its own check.

For example, a bypass intended for an internal health check should not also send your public exit-IP check directly. Test both URLs from the same running service after the configuration change. Save the client version and a redacted rule with the result so the next deploy can reproduce it.

References: everything curl: NO_PROXY matching and CIDR; HTTPX: NO_PROXY syntax

Reproduce an explicit curl proxy being bypassed

Our loopback fixture starts separate local origin and proxy listeners. With curl 8.7.1 on macOS, an explicit proxy in a private configuration file and an empty NO_PROXY value returned the proxy fixture's body. Keeping that configuration and setting NO_PROXY=127.0.0.1 returned the origin fixture's body instead.

Both paths returned a successful HTTP response. The body identified the listener that received the request, which is why a status-only health check would have missed the routing change. The test establishes exact IPv4-address matching for that curl version. It does not test domain suffixes, CIDR ranges or Python-client precedence.

bash
python3 proxy-diagnostics-lab.py --output proxy-lab-results.json

Requires Python 3.9+ and curl. The script binds only to 127.0.0.1, uses disposable fixture settings and never forwards a request externally. Optional Requests timeout checks skip when Requests is unavailable.

Download the local bypass experiment

Make a Python worker's route explicit when needed

For a worker dedicated to proxied requests, configure the proxy on the client and decide deliberately whether it should inherit environment settings. This HTTPX example uses a secret supplied by the runtime and turns environment integration off. Replace the test URL with your authorized endpoint.

python
import os
import httpx

with httpx.Client(
    proxy=os.environ['APP_PROXY_URL'],
    trust_env=False,
    timeout=10.0,
) as client:
    response = client.get('https://your-test-host.example/')
    print(response.status_code)

trust_env=False also prevents HTTPX from using environment-based certificate settings such as SSL_CERT_FILE. If your deployment needs a private CA, supply an explicit SSL context instead of disabling certificate verification. Confirm the route with your test endpoint; HTTP 200 alone does not identify the exit IP.

References: HTTPX: environment proxy and certificate settings; HTTPX: explicit proxy configuration

Sources and further reading