Guide
How to Use a Proxy with cURL: HTTP, HTTPS and SOCKS5 Command Examples
In cURL, a proxy is set with the -x option, and credentials go in the URL or are passed with -U. HTTPS requests through an HTTP proxy, socks5 vs socks5h, environment variables and .curlrc, exit IP and timing checks, Windows commands and common cURL proxy errors.
Key takeaways
- In cURL, the proxy is passed with the -x (--proxy) option: curl -x "http://USER:[email protected]:8989" https://api.ipify.org; credentials can go inside the URL or separately with -U "USER:PASSWORD".
- Even when the target site is HTTPS, an HTTP proxy address is written with http://; cURL sends CONNECT to the proxy and TLS is set up inside the tunnel. The https:// scheme means speaking TLS with the proxy server too.
- For SOCKS5, socks5:// resolves the domain locally and socks5h:// resolves it on the proxy side; to keep DNS queries off your local network, use socks5h:// or --socks5-hostname.
- For HTTP, cURL only reads the lowercase http_proxy variable; HTTPS_PROXY, ALL_PROXY and NO_PROXY are also supported. A -x on the command line overrides the environment variable.
- In Windows PowerShell 5.1, curl is an alias for Invoke-WebRequest; type curl.exe in proxy commands, and in cmd.exe put the address in double quotes.
To use a proxy in cURL, add the -x option (long name --proxy) and the proxy address to your request: curl -x "http://USER:[email protected]:8989" https://api.ipify.org. An HTTP proxy address is written with the http:// scheme, and a SOCKS5 proxy with socks5h://. The target site being HTTPS doesn’t change the proxy address.
The same command works on Linux, macOS and Windows. If the IP address it returns is the proxy’s exit IP, the connection, authentication and tunnel are set up correctly. The examples use the WeProxy gateway address gw.weproxy.com.tr:8989; USER and PASSWORD are the credentials from your dashboard.
How do you set a proxy in cURL? The -x and -U options
The -x option takes the proxy address in the form [scheme://][user:password@]host[:port]. You can put the credentials inside the address or pass them separately with -U (--proxy-user):
curl -x "http://USER:[email protected]:8989" https://api.ipify.org
curl -x "http://gw.weproxy.com.tr:8989" -U "USER:PASSWORD" https://api.ipify.org
Both commands send the same request. The difference shows up when the password has special characters. A password containing @, :, # or % has to be percent-encoded inside a URL (@ → %40). -U splits the value at the first :, so as long as the username has no :, you can write the password as is, without encoding. Encoding rules and other line formats are covered in the proxy formats guide.
According to the cURL documentation, a -x value without a scheme is treated as an HTTP proxy, and if the port is missing, 1080 is used. The WeProxy gateway listens on a different port, so write the port explicitly in every command. If the proxy authorizes you by IP whitelist, you don’t need credentials: curl -x "http://gw.weproxy.com.tr:8989" https://api.ipify.org is enough. The proxy authentication guide lists which method each WeProxy product supports.
A password typed on the command line can end up in your shell history and in the system’s process list. On shared servers, read the password from an environment variable:
export PROXY_PASS='PASSWORD'
curl -x "http://gw.weproxy.com.tr:8989" -U "USER:$PROXY_PASS" https://api.ipify.org
How do you send an HTTPS request through an HTTP proxy with cURL?
When you reach an HTTPS site through an HTTP proxy, the proxy address still starts with http://. cURL first sends a CONNECT api.ipify.org:443 request to the proxy. If the proxy returns 200, the TLS connection is set up inside this tunnel, directly with the target site. The proxy doesn’t see the target’s certificate or the page content; it only knows which host and port you connected to.
If the target starts with http://, cURL doesn’t open a tunnel. It sends the request to the proxy with the full URL, and the proxy goes to the target itself. To send a plain HTTP request through a tunnel too, add -p (--proxytunnel):
curl -p -x "http://USER:[email protected]:8989" http://example.com
Use -v to see what gets sent. Lines starting with > are outgoing data, and lines starting with < are incoming. A shortened example (details vary by cURL version):
> CONNECT api.ipify.org:443 HTTP/1.1
> Proxy-Authorization: Basic ...
< HTTP/1.1 200 Connection established
* CONNECT tunnel established, response 200
> GET / HTTP/2
< HTTP/2 200
The first < line is the proxy’s response, and the < lines after it come from the target site. If the CONNECT response is 407, the problem is with the credentials. If the tunnel opens with 200 and the target returns 403 or 429, the proxy works and the rejection comes from the target site.
Writing the proxy address with https:// means cURL will also speak TLS with the proxy server (an HTTPS proxy). If the proxy doesn’t offer that, the handshake fails and you get curl: (35). To send a header to the proxy itself, use --proxy-header instead of -H; -H headers go to the target site.
How do you use a SOCKS5 proxy with cURL? socks5 vs socks5h
For SOCKS5, only the scheme changes. cURL recognizes two schemes:
curl -x "socks5://USER:[email protected]:8989" https://api.ipify.org
curl -x "socks5h://USER:[email protected]:8989" https://api.ipify.org
socks5:// resolves the target domain on your machine and sends the IP address to the proxy. socks5h:// passes the domain to the proxy as is, and DNS resolution happens on the proxy side. With the second scheme, your DNS queries don’t leave your local network, and the target is resolved according to the proxy’s country. If you’re dealing with geo-specific content or want to close a DNS leak, use socks5h://. The DNS leak guide shows how to measure a leak.
Older commands use separate options that do the same job: --socks5 matches socks5:// with local resolution, and --socks5-hostname matches socks5h://. With these options, pass the credentials with -U:
curl --socks5-hostname "gw.weproxy.com.tr:8989" -U "USER:PASSWORD" https://api.ipify.org
Most WeProxy products offer HTTP and SOCKS5 together. Mobile proxy endpoints support HTTP only, so if you write that product with socks5://, the connection won’t open. The HTTP vs SOCKS5 article compares which protocol fits which job.
cURL proxy options compared
| Option | What it does | Example |
|---|---|---|
-x, --proxy | Sets the proxy address and protocol | -x "http://gw.weproxy.com.tr:8989" |
-U, --proxy-user | Proxy username and password | -U "USER:PASSWORD" |
-p, --proxytunnel | Sends plain HTTP requests through a CONNECT tunnel too | -p -x ... http://example.com |
--socks5-hostname | SOCKS5, DNS on the proxy (same as socks5h://) | --socks5-hostname gw.weproxy.com.tr:8989 |
--socks5 | SOCKS5, DNS local (same as socks5://) | --socks5 gw.weproxy.com.tr:8989 |
--proxy-header | Header sent only to the proxy | --proxy-header "X-Test: 1" |
--noproxy | Hosts that bypass the proxy | --noproxy "localhost,127.0.0.1" |
--connect-timeout | Time limit for setting up the connection (seconds) | --connect-timeout 10 |
-m, --max-time | Time limit for the whole operation (seconds) | -m 30 |
If you pass both -x and --socks5 in one command, the last one wins. To avoid confusion, pick one method; -x with a scheme URL is the easiest to read in scripts.
How to set a permanent cURL proxy with environment variables and .curlrc
If you don’t want to type -x in every command, set the environment variables cURL reads:
export http_proxy="http://USER:[email protected]:8989"
export HTTPS_PROXY="http://USER:[email protected]:8989"
export NO_PROXY="localhost,127.0.0.1"
curl https://api.ipify.org
For HTTP requests, cURL only reads the lowercase http_proxy variable; uppercase HTTP_PROXY is ignored for security reasons. For HTTPS you can use HTTPS_PROXY or https_proxy, and ALL_PROXY for all protocols. Hosts in the NO_PROXY list skip the proxy. A -x on the command line overrides the environment variable, and --noproxy "*" turns the proxy off completely for that request.
You can also put the same setting in a per-user config file. On Linux and macOS, that’s ~/.curlrc:
proxy = "http://gw.weproxy.com.tr:8989"
proxy-user = "USER:PASSWORD"
On Windows, cURL looks for the file in your user folder (%USERPROFILE% or %APPDATA%) under the name .curlrc or _curlrc. If you pass -q as the first argument of the command, cURL doesn’t read this file. If a script unexpectedly goes out through a proxy, check the environment variables and the .curlrc file first.
How do you check your proxy exit IP with cURL?
The quickest test is to send a request through the proxy to a service that returns your IP address as plain text:
curl -s -x "http://USER:[email protected]:8989" "https://api.ipify.org?format=json"
If the address you get back is your own IP, the request didn’t go through the proxy. In that case, check the NO_PROXY value, the -x address, and whether the command you’re looking at is the one that actually ran. To see the IP’s country, city and network, paste the address into the IP lookup tool; My IP shows your browser’s exit through the proxy.
To test how a rotating gateway rotates, run the same command several times in a row. Each curl call opens a new connection, so with a pool that rotates per request you’ll see a different IP on each line:
for i in 1 2 3 4 5; do
curl -s -x "http://USER:[email protected]:8989" https://api.ipify.org
echo
done
If you have a list from the dashboard in host:port:user:pass format, a short Bash loop that tries each line in turn shows which proxies work:
while IFS=: read -r host port user pass; do
printf '%s:%s -> ' "$host" "$port"
curl -s -m 15 -x "http://$host:$port" -U "$user:$pass" https://api.ipify.org || printf 'ERROR'
echo
done < proxies.txt
read gives the rest of the line to the last variable, so even if the password contains :, it stays whole in pass. Since -U is used, you don’t need to percent-encode the password either. -m 15 keeps a line that doesn’t respond from locking up the loop.
If you need to keep the same IP for a while (login, cart, multi-step form), WeProxy residential and mobile pools add a session ID to the username. The residential pool can hold the same exit IP for up to 24 hours, and the mobile pool for up to 60 minutes. The exact username format depends on the product, so copy it from the dashboard and use the loop above to check that the same IP comes back. The sticky vs rotating proxy guide walks through which tasks need a fixed IP and which need a rotating one, scenario by scenario.
To see which stage of the connection is losing time, print timing values with -w:
curl -s -o /dev/null -x "http://USER:[email protected]:8989" \
-w "connect=%{http_connect} http=%{http_code} tcp=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n" \
https://api.ipify.org
%{http_connect} gives the proxy’s CONNECT response, and %{http_code} gives the target site’s response. time_connect is the moment the TCP connection to the proxy completes, and time_appconnect is when the TLS handshake with the target finishes. If the total time is high but time_connect is low, you’re reaching the proxy quickly; the delay is beyond the tunnel or at the target site. To test a single line independently of your code, you can also use the proxy checker.
How to use a proxy with cURL on Windows
Windows 10 and 11 ship with curl.exe. In Windows PowerShell 5.1, though, curl runs Invoke-WebRequest, a different command with different parameters. In PowerShell, always type curl.exe:
curl.exe -x "http://USER:[email protected]:8989" https://api.ipify.org
In Command Prompt (cmd.exe), single quotes don’t count as quotes. Write the address in double quotes. For line continuation, cmd.exe uses ^ and PowerShell uses the backtick, where Bash would use \. Environment variables are also set differently depending on the shell:
# PowerShell
$env:HTTPS_PROXY = "http://USER:[email protected]:8989"
curl.exe https://api.ipify.org
:: cmd.exe
set HTTPS_PROXY=http://USER:[email protected]:8989
curl https://api.ipify.org
In cmd.exe, if the password contains %, ^ or &, the shell interprets those characters. Pass such a password with -U inside double quotes, or percent-encode it in the URL. cURL doesn’t read the Windows system proxy setting; for a system-wide setup, see the Windows integration page.
cURL proxy errors and how to fix them
When cURL fails, the number at the start of the line (the exit code) tells you at which stage the problem happened:
| Error | Meaning | Fix |
|---|---|---|
curl: (5) Could not resolve proxy | The proxy host name couldn’t be resolved | Check the gateway name and your local DNS |
curl: (7) Failed to connect | The proxy port couldn’t be reached | Write the port explicitly, check the firewall |
curl: (56) CONNECT tunnel failed, response 407 | The proxy didn’t accept the credentials | Check the username, password and percent-encoding |
curl: (35) TLS error | Proxy written with https:// or the tunnel couldn’t be set up | Change the proxy scheme to http:// |
curl: (97) | SOCKS handshake failed | Check the product’s SOCKS5 support and the credentials |
curl: (28) | Timeout | Separate --connect-timeout and -m limits, try again |
| Your own IP comes back | The request didn’t go to the proxy | Check NO_PROXY, .curlrc and the -x value |
For temporary network errors, you can add --retry 3 --retry-delay 2 to retry the request automatically. --retry only kicks in on errors cURL treats as transient; retrying a permanent error like 407 won’t change the result. The proxy error codes guide explains which layer each status code comes from and where to look first for each one. When you move on to sending the same requests from code, the examples in the Python proxy guide use the same address format.
When sending bulk requests with cURL, follow the target site’s terms of use and its robots.txt file; if you collect personal data, KVKK and GDPR obligations apply. Permitted uses of WeProxy services are listed on the acceptable use page. For a new IP on every request, see the plans on the rotating residential proxy page; for a fixed exit address, see the static datacenter IPv4 page.
Frequently asked questions
How do I set a proxy in cURL?
Add the proxy address to the request with the -x option: curl -x "http://USER:[email protected]:8989" https://api.ipify.org. To pass credentials separately, write -x "http://gw.weproxy.com.tr:8989" -U "USER:PASSWORD". Without a scheme, cURL treats the address as an HTTP proxy, and without a port it uses 1080, so always write the port explicitly. If the returned IP is the proxy’s exit IP, the setup is correct.
Should the proxy address use https:// for HTTPS sites?
No, in most cases it’s written with http://. The scheme describes the proxy server’s protocol, not the target site’s. For HTTPS targets, cURL sends a CONNECT request to the proxy and sets up the TLS connection with the target inside that tunnel. Writing the proxy address with https:// means cURL will also speak TLS with the proxy itself; if the proxy doesn’t offer that, you get a curl: (35) error.
What is the difference between socks5 and socks5h in cURL?
Both connect to the same SOCKS5 proxy; the difference is in DNS resolution. socks5:// or --socks5 resolves the target domain on your own machine and sends the IP address to the proxy. socks5h:// or --socks5-hostname passes the domain to the proxy, and resolution happens on the proxy side. The second method keeps DNS queries from leaving your local network and resolves the target according to the proxy’s location.
Why do I get a 407 error in cURL?
The message curl: (56) CONNECT tunnel failed, response 407 means the proxy didn’t accept your credentials. Copy the username and password from the dashboard again. If the password contains characters like @, : or %, percent-encode them inside the URL or pass the credentials separately with -U "USER:PASSWORD". If you use an IP whitelist, check that the IP your request comes from is registered in the dashboard.
How can I use a proxy without adding it to every cURL command?
Set an environment variable: on Linux and macOS, export HTTPS_PROXY="http://USER:[email protected]:8989", and in PowerShell, $env:HTTPS_PROXY. HTTP requests need the lowercase http_proxy. For a permanent setting, add proxy and proxy-user lines to the ~/.curlrc file. Use NO_PROXY to exclude specific hosts, and --noproxy "*" to turn the proxy off for a single request.









