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.

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:
HTTP_PROXYandhttp_proxyfor HTTP destinationsHTTPS_PROXYandhttps_proxyfor HTTPS destinationsALL_PROXYandall_proxyas a fallback for multiple schemesNO_PROXYandno_proxyfor destinations that should bypass those proxies
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.

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
- Passing
proxies={}while environment proxy variables remain active. - Disabling
trust_envand forgetting that the session also relied onREQUESTS_CA_BUNDLEor.netrc. - Setting
NO_PROXYto a full URL such ashttps://api.example.com/pathinstead of a hostname. - Checking proxy variables only in an interactive shell when the application runs in a container or service.
- Printing an authenticated proxy URL into CI logs while debugging.
- Using
verify=Falseto hide a certificate error caused by a missing CA path. - Assuming
localhostinside a container refers to a service running on the host machine. - Treating a target-side
403or429as proof that proxy bypass failed.
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().