curl with a proxy: HTTP, SOCKS5 and common errors
Published 7 min read
In short
In curl, --proxy sets the proxy address and --proxy-user sets the username and password. For Proxeta residential and mobile proxies that is http://host:8080 or socks5h://host:1080; with socks5h, the proxy resolves the site’s name. You check the exit IP with a service that echoes your address, and the error points to the cause: a 407 response means the login or password, exit code 7 means the port or network.
curl is on almost every system, which makes it a handy way to test a proxy before you plug it into a script or an app. Below are commands for HTTP and SOCKS5 with a username and password, the difference between socks5h:// and socks5://, how to check the exit IP, and what curl’s error messages mean. The commands are written for bash and zsh (macOS and Linux). The details in the examples are placeholders: use your own from the Dashboard.
The proxy string and curl’s flags
The Proxeta Dashboard issues residential and mobile proxies as a host:port:login:password string. Port 8080 is HTTP, port 1080 is SOCKS5, and the login and password are the same for both. The location and session mode are encoded in the login, so copy it whole; its parts are explained in proxy string format.
curl takes these details through two flags:
--proxy(short form-x): the scheme, host and port, such ashttp://host:8080orsocks5h://host:1080;--proxy-user(short form-U): the username and password separated by a colon. curl splits the value at the first colon, so colons,@and/in the password do no harm here.
You can also put the username and password straight into the proxy address: http://login:password@host:8080. Then special characters in the password must be URL-encoded: @ as %40, : as %3A, / as %2F.
curl through an HTTP proxy
The logins in the examples are shortened: a string from the Dashboard also carries a filter parameter such as -filter-medium, so copy it whole.
curl -sS --max-time 30 -w '\n' \
--proxy http://proxy.example.invalid:8080 \
--proxy-user 'login-country-us:password' \
https://api64.ipify.org
The command prints the IP the request reached api64.ipify.org from, which is the proxy’s exit address. -sS hides the progress meter but keeps error messages, --max-time 30 caps the request time, and -w '\n' adds a line break after the response.
For an https:// site, curl sends the proxy a CONNECT request with the site’s name and port 443, then encrypts the connection with the site itself. The proxy sees which host you are reaching, but not the page addresses or their content. The scheme in --proxy stays http://: https:// in the proxy address means a TLS connection to the proxy itself, which is a different kind of proxy.
The same request with the login inside the address:
curl -sS --max-time 30 -w '\n' \
--proxy 'http://login-country-us:password@proxy.example.invalid:8080' \
https://api64.ipify.org
Keeping the password out of your shell history
A password in a command like this ends up in your shell history. To avoid that, move the settings into a config file, proxy.conf:
proxy = "http://proxy.example.invalid:8080"
proxy-user = "login-country-us:password"
and pass it with -K:
chmod 600 proxy.conf
curl -sS --max-time 30 -w '\n' -K proxy.conf https://api64.ipify.org
chmod 600 leaves the file readable only by you. Do not publish this file or your proxy strings: they contain your password.
curl through SOCKS5: socks5h or socks5
curl -sS --max-time 30 -w '\n' \
--proxy socks5h://proxy.example.invalid:1080 \
--proxy-user 'login-country-us:password' \
https://api64.ipify.org
The h in the scheme decides who turns the site’s name into an IP address:
| Scheme | Who resolves the site’s name | What the proxy receives |
|---|---|---|
socks5h:// | The proxy | The site’s name, such as api64.ipify.org |
socks5:// | Your device | A ready-made IP address |
With socks5h://, the proxy does the DNS lookup, so the site’s address is chosen for the exit location. With socks5://, your DNS server resolves the name: large sites and CDNs may return it a server near you rather than near the exit IP, and your DNS provider sees which sites you open. If your device cannot resolve the name, curl with socks5:// stops with Could not resolve host before it ever connects to the site.
Instead of the socks5h:// scheme, you can use the --socks5-hostname proxy.example.invalid:1080 flag, which works the same way. An HTTP proxy has no such choice: the CONNECT request carries the site’s name, and the proxy resolves it. The protocols are compared in detail in HTTP vs SOCKS5.
How to check the exit IP
The api64.ipify.org service replies with the address the request came from, over both IPv4 and IPv6. That matters: without the ipv4-true parameter in the login, the exit address may be IPv6. Compare the answer with and without the proxy: if the addresses match, the request bypassed the proxy.
Geolocation services map an IP to a country and city with their own databases, and different databases disagree. So the city one service shows may not match what another site sees.
The loop below asks for the IP three times with a rotating string and three times with a sticky session string:
for login in login-country-us login-country-us-sid-k7m2q9x4ab; do
echo "$login"
for i in 1 2 3; do
curl -sS --max-time 30 -w '\n' \
--proxy http://proxy.example.invalid:8080 \
--proxy-user "$login:password" \
https://api64.ipify.org
done
done
Every curl run opens a new connection. With rotation (a login without -sid-), each new connection gets an IP from the pool afresh, so the addresses change. With a sticky session, all three answers are one address while the session lasts; the session length cannot be set, see sticky session vs rotation.
Within one run, curl reuses the connection. If you pass two URLs in one command, both requests go through one tunnel and leave from one IP, even with rotation:
curl -sS --max-time 30 -w '\n' \
--proxy http://proxy.example.invalid:8080 \
--proxy-user 'login-country-us:password' \
https://api64.ipify.org https://api64.ipify.org
Common errors and what they mean
The number in brackets is curl’s exit code, which the command also returns, so a script can check $?. The messages below come from curl 8.7.1; other versions may word them differently.
| curl message | What it means | What to check |
|---|---|---|
(5) Could not resolve proxy: ... | curl could not find the proxy’s address | The proxy host. The placeholder proxy.example.invalid from the examples never resolves, so an unedited command ends exactly like this |
(7) Failed to connect to ... port 8080 ...: Couldn't connect to server | The connection to the proxy was not established (older curl versions say Connection refused) | The port: 8080 for HTTP, 1080 for SOCKS5. Whether your network, firewall or antivirus blocks outgoing connections to that port |
(56) CONNECT tunnel failed, response 407 | The HTTP proxy did not accept the username or password | That the login was copied whole, without spaces or line breaks; the password; the encoding of special characters if the login is in a URL |
(97) User was rejected by the SOCKS5 server | The SOCKS5 proxy did not accept the username or password | The same as for 407 |
(97) Could not resolve host: ... with the socks5:// scheme | Your device could not resolve the site’s name | The socks5h:// scheme, so the proxy resolves the name |
(28) ... timed out after ... milliseconds | No answer came within the time limit | Your network and whether the site is up. If only the request through the proxy hangs, check that the scheme matches the port |
A drop or a hang right after connecting, such as Proxy CONNECT aborted | The scheme does not match the port, or https:// was used instead of http:// | http:// only with port 8080, socks5h:// with port 1080 |
For an http:// site there is no tunnel: the proxy returns 407 as an ordinary response, and curl exits with code 0 and prints the body of that response, if the proxy sent one. To see the response code, add -w '%{http_code}\n' or -v.
How to see the proxy’s answer
The -v flag shows the whole exchange: lines starting with > are what curl sent, lines starting with < are what came back. Right after > CONNECT comes the proxy’s answer: 200 means the tunnel is open, 407 means the username or password was not accepted.
curl -v -sS --max-time 30 -o /dev/null \
--proxy http://proxy.example.invalid:8080 \
--proxy-user 'login-country-us:password' \
https://api64.ipify.org
The -v output includes a Proxy-Authorization: Basic ... line. That is your username and password in base64, an encoding rather than encryption, and anyone can decode it. Do not publish this output in full.
How the examples were run
The commands were run on November 5, 2026 with curl 8.7.1 on macOS, through local test HTTP and SOCKS5 proxies with a username and password and a local site, not through the Proxeta gateway. That checks the syntax and how curl behaves, but not exit IPs or the real network. The same techniques for code are in proxies in Python, and how the gateway hands out addresses is in what is a backconnect proxy.
Frequently asked questions
How do I pass a proxy username and password to curl?
Use --proxy-user 'username:password', or put them in the proxy address: --proxy 'http://username:password@host:8080'. In the URL form, encode special characters in the password: @ as %40, : as %3A, / as %2F. With --proxy-user, no encoding is needed.
What is the difference between socks5h and socks5 in curl?
With socks5h, the proxy resolves the site’s name; with socks5, your device resolves it and the proxy receives a ready-made IP address. For a proxy with a chosen location, use socks5h: the site’s address is picked for the exit location, and your DNS server does not see which sites you open.
What does a 407 error in curl mean?
407 Proxy Authentication Required means the proxy did not accept the username or password. curl reports it as “CONNECT tunnel failed, response 407”. Copy the login from your Dashboard in full, with no spaces, check the password, and check the encoding of special characters if the login is in a URL.
How do I check that curl goes through the proxy?
Request a service that returns your IP, such as https://api64.ipify.org, with and without the proxy. If the addresses match, the request bypassed the proxy: check the --proxy flag and the address scheme.
Why does curl say Couldn't connect to server or Connection refused?
The connection to the proxy was not established: the port is wrong or blocked on your network, for example by a firewall. On Proxeta residential and mobile proxies, HTTP runs on port 8080 and SOCKS5 on port 1080.