We use cookies to enhance user experience, personalize content, and analyze traffic. Cookie Policy

← Back to all articles

Python Requests No Proxy: Bypass Proxy Settings

Use Python Requests no proxy settings to bypass inherited proxy variables, configure NO_PROXY, and verify direct connections without weakening TLS.

by Unknown Proxies

11 min read

September 4, 2026

Python Requests No Proxy: Bypass Proxy Settings

A Python Requests no proxy setup requires more than omitting the proxies argument when your shell, operating system, container, or CI runner defines proxy environment variables. For a reliably direct Requests session, create a Session and set trust_env to False:

import requests

session = requests.Session()
session.trust_env = False

response = session.get("https://example.com", timeout=(5, 20))
response.raise_for_status()

This prevents that session from importing HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY from its process environment. It also disables other environment-derived behavior, including .netrc authentication and the REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE certificate paths, so account for those settings explicitly if your application needs them.

Decision flow showing how Python Requests chooses a direct connection or an environment proxy

Python Requests No Proxy: Choose the Right Scope

There are three different meanings of “no proxy,” and the correct fix depends on scope:

Goal Best method What it changes
Make every request in one session direct session.trust_env = False Ignores all environment proxy rules for that session
Bypass the proxy only for selected hosts Set NO_PROXY Keeps the environment proxy for other destinations
Remove inherited proxies for one process Unset proxy variables before launch Changes what every compatible HTTP client in that process can inherit

Do not treat a direct Requests connection as proof that no network intermediary exists. A VPN, service mesh, transparent gateway, firewall, or corporate egress device can route traffic without appearing in Requests' proxy settings. The code here controls application-level proxy selection.

Why Requests Uses a Proxy You Did Not Configure

Requests trusts environment settings by default. If the running process contains a proxy variable, a plain call such as requests.get(url) can inherit it even though the code contains no proxy dictionary.

The relevant variables are:

The Requests proxy documentation confirms that both lowercase and uppercase variants are supported. Requests' current proxy-selection code gives the lowercase form priority when both cases are present, so duplicated variables with different values are a source of confusing results.

Check which names exist without printing credentials embedded in their values:

import os

proxy_names = (
    "http_proxy",
    "https_proxy",
    "all_proxy",
    "no_proxy",
    "HTTP_PROXY",
    "HTTPS_PROXY",
    "ALL_PROXY",
    "NO_PROXY",
)

configured = [name for name in proxy_names if os.environ.get(name)]
print("Proxy-related variables present:", configured)

Environment values may be injected outside your interactive terminal. Check the actual runtime configuration for a systemd service, Docker container, Kubernetes pod, IDE, scheduled task, or CI job instead of assuming it matches your login shell.

Disable Environment Proxies for a Whole Session

Use a dedicated direct session when all requests in one logical workflow must ignore environment proxy settings:

import requests

direct_session = requests.Session()
direct_session.trust_env = False

response = direct_session.get(
    "https://example.com/health",
    timeout=(5, 20),
)
response.raise_for_status()

trust_env belongs to Session; it is not an argument accepted by requests.get(). The top-level helper creates and closes a temporary session internally, so create your own session when you need to change this behavior.

Keep that session local to the code path that requires a direct connection. Giving it a clear name such as direct_session makes the routing policy visible during review and reduces the chance that another call accidentally uses the wrong transport configuration.

Preserve a custom CA bundle explicitly

Setting trust_env = False is broader than “ignore proxy variables.” Requests also stops reading REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE. If your direct destination uses a private certificate authority, assign the certificate bundle explicitly:

import requests

session = requests.Session()
session.trust_env = False
session.verify = "/etc/ssl/certs/internal-ca-bundle.pem"

response = session.get(
    "https://service.example.internal/health",
    timeout=(5, 20),
)
response.raise_for_status()

Do not replace a missing CA configuration with verify=False. That disables TLS certificate verification and turns a routing fix into a security problem. Requests documents both the environment CA variables and explicit verify paths in its SSL certificate verification guidance.

Supply authentication explicitly when needed

A session with trust_env = False also ignores credentials discovered through .netrc. Pass approved target authentication through the method your service expects, such as an explicit auth= tuple, token header, or application credential provider.

