curl Cheatsheet
Proxies
Use this curl reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Setting a proxy
-x / --proxy takes [scheme://]host[:port]. With no scheme curl assumes an
HTTP proxy, and with no port it assumes 1080, which trips people who expect 80
or 8080.
curl -x http://proxy.corp:3128 https://api.example.com/ curl -x proxy.corp:3128 https://api.example.com/ # same, http:// implied curl -x socks5h://127.0.0.1:1080 https://api.example.com/ curl -x '' https://api.example.com/ # ignore proxy env vars
| Scheme | Proxy type |
|---|---|
http:// (or none) | HTTP proxy, CONNECT for HTTPS targets |
https:// | HTTPS proxy, the hop to the proxy is itself TLS |
socks4:// | SOCKS4, client-side DNS |
socks4a:// | SOCKS4a, proxy-side DNS |
socks5:// | SOCKS5, client-side DNS |
socks5h:// | SOCKS5, proxy-side DNS |
socks5h:// is nearly always the one you want, because socks5:// resolves the
hostname locally, which leaks your DNS queries and breaks any name that only the
proxy can resolve.
Proxy environment variables
curl reads these when no -x is given. The lowercase spellings are the portable
ones, and -x overrides all of them.
| Variable | Applies to |
|---|---|
http_proxy | http:// URLs, lowercase only by design |
https_proxy / HTTPS_PROXY | https:// URLs |
all_proxy / ALL_PROXY | Any protocol without a specific variable |
no_proxy / NO_PROXY | Comma list of hosts to bypass |
export https_proxy=http://proxy.corp:3128 export no_proxy='localhost,127.0.0.1,.internal.example.com' curl https://api.example.com/ curl --noproxy '' https://api.example.com/ # override no_proxy for one call
curl deliberately ignores an uppercase HTTP_PROXY, because in a CGI context that
name comes from a client-supplied Proxy: header. Only http_proxy in lowercase
is honored.
Bypassing with --noproxy
--noproxy overrides no_proxy for a single command. Matching is by domain
suffix, so local.com matches local.com, local.com:80, and www.local.com,
but not www.notlocal.com.
curl --noproxy '.internal.example.com,localhost' https://api.example.com/ curl --noproxy '192.168.0.0/16' http://192.168.4.7/ # CIDR, curl 7.86.0 curl --noproxy '*' https://api.example.com/ # bypass everything curl --noproxy '' https://api.example.com/ # force the proxy
The only wildcard is a bare *, which disables the proxy for every host. There is
no *.example.com glob, a leading dot already means "and subdomains".
Proxy authentication
The proxy has its own credential set, entirely separate from -u, which belongs
to the origin server.
| Flag | Purpose |
|---|---|
-U / --proxy-user <u:p> | Proxy credentials |
--proxy-basic / --proxy-digest / --proxy-ntlm / --proxy-negotiate | Proxy auth scheme |
--proxy-anyauth | Probe and pick the strongest the proxy offers |
--proxy-header <h> | Header sent to the proxy only |
-p / --proxytunnel | Tunnel with CONNECT even for non-HTTPS |
--suppress-connect-headers | Hide the CONNECT response from -i/-v |
curl -x proxy.corp:3128 -U 'ada:s3cret' https://api.example.com/ curl -x proxy.corp:3128 -U 'ada:p%40ss' https://api.example.com/ curl -x proxy.corp:3128 -U ada:s3cret -u api:key https://api.example.com/
curl URL-decodes the credentials inside -x and -U, so a literal @ is %40
and a literal : is %3a. That is the escape people miss when a proxy password
contains punctuation.
TLS through a proxy
Two separate TLS relationships exist: curl to the proxy (only with an https://
proxy) and curl to the origin through the tunnel. Each has its own flag family, and
mixing them up is the classic mistake.
| Origin flag | Proxy equivalent |
|---|---|
--cacert | --proxy-cacert |
--capath | --proxy-capath |
-E / --cert | --proxy-cert |
--key | --proxy-key |
-k / --insecure | --proxy-insecure |
--tlsv1.2 | --proxy-tlsv1 |
--ciphers | --proxy-ciphers |
curl -x https://proxy.corp:3129 \
--proxy-cacert /etc/ssl/proxy-ca.pem \
--cacert /etc/ssl/corp-root.pem \
https://api.example.com/A corporate MITM proxy that re-signs certificates means the origin chain is
signed by the proxy's CA, so --cacert proxy-ca.pem is the right fix. Reaching for
-k hides the problem and turns off verification for the real target too.
Debugging a proxy path
curl -v -x proxy.corp:3128 https://api.example.com/ 2>&1 | head -20 # > CONNECT api.example.com:443 HTTP/1.1 # < HTTP/1.1 200 Connection established curl -sx proxy.corp:3128 -o /dev/null \ -w 'proxy=%{http_connect} code=%{http_code} t=%{time_connect}\n' \ https://api.example.com/
- %{http_connect} is the proxy's CONNECT status. A 407 there means proxy
auth, not origin auth.
- Exit 7 with a proxy set is a failure reaching the proxy, not the target.
- --unix-socket <path> is not a proxy option. It replaces the TCP connection
entirely and is how you talk to a local daemon.
curl --unix-socket /var/run/docker.sock http://localhost/v1.45/containers/json