cURL is the fastest way to test a proxy connection — one command and you know if it's working, what IP you're getting, and how fast the response is. But cURL has over a dozen proxy-related flags, and the documentation doesn't explain when to use which. This is the complete reference for every proxy option in cURL, with working examples using residential proxies.
Basic Proxy Syntax
There are three ways to specify a proxy in cURL:
# Method 1: -x / --proxy flag (most common)
curl -x http://gate.proxylabs.app:8080 https://httpbin.org/ip
# Method 2: Environment variable
export https_proxy=http://gate.proxylabs.app:8080
curl https://httpbin.org/ip
# Method 3: .curlrc config file
echo "proxy = http://gate.proxylabs.app:8080" >> ~/.curlrc
curl https://httpbin.org/ip
Method 1 is best for testing. Method 2 is best for scripts where every request should go through the proxy. Method 3 is useful for development machines, but be aware it affects all cURL commands — including package managers and other tools that use cURL under the hood.
Proxy Authentication
Most residential proxies require username/password. cURL supports auth in the URL or via a separate flag:
# Auth in URL (simplest)
curl -x http://your-username:[email protected]:8080 https://httpbin.org/ip
# Auth via --proxy-user flag (avoids credentials in URL)
curl -x http://gate.proxylabs.app:8080 \
--proxy-user your-username:your-password \
https://httpbin.org/ip
# Auth via -U shorthand
curl -x http://gate.proxylabs.app:8080 \
-U your-username:your-password \
https://httpbin.org/ip
The --proxy-user flag is preferred in scripts because the proxy URL won't contain credentials if it shows up in logs or ps output. That said, cURL does try to hide credentials from ps by overwriting the argument in memory after parsing.
Geo-Targeting
With ProxyLabs, append country and city modifiers to the username:
# US IP
curl -x http://gate.proxylabs.app:8080 \
-U your-username-country-US:your-password \
https://httpbin.org/ip
# UK IP from London
curl -x http://gate.proxylabs.app:8080 \
-U your-username-country-GB-city-London:your-password \
https://httpbin.org/ip
# German IP from Berlin
curl -x http://gate.proxylabs.app:8080 \
-U your-username-country-DE-city-Berlin:your-password \
https://httpbin.org/ip
Verify the IP location with the ProxyLabs IP Lookup tool.
Sticky Sessions
By default, each cURL request through a rotating proxy gets a different IP. To keep the same IP across multiple requests, add a session ID:
# All three requests use the same IP
curl -x http://gate.proxylabs.app:8080 \
-U your-username-session-mysession01:your-password \
https://httpbin.org/ip
curl -x http://gate.proxylabs.app:8080 \
-U your-username-session-mysession01:your-password \
https://httpbin.org/ip
curl -x http://gate.proxylabs.app:8080 \
-U your-username-session-mysession01:your-password \
https://httpbin.org/ip
The session ID can be any string. It stays active for up to 30 minutes. For more on when to use sticky vs rotating, see rotating vs sticky proxies.
HTTPS Through Proxies (CONNECT Tunneling)
When you curl an HTTPS URL through an HTTP proxy, cURL uses the CONNECT method to establish a tunnel. The proxy sees the hostname but can't read the encrypted traffic.
# This automatically uses CONNECT for HTTPS
curl -x http://your-username:[email protected]:8080 \
https://httpbin.org/ip
# Force tunnel mode explicitly
curl -x http://your-username:[email protected]:8080 \
--proxytunnel \
https://httpbin.org/ip
The --proxytunnel flag is usually unnecessary — cURL uses tunneling automatically for HTTPS. But it's useful when you want to tunnel non-HTTP protocols through an HTTP proxy.
SOCKS5 Proxies
If your proxy provider supports SOCKS5 (ProxyLabs' gateway is HTTP, but this is useful to know):
# SOCKS5 proxy
curl --socks5 proxy-host:1080 https://httpbin.org/ip
# SOCKS5 with authentication
curl --socks5 proxy-host:1080 \
--proxy-user username:password \
https://httpbin.org/ip
# SOCKS5 with DNS resolved by the proxy (recommended — prevents DNS leaks)
curl --socks5-hostname proxy-host:1080 \
--proxy-user username:password \
https://httpbin.org/ip
The difference between --socks5 and --socks5-hostname matters: --socks5 resolves DNS locally (your machine resolves the domain, then sends the IP to the proxy). --socks5-hostname sends the domain name to the proxy, which resolves it. Use --socks5-hostname to avoid DNS leaks.
Every Proxy-Related cURL Flag
| Flag | Description | Example |
|---|---|---|
-x, --proxy | Set proxy URL | -x http://proxy:8080 |
-U, --proxy-user | Proxy credentials | -U user:pass |
--proxy-basic | Force Basic auth (default) | --proxy-basic |
--proxy-digest | Use Digest auth | --proxy-digest |
--proxy-ntlm | Use NTLM auth | --proxy-ntlm |
--proxy-header | Send header only to proxy | --proxy-header "X-Custom: val" |
--proxytunnel | Force CONNECT tunnel | --proxytunnel |
--proxy-insecure | Skip proxy TLS verification | --proxy-insecure |
--proxy-cacert | CA cert for proxy connection | --proxy-cacert ca.pem |
--proxy-cert | Client cert for proxy | --proxy-cert client.pem |
--noproxy | Bypass proxy for hosts | --noproxy localhost,127.0.0.1 |
--socks5 | SOCKS5 proxy | --socks5 proxy:1080 |
--socks5-hostname | SOCKS5 + remote DNS | --socks5-hostname proxy:1080 |
--socks4 | SOCKS4 proxy | --socks4 proxy:1080 |
--preproxy | First proxy in chain | --preproxy socks5://first:1080 |
Useful Debugging Flags
When your proxy isn't working, these flags help diagnose the issue:
# Verbose output — shows connection details, headers, TLS handshake
curl -v -x http://your-username:[email protected]:8080 \
https://httpbin.org/ip
# Show timing breakdown
curl -x http://your-username:[email protected]:8080 \
-o /dev/null -s -w "\
DNS lookup: %{time_namelookup}s\n\
Connect: %{time_connect}s\n\
TLS: %{time_appconnect}s\n\
First byte: %{time_starttransfer}s\n\
Total: %{time_total}s\n\
HTTP code: %{http_code}\n" \
https://httpbin.org/ip
# Write response headers to stderr
curl -x http://your-username:[email protected]:8080 \
-D - https://httpbin.org/ip
The timing breakdown is especially useful. Typical values with residential proxies:
| Phase | Expected range | If too high |
|---|---|---|
| DNS lookup | 0-50ms | DNS resolution issue (not proxy-related) |
| Connect | 20-150ms | Network path to proxy gateway |
| TLS handshake | 50-200ms | TLS negotiation with target via proxy |
| First byte | 100-500ms | Proxy routing + target server response |
| Total | 200-1000ms | Normal for residential proxy |
Scripting with cURL and Proxies
Batch Requests with IP Rotation
#!/bin/bash
# Scrape multiple URLs with rotating IPs
PROXY_HOST="gate.proxylabs.app:8080"
PROXY_USER="your-username"
PROXY_PASS="your-password"
URLS=(
"https://example.com/page/1"
"https://example.com/page/2"
"https://example.com/page/3"
)
for url in "${URLS[@]}"; do
echo "Fetching: $url"
curl -s -x "http://${PROXY_HOST}" \
-U "${PROXY_USER}:${PROXY_PASS}" \
-o "$(basename "$url").html" \
-w " Status: %{http_code}, Time: %{time_total}s, Size: %{size_download} bytes\n" \
"$url"
sleep $((RANDOM % 3 + 2)) # 2-4 second random delay
done
Parallel Requests with xargs
#!/bin/bash
# Parallel cURL with proxies — 5 concurrent requests
PROXY="http://your-username:[email protected]:8080"
cat urls.txt | xargs -P 5 -I {} \
curl -s -x "$PROXY" \
-o "/tmp/output_{#}.html" \
-w "{} -> %{http_code} (%{time_total}s)\n" \
{}
Testing Proxy Rotation
Verify that each request gets a different IP:
#!/bin/bash
# Confirm IP rotation — should show 10 different IPs
PROXY_HOST="gate.proxylabs.app:8080"
PROXY_USER="your-username"
PROXY_PASS="your-password"
echo "Testing IP rotation (10 requests):"
for i in $(seq 1 10); do
IP=$(curl -s -x "http://${PROXY_HOST}" \
-U "${PROXY_USER}:${PROXY_PASS}" \
https://httpbin.org/ip | grep -o '"origin": "[^"]*"' | cut -d'"' -f4)
echo " Request $i: $IP"
done
Testing Geo-Targeting
#!/bin/bash
# Verify geo-targeting for different countries
PROXY_HOST="gate.proxylabs.app:8080"
PROXY_PASS="your-password"
COUNTRIES=("US" "GB" "DE" "JP" "BR")
for country in "${COUNTRIES[@]}"; do
IP=$(curl -s -x "http://${PROXY_HOST}" \
-U "your-username-country-${country}:${PROXY_PASS}" \
https://httpbin.org/ip | grep -o '"origin": "[^"]*"' | cut -d'"' -f4)
echo "$country: $IP"
done
Common Errors and Fixes
curl: (56) Proxy CONNECT aborted
The proxy server rejected the CONNECT request. Usually means bad credentials.
# Check your credentials
curl -v -x http://gate.proxylabs.app:8080 \
-U your-username:your-password \
https://httpbin.org/ip 2>&1 | grep "< HTTP"
# Should show: < HTTP/1.1 200 Connection established
curl: (7) Failed to connect to proxy
Can't reach the proxy server. Check the hostname and port.
# Test basic connectivity
curl -v -x http://gate.proxylabs.app:8080 http://httpbin.org/ip
# If this fails, check DNS resolution and firewall rules
curl: (35) SSL connect error
TLS handshake failed through the proxy. Try --proxy-insecure for debugging (don't use in production):
curl -x http://your-username:[email protected]:8080 \
--proxy-insecure \
https://httpbin.org/ip
Empty response or timeout
The target site might be blocking the proxy IP. Try a different country or add headers:
curl -x http://gate.proxylabs.app:8080 \
-U your-username-country-US:your-password \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
-H "Accept: text/html,application/xhtml+xml" \
--connect-timeout 10 \
--max-time 30 \
https://example.com
Environment Variables for Persistent Proxy
Set these in your shell profile (~/.bashrc, ~/.zshrc) to route all cURL traffic through a proxy:
# Add to ~/.bashrc or ~/.zshrc
export http_proxy="http://your-username:[email protected]:8080"
export https_proxy="http://your-username:[email protected]:8080"
export no_proxy="localhost,127.0.0.1,.local"
# These also work (uppercase)
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export NO_PROXY="$no_proxy"
Be careful: these environment variables affect most command-line HTTP tools (wget, httpie, Python requests, Node.js fetch). Use no_proxy to exclude local services.
For testing proxy connections quickly before building more complex scrapers, use the ProxyLabs Proxy Tester. For full scraping setups, see our guides for Python (Scrapy), Selenium, Puppeteer, and Playwright.
Ready to try the fastest residential proxies?
Join developers and businesses who trust ProxyLabs for mission-critical proxy infrastructure.
Building proxy infrastructure since 2019. Previously failed at many things, now failing slightly less.
Related Articles
How to Scrape Amazon Prices in 2026 (Without Getting Blocked)
A working guide to scraping Amazon product prices with residential proxies. Covers their anti-bot stack, request patterns, and code examples in Python.
7 min readProxy Authentication: IP Whitelist vs User/Pass vs API
Compare proxy authentication methods: IP whitelisting, username/password, and API tokens. Covers security trade-offs, setup complexity, and when to use each.
7 min readContinue exploring
Implementation guides for requests, Scrapy, Axios, Puppeteer, and more.
See how residential proxies fit large-scale scraping workflows.
Evaluate ProxyLabs against Bright Data, Oxylabs, Smartproxy, and others.
Browse location coverage and targeting options across 195+ countries.