This does not affect credentials inside a proxy URL because the direct session is not supposed to use that URL. It affects authentication to the destination itself.

Use NO_PROXY for Selected Hosts

If most outbound traffic must use an organization proxy but internal services or local development endpoints should connect directly, keep environment proxy discovery enabled and define a bypass list:

export HTTPS_PROXY="http://proxy.example.net:8080"
export NO_PROXY="localhost,127.0.0.1,.example.internal,api.example.com:8443"

Then ordinary Requests calls use the proxy except when the destination matches NO_PROXY:

import requests

response = requests.get(
    "https://service.example.internal/health",
    timeout=(5, 20),
)
response.raise_for_status()

Use hostnames, IP addresses, domain suffixes, or host-and-port entries—not full URLs or URL paths. Requests also handles IPv4 CIDR entries in NO_PROXY. A leading-dot suffix such as .example.internal covers the parent hostname and its subdomains in current Requests behavior.

Be precise with suffixes. A broad entry can send more traffic directly than intended, while an entry that includes the wrong port may fail to match. After changing NO_PROXY, test both a bypassed host and a host that should still use the proxy.

Comparison of session-wide direct routing, host-specific NO_PROXY bypass, and inherited proxy routing

Why proxies={} Does Not Reliably Mean No Proxy

An empty proxy dictionary looks like an explicit instruction, but Requests can populate missing proxy keys from the environment while trust_env remains enabled:

# This may still inherit HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY.
response = requests.get(
    "https://example.com",
    proxies={},
    timeout=(5, 20),
)

Passing None values for http and https is also a fragile workaround. An inherited ALL_PROXY value can still supply a route, and redirects cause Requests to re-evaluate proxy configuration for the new URL. A dedicated session with trust_env = False states the intended policy directly and applies it consistently across redirects.

If your goal is the opposite—configuring an authenticated proxy intentionally—use an explicit proxy mapping and the examples in the Python proxy requests guide. Keep direct and proxied sessions separate when an application needs both.

If you are switching to a direct connection only because an intended proxy failed, use the proxy error troubleshooting checklist to identify the failing layer first. For a 407 Proxy Authentication Required response, follow the Python Requests proxy authentication guide instead of bypassing a proxy that the network or workflow requires.

Use Separate Direct and Proxied Sessions

One application may need a direct route for an internal API and a proxy for approved location testing. Model those as two sessions instead of changing global environment variables between requests:

import os
import requests

direct = requests.Session()
direct.trust_env = False

proxied = requests.Session()
proxied.trust_env = False
proxy_url = os.environ["PROXY_URL"]
proxied.proxies.update({
    "http": proxy_url,
    "https": proxy_url,
})

internal_response = direct.get(
    "https://service.example.internal/health",
    timeout=(5, 20),
)

regional_response = proxied.get(
    "https://example.com/catalog",
    timeout=(5, 20),
)

If PROXY_URL uses http://, the connection to the proxy is unencrypted. Basic proxy credentials and the initial CONNECT request are exposed on that connection even when the destination uses HTTPS. Use an authenticated HTTP proxy only over a trusted network, or use a TLS-protected proxy endpoint supported by the provider and your Requests/urllib3 versions.

Never log proxy_url; authenticated proxy URLs commonly contain a username and password. Keep cookies and authentication state separated too. Reusing one cookie jar across direct and proxied identities can make a stateful workflow inconsistent.

If the application does not need proxy routing at all, do not create the second session. Many small, permitted scraping jobs are easier to test directly at a low request rate before adding network infrastructure. The Python scraping workflow explains how to validate fetching and parsing before scaling.

Remove Proxy Variables for One Process

When several libraries in the same process should ignore inherited proxy variables, remove them at process launch rather than mutating os.environ halfway through a multithreaded program.

On a Linux or macOS shell:

env \
  -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u NO_PROXY \
  -u http_proxy -u https_proxy -u all_proxy -u no_proxy \
  python app.py

On PowerShell, start a clean child process from a block that temporarily removes the variables, then restore them if the parent session still needs them. In containers and CI, removing proxy variables from that service's environment definition is usually clearer than modifying them inside application code.

