A cURL proxy is one flag: -x (long form --proxy) followed by the proxy URL, with the username and password either in the URL or passed with -U. For an HTTPS target, cURL opens a CONNECT tunnel through the proxy and does TLS with the site itself.
curl -x http://USERNAME:PASSWORD@HOST:PORT "https://api.ipify.org?format=json"
Every command on this page ran on 2026-09-29 with curl 8.5 against a local authenticating HTTP proxy and a SOCKS5 proxy that enforces a username and password.
Before you start: copy your proxy details
- Open your order in the dashboard at https://app.proxyhive.io.
- Copy HOST, PORT, USERNAME and PASSWORD. Every ISP or datacenter IP is its own endpoint, with its own HTTP, HTTPS and SOCKS5 ports on the order. The dashboard's copy formats include
USER:PASS@HOST:PORT, which drops straight into a URL. - Put them in the environment so they stay out of your shell history:
export PROXY_HOST=HOST PROXY_PORT=PORT PROXY_USER=USERNAME PROXY_PASS=PASSWORD
No IP yet? A static ISP proxy can be bought one address at a time.
cURL proxy basics: -x and --proxy
curl -x "http://$PROXY_HOST:$PROXY_PORT" \
-U "$PROXY_USER:$PROXY_PASS" \
"https://api.ipify.org?format=json"
-x HOST:PORT without a scheme also works and defaults to HTTP. Spelling out http:// is clearer and avoids surprises when you later switch to socks5h://. The scheme describes how cURL talks to the proxy, not the target: an http:// proxy URL is right for https:// sites.
cURL proxy authentication: -U, --proxy-user and allowlists
-U user:pass and --proxy-user user:pass are the same option. They beat credentials in the URL when the password contains @ or :, because nothing has to be percent-encoded. Wrap the argument in quotes so the shell leaves $, ! and & alone.
To skip credentials entirely, switch the IP to allowlist authentication on the order in the dashboard and add your machine's public IP. Then:
curl -x "http://$PROXY_HOST:$PROXY_PORT" "https://api.ipify.org?format=json"
cURL SOCKS5 proxy: socks5h vs socks5
Use the SOCKS5 port from the order:
curl -x "socks5h://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:SOCKS5_PORT" "https://api.ipify.org?format=json"
# the same thing with dedicated flags
curl --socks5-hostname "$PROXY_HOST:SOCKS5_PORT" -U "$PROXY_USER:$PROXY_PASS" "https://api.ipify.org?format=json"
socks5h:// and --socks5-hostname hand the hostname to the proxy. socks5:// and --socks5 resolve it locally and send the IP. Our test proxy logged exactly that difference. Prefer the h variants so DNS lookups leave from the proxy, not from your machine. When SOCKS5 is worth it over HTTP is covered in HTTP vs SOCKS5 proxies.
Debug the CONNECT with -v
-v prints the conversation with the proxy before the conversation with the site. A failing tunnel looks like this:
* Establish HTTP proxy tunnel to api.ipify.org:443
> CONNECT api.ipify.org:443 HTTP/1.1
> Host: api.ipify.org:443
>
< HTTP/1.1 407 Proxy Authentication Required
< Proxy-Authenticate: Basic
* CONNECT tunnel failed, response 407
A 407 on the CONNECT line means the proxy rejected you, and the target never saw the request. A 200 Connection established followed by a 403 from the site means the proxy worked and the target refused. Knowing which hop failed saves most of the debugging time. Proxy error codes maps each status to its cause.
Proxy environment variables in cURL
cURL reads these when you pass no -x:
| Variable | Case | Applies to |
|---|---|---|
http_proxy | lowercase only | http:// URLs |
HTTPS_PROXY / https_proxy | either | https:// URLs |
ALL_PROXY / all_proxy | either | anything not matched above |
NO_PROXY / no_proxy | either | hosts to reach directly |
export https_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT"
curl "https://api.ipify.org?format=json"
The curl manual documents the lowercase-only rule. The reason is CGI: there an uppercase HTTP_PROXY can be set from an incoming request header. We confirmed it: with only HTTP_PROXY set, cURL went direct. --noproxy '*' ignores all of them for one command.
Make it the default with .curlrc
For a machine that should always use the proxy, put the options in ~/.curlrc, or in a separate file you load with -K:
proxy = "http://HOST:PORT"
proxy-user = "USERNAME:PASSWORD"
curl -K proxy.curlrc "https://api.ipify.org?format=json"
A .curlrc is plain text with a password in it: chmod 600 it, and remember every cURL call on that account now goes through the proxy, including your package manager's if it shells out to cURL.
HTTPS proxies and --proxy-insecure
The dashboard lists an HTTPS port next to HTTP, and the snippets it generates use an http:// proxy URL for both. --proxy-insecure only matters when the proxy URL itself starts with https:// and the proxy's certificate cannot be verified. For HTTPS websites through an HTTP proxy you never need it, and -k (which disables checks on the site's certificate) is not a proxy fix either.
Verify the exit IP and rotate across several IPs
Compare direct and proxied:
curl -s "https://api.ipify.org?format=json"
curl -s -x "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" "https://api.ipify.org?format=json"
With several static IPs, loop over a file with one http://USER:PASS@HOST:PORT URL per line:
while read -r proxy; do
curl -s -x "$proxy" --connect-timeout 10 --max-time 30 "https://api.ipify.org?format=json"; echo
done < proxies.txt
Timeouts and retries
--connect-timeout 10 caps the proxy handshake, --max-time 30 caps the whole transfer, and --retry 3 retries timeouts and 408, 429, 500, 502, 503 and 504 responses with backoff. -w '%{http_code} %{time_total}\n' prints status and latency per call, which is a cheap way to measure an IP yourself.
Common cURL proxy errors
| Symptom | Exit code | Fix |
|---|---|---|
CONNECT tunnel failed, response 407 | 56 | Wrong credentials; re-copy them, quote the -U argument |
Failed to connect to HOST port PORT | 7 | Wrong port for the scheme, or a typo in the host |
| SOCKS handshake fails | 97 | Wrong SOCKS credentials |
Hangs, then Operation timed out | 28 | Protocol and port mismatch, such as socks5h:// against the HTTP port |
| Request goes direct | 0 | HTTP_PROXY in uppercase; use http_proxy |
Next steps
- Move the same endpoint into code with Python requests or Node.js.
- Connection reference and copy formats: the docs.