Proxy environment variables: HTTP_PROXY, HTTPS_PROXY and NO_PROXY tested in 9 tools
No standard defines the proxy environment variables, so curl, Python, Node.js, Go and git all read them differently. A tested matrix of which tools use HTTPS_PROXY, HTTP_PROXY, ALL_PROXY and NO_PROXY, which NO_PROXY patterns match, upper vs lower case, and settings that work everywhere.

Setting a proxy through environment variables looks like this in a Linux or macOS shell:
export HTTPS_PROXY="http://USERNAME:[email protected]:8080"
export HTTP_PROXY="$HTTPS_PROXY"
export NO_PROXY="localhost,127.0.0.1,::1,.internal.example"
curl -s https://api.ipify.orgAnd like this in Windows PowerShell:
$env:HTTPS_PROXY = "http://USERNAME:[email protected]:8080"
$env:HTTP_PROXY = $env:HTTPS_PROXY
$env:NO_PROXY = "localhost,127.0.0.1,::1,.internal.example"
curl.exe -s https://api.ipify.orgThe catch is that there is no standard behind these variables. Every tool reads them its own way, and the differences decide whether a request goes through the proxy or straight out from your own IP, usually without any error. We ran the same scenarios through nine HTTP clients and logged on a test proxy which requests actually arrived. The results are below, followed by the settings that behave the same everywhere.
What each variable means
- HTTPS_PROXY: the proxy for
https://URLs. - HTTP_PROXY: the proxy for
http://URLs. - ALL_PROXY: a fallback for any scheme, read by some tools only.
- NO_PROXY: a comma-separated list of hosts that skip the proxy.
The value is the address of the proxy itself, and for a normal HTTP proxy port it starts with http:// even in HTTPS_PROXY. The client asks the proxy to open a tunnel with CONNECT and runs TLS through it, end to end with the website. Writing https:// there tells the client to speak TLS to the proxy, which a plain HTTP port does not do.
The test
The clients: curl 8.19, Requests 2.34, httpx 0.28, aiohttp 3.14 with trust_env=True, Python's own urllib on Python 3.14, Node.js 26.1 fetch and its https module with NODE_USE_ENV_PROXY=1, Go 1.26 net/http, and git 2.54. Each scenario ran in a fresh process against our local test proxy, which logged every connection it received. The tests ran on Windows; the differences in upper and lower case, which Windows does not have, are covered separately below.
Which tools read the variables at all
- By default: curl, Requests, httpx, urllib, Go and git.
- aiohttp: only when the session is created with
trust_env=True. - Node.js: only with
NODE_USE_ENV_PROXY=1or--use-env-proxy.
Node's documentation lists the environment variable from v24.0.0 and v22.21.0. Without it, Node's fetch ignores every proxy variable; the Node.js proxy guide has the other options.
HTTP_PROXY does not cover HTTPS sites
With only HTTP_PROXY set, eight of the nine clients sent an HTTPS request directly. Node's fetch was the only one that used HTTP_PROXY for an HTTPS site, and Node's own https module did not.
Since nearly every site is HTTPS, a setup with only HTTP_PROXY means most of your traffic skips the proxy. Always set HTTPS_PROXY.
ALL_PROXY is not universal
With only ALL_PROXY set, curl, Requests, httpx and git used it. aiohttp, urllib, Node and Go ignored it and connected directly. Treat ALL_PROXY as a convenience for curl-based tools, not as a catch-all.
NO_PROXY: which patterns match
We set HTTPS_PROXY and requested https://api.ipify.org with different NO_PROXY values:
- Parent domain,
ipify.org: every client skipped the proxy, except Node'shttpsmodule, which matches exact names only. - Leading dot,
.ipify.org: every client skipped the proxy. - Wildcard,
*.ipify.org: only Node and Go skipped it. curl, Requests, httpx, aiohttp, urllib and git still sent the request through the proxy. - Lone asterisk,
*: every client skipped the proxy for everything.
So write domains with a leading dot, .example.com, which every client matched. The *.example.com form looks natural but is ignored by most of them.
Local addresses go through the proxy too
Go never sends localhost or a loopback address through a proxy; its source code says so. curl, Requests, httpx, aiohttp, urllib and Node all sent requests for 127.0.0.1 and localhost to the proxy unless they were listed in NO_PROXY. That breaks local development servers and health checks in a way that looks like the server is down.
Two more traps:
- localhost does not cover 127.0.0.1. With
NO_PROXY=localhost, requests to127.0.0.1still went through the proxy in curl, Python and Node. - CIDR ranges are not universal. With
NO_PROXY=127.0.0.0/8, curl and Requests went direct; httpx, aiohttp, urllib and Node still used the proxy. Go documents CIDR support.
List every form of local address explicitly: localhost,127.0.0.1,::1.
Upper case or lower case
On Linux and macOS, HTTPS_PROXY and https_proxy are different variables, and tools disagree about which one wins:
- curl: reads
http_proxyin lower case only. Its manual says the other variables work in either case, and "the lower case version has precedence". - Python: urllib, Requests, httpx and aiohttp accept any case and prefer lower case. An empty lower-case variable cancels an upper-case one.
- Node.js: accepts both and prefers lower case, according to its documentation.
- Go: accepts both and prefers upper case. Its code checks
HTTP_PROXYbeforehttp_proxy.
Both languages also distrust HTTP_PROXY inside a CGI script, detected by a REQUEST_METHOD variable, because there a client can set it through a request header: Python drops the upper-case variable, and Go refuses to use an HTTP proxy at all.
The way out is simple: set both cases to the same value.
export https_proxy="http://USERNAME:[email protected]:8080"
export HTTPS_PROXY="$https_proxy"
export http_proxy="$https_proxy"
export HTTP_PROXY="$https_proxy"
export no_proxy="localhost,127.0.0.1,::1"
export NO_PROXY="$no_proxy"
curl -s https://api.ipify.orgPython can use a proxy you never set
If none of the proxy variables is set, Python's urllib falls back to the system proxy settings on Windows and macOS, and Requests, httpx and aiohttp all get their proxy settings from urllib. A comment in the httpx source puts it plainly: "urllib.request.getproxies() falls back on System Registry and Config for proxies on Windows and macOS."
So if a Python script uses a proxy after you have unset every variable, check the operating system's proxy settings. The Python Requests guide shows how to switch this off for a session.
Tools with their own proxy settings
Some tools read the variables and also have a setting of their own, which is handy when you want a proxy for one tool only.
git has http.proxy. Also set http.proxyAuthMethod to basic:
git config --global http.proxy http://USERNAME:[email protected]:8080
git config --global http.proxyAuthMethod basicgit's default method, anyauth, first sends each request without credentials to discover what the proxy accepts. Against our test proxy, which closes the connection after its 407 reply, that default failed with "Proxy CONNECT aborted", whether the proxy came from http.proxy or from HTTPS_PROXY. Set to basic, through http.proxyAuthMethod or the GIT_HTTP_PROXY_AUTHMETHOD variable, git sent the credentials straight away and worked in both cases. git also accepted a socks5h:// URL in http.proxy, and git config --global --unset http.proxy removes the setting.
pip has a --proxy option, and also reads HTTPS_PROXY:
pip install --proxy http://USERNAME:[email protected]:8080 requestsnpm keeps its own https-proxy setting. It also used HTTPS_PROXY, but with only HTTP_PROXY set, it fetched from its HTTPS registry directly:
npm config set https-proxy http://USERNAME:[email protected]:8080For curl, the -x and --noproxy options override the variables; the curl proxy guide covers them.
Settings that work everywhere
- Set HTTPS_PROXY and HTTP_PROXY, in both upper and lower case, to the same value.
- Start the value with http:// for an HTTP proxy port, even for HTTPS sites.
- Percent-encode special characters in the password, such as
@as%40. - Write NO_PROXY domains with a leading dot, and list localhost, 127.0.0.1 and ::1 separately.
- Do not rely on ALL_PROXY or CIDR ranges unless every tool you use supports them.
- Check the IP a test site reports after any change, because a skipped proxy fails silently.
The proxy testing guide shows quick ways to run that last check.
FAQ
Is HTTP_PROXY case-sensitive? On Linux and macOS, yes, and curl reads only the lower-case http_proxy. On Windows, variable names are not case-sensitive.
Does NO_PROXY support wildcards? A lone * disables the proxy everywhere. The *.example.com form worked only in Node and Go; use .example.com instead.
Why does my request skip the proxy even though HTTP_PROXY is set? The site is HTTPS, and most tools only use HTTPS_PROXY for HTTPS URLs.
Why are my localhost requests going through the proxy? Most tools do not exempt local addresses. Add localhost,127.0.0.1,::1 to NO_PROXY.
Try it
Create a NyxonProxies account, link Discord under Freebies for 250MB of free Residential Budget traffic, and put the username and password from the Generate page into the variables above. Prices for every proxy type are on the pricing page.