This process-level method can affect package managers, telemetry clients, cloud SDKs, and every other library that honors the same variables. Prefer the session-level switch when only Requests should connect directly.

Verify That Requests Is Not Using a Proxy

Use a controlled destination and compare the result with your expected direct egress address. Unknown Proxies provides a small IP response endpoint that is useful for this check:

import requests

session = requests.Session()
session.trust_env = False

response = session.get(
    "https://ipv4.unknownproxies.com/ip",
    timeout=(5, 20),
)
response.raise_for_status()
print(response.text.strip())

Run the same test from the same host with your intentional proxy session and compare the addresses. A difference proves that the two application routes have different public exits; it does not identify every gateway between your process and the internet.

For an internal service, server-side access logs are stronger evidence. Record a request ID on the client and confirm the source address and route at the destination. Avoid treating a successful 200 response alone as proof of direct routing.

Diagnose failures by layer

Changing to no-proxy mode can expose a real network requirement. Use the symptom to choose the next check:

Symptom after disabling the proxy Likely explanation Next check
Connection timeout Direct egress is blocked, destination is unavailable, or routing is wrong Test DNS, port access, and organization egress policy
DNS resolution error Direct DNS cannot resolve the host or the name is only available through a network gateway Compare DNS inside the actual runtime environment
TLS verification error The session stopped loading an environment CA bundle Set session.verify to the approved CA path
401 Unauthorized .netrc credentials are no longer loaded or target auth is missing Configure destination authentication explicitly
403 Forbidden The destination received the request but refused it Review permissions, policy, session state, and source network
429 Too Many Requests The destination is rate limiting the direct identity Reduce concurrency and honor Retry-After

A 403 or 429 does not mean Requests secretly used a proxy. Those are destination responses, while a proxy connection failure usually appears as requests.exceptions.ProxyError. The proxy versus firewall guide provides a layer-by-layer comparison when the boundary is unclear.

Common No-Proxy Mistakes

Change one layer at a time. First confirm which environment variable names exist, then choose a session-wide or host-specific bypass, and finally verify the observed route.

FAQ

How do I force Python Requests to use no proxy?

Create a requests.Session(), set session.trust_env = False, and make the request through that session. This prevents Requests from importing proxy rules from environment variables.

Does requests.get() use system proxy settings?

It can. Requests reads standard proxy environment variables by default. Depending on the operating system, Python's underlying proxy discovery can also consult platform configuration exposed through urllib.request.getproxies().

Does proxies={} disable environment proxies?

Not reliably. With trust_env enabled, Requests can merge environment proxies into keys missing from the empty dictionary. Use a session with trust_env = False when all requests in that session must be direct.

What is the difference between NO_PROXY and trust_env = False?

NO_PROXY bypasses environment proxies only for matching destinations. trust_env = False prevents the entire session from reading environment proxy settings and also disables environment-derived CA bundle and .netrc behavior.

Can I disable a proxy for one request?

Requests has no trust_env keyword on an individual get() call. Create a dedicated direct session and use it for that request. Keeping the session separate is clearer than temporarily changing process-wide environment variables.

Why does a request fail after I disable the proxy?

Your network may require the proxy for outbound access, direct DNS may differ, or the session may have stopped loading a custom CA bundle or .netrc credentials. Use the exact exception and response status to identify the failed layer before changing more settings.

Conclusion

For a Python Requests no proxy configuration, the reliable pattern is a dedicated Session with trust_env = False. Use NO_PROXY instead when only selected hosts should bypass an otherwise required environment proxy, and verify the result against a controlled endpoint or destination logs.

Remember that trust_env also controls environment CA bundles and .netrc authentication. Configure those dependencies explicitly, keep direct and proxied sessions separate, and do not disable TLS verification just to make a direct request succeed.

Technical references: Requests advanced usage: proxies, Requests Session API, and Python urllib.request.getproxies().

About the Author

Unknown Proxies

Proxy Infrastructure Team

Stay Unknown

High-performance dedicated proxies optimized for speed and reliability. Get uncompromising quality, 99.9% uptime, and unmatched support. Stay Unknown.

Explore Plans