How to Use curl with a Proxy: -x, SOCKS5 and Env Vars

Send curl requests through a proxy with -x, log in with -U, pick HTTP, HTTPS, SOCKS5 or socks5h, use environment variables and read the errors. All tested.

TutorialsPublished Oct 25, 20264 min read

On this page

To send a curl request through a proxy, add -x with the proxy's address and -U with its username and password: curl -x http://HOST:PORT -U "USERNAME:PASSWORD" https://example.com. The scheme in front of the address sets the protocol: http:// or https:// for an HTTP proxy, socks5h:// for a SOCKS5 proxy that also looks up the site's address. curl can also take the proxy from environment variables or a config file, and -v shows exactly what happens between curl and the proxy.

A proxy URL split into five parts: scheme socks5h, username, password, host and port, separated by ://, colon, @ and colon. The scheme sets the protocol: http:// for an HTTP proxy with CONNECT tunnels, https:// for an HTTP proxy reached over TLS like the NanoIP gateway, socks5:// where curl looks up the site's IP itself, and socks5h:// where the proxy looks it up
The scheme sets the protocol; the rest is the login and the proxy's address.

The basic command

bash
curl -x http://HOST:PORT -U "USERNAME:PASSWORD" https://example.com
  • -x (long form --proxy) is the proxy address.
  • -U (long form --proxy-user) is the proxy login. Quote it if the password has characters your shell treats specially.

To see which IP the website sees, request an IP lookup service instead of a normal page. https://ipinfo.io/ip prints the exit IP alone, and https://ipinfo.io/json adds the country, city and network:

bash
curl -x http://HOST:PORT -U "USERNAME:PASSWORD" https://ipinfo.io/json

Login in the URL vs -U

You can also put the login in the proxy URL: -x http://USERNAME:PASSWORD@HOST:PORT. That works until the password contains @, :, / or #, which split the URL in the wrong place. Encode them (@ is %40, : is %3A). In our test, the password p@ss:word worked as p%40ss%3Aword in the URL and unchanged with -U:

bash
curl -x "http://user:p%40ss%3Aword@127.0.0.1:28181" https://example.com
curl -x http://127.0.0.1:28181 -U "user:p@ss:word" https://example.com

Passing the login with -U avoids encoding altogether, which is why we use it in the rest of this guide.

HTTP, HTTPS and SOCKS5 proxies

SchemeProxy typeWhat curl does
http://HTTP proxySends CONNECT to open a tunnel for HTTPS sites, or the whole request for http:// sites
https://HTTP proxy over TLSSame, but the connection to the proxy is encrypted first
socks5://SOCKS5Looks up the site's address itself, then asks the proxy to connect to that IP
socks5h://SOCKS5Sends the site's hostname and lets the proxy look it up

The flags --socks5 and --socks5-hostname do the same as the socks5:// and socks5h:// schemes. If the scheme does not match what the proxy speaks, the request fails without a clear message: in our test, http:// against a SOCKS5 port ended with Recv failure: Connection reset by peer, and socks5h:// or https:// against a plain HTTP proxy hung until curl's time limit.

The SOCKS5 vs HTTP proxy guide explains when to use each protocol.

socks5 or socks5h?

With socks5://, curl looks up example.com itself and sends the proxy an IP address; your local resolver sees the lookup and answers for your location. With socks5h://, curl sends the hostname example.com and the SOCKS5 proxy looks it up in its own network and country
The h in socks5h moves the DNS lookup from your machine to the proxy.

Use socks5h:// unless you have a reason not to. Our test proxy logged what it received for the same request to example.com:

text
socks5://   → the proxy received an IP address (curl had looked it up locally)
socks5h://  → the proxy received "example.com" (the proxy looked it up)

A local lookup is answered by your own DNS resolver, which can return servers chosen for your location rather than the proxy's, and it shows your resolver every site you visit. With socks5h://, the lookup happens on the proxy's side.

Setting the proxy without -x

Environment variables

curl reads these variables when no -x is given:

VariableUsed forNotes from our test
http_proxyhttp:// URLsLowercase only: curl ignored HTTP_PROXY and connected directly
https_proxy or HTTPS_PROXYhttps:// URLsBoth spellings worked
ALL_PROXYEvery URL without a more specific variableWorked with a socks5h:// proxy
NO_PROXYHosts that skip the proxyComma-separated list; * means every host
bash
export https_proxy="http://USERNAME:PASSWORD@HOST:PORT"
curl https://example.com

The login has to go in the URL here, so encode special characters. Other programs read these variables too, so export affects everything you run in that shell; set them on the command itself (https_proxy=… curl …) to limit them to one request.

A config file

curl reads ~/.curlrc on start-up (_curlrc in your application data folder on Windows), and -K FILE reads another file. The same options work there without the dashes:

text
proxy = "http://HOST:PORT"
proxy-user = "USERNAME:PASSWORD"

Which setting wins

Where curl finds its proxy, first match wins: -x on the command line, then proxy in a config file such as ~/.curlrc or -K file, then the environment variables https_proxy, http_proxy and ALL_PROXY, and otherwise no proxy. Hosts in --noproxy or NO_PROXY skip the proxy in every case
Command line first, then the config file, then environment variables.

In our tests, -x beat a wrong https_proxy, and a config file beat it too. Between -x and -K, the one that comes later on the command line wins, so ~/.curlrc, which curl reads first, never overrides your -x. To skip the proxy for one request, use --noproxy '*'; to ignore ~/.curlrc, start the command with -q.

Debugging a proxy connection

See the conversation with -v

-v prints every step. This is the start of a working request through our test proxy:

text
* Connected to 127.0.0.1 (127.0.0.1) port 28181
* Proxy auth using Basic with user 'user'
* Establish HTTP proxy tunnel to example.com:443
> CONNECT example.com:443 HTTP/1.1
> Proxy-Authorization: Basic dXNlcjpwQHNzOndvcmQ=
< HTTP/1.1 200 Connection established
* CONNECT tunnel established, response 200

Lines with > are what curl sent to the proxy, lines with < are the proxy's answer. If the tunnel is not established, the problem is between curl and the proxy, not with the website. Note that Proxy-Authorization is only Base64, not encryption: don't paste -v output with real credentials into tickets or chats.

-I (headers only) through a proxy prints the proxy's HTTP/1.1 200 Connection established first, then the website's own headers, so the first status line you see is not the site's.

Time each step with -w

bash
curl -x http://HOST:PORT -U "USERNAME:PASSWORD" -o /dev/null -s \
  -w 'connect: %{time_connect}s  tls: %{time_appconnect}s  total: %{time_total}s\n' \
  https://example.com

time_connect is the connection to the proxy; the gap between it and time_appconnect is the tunnel plus the TLS handshake with the site. A slow time_connect points at the route to the proxy; a fast connect with a slow total points at the exit or the site.

Errors you will see

The messages for codes 7, 56, 97 and 28 are copied from our tests; code 5 is described in curl's documentation.

Exit codeMessageUsual cause
7Failed to connect to 127.0.0.1 port 1 after 0 ms: Couldn't connect to serverWrong port, or the proxy is not reachable from your network
56CONNECT tunnel failed, response 407Missing or wrong proxy login; see how to fix proxy error 407
56Recv failure: Connection reset by peerWrong scheme, such as http:// against a SOCKS5 port
97User was rejected by the SOCKS5 server (1 1).Wrong SOCKS5 username or password
28Connection timed out after 8006 millisecondsProxy unreachable, or a scheme the proxy does not speak
5Could not resolve proxyThe proxy hostname is mistyped

Using curl with NanoIP proxies

Residential and mobile proxies connect through the HTTPS gateway, with the username and password of a route generated in Dynamic Routes:

bash
curl -x https://gateway.nanoip.net:1111 -U "USERNAME:PASSWORD" https://ipinfo.io/json

Each ISP proxy IP has its own host and port and accepts both HTTP and SOCKS5 with the same login:

bash
curl -x http://HOST:PORT -U "USERNAME:PASSWORD" https://ipinfo.io/json
curl -x socks5h://HOST:PORT -U "USERNAME:PASSWORD" https://ipinfo.io/json

Run the residential command a few times on a rotating route and the IP changes each time; on a sticky route or an ISP IP it stays the same. NanoIP authenticates by username and password only, so the commands work the same from any network. The getting started guide shows where to find each value, and rotating vs sticky sessions explains the session types.

Frequently asked questions

Does curl use my system proxy settings?

No. curl ignores the proxy configured in macOS or Windows network settings. It only uses -x, its config file and the environment variables above.

How do I make curl skip the proxy for some hosts?

Add --noproxy with a comma-separated list, for example --noproxy localhost,example.com, or set NO_PROXY. --noproxy '*' skips the proxy for everything.

Why does my request work in the browser but not in curl?

The browser may be using a different proxy, or none. Check which variables are set with env | grep -i proxy, then pass the proxy explicitly with -x and -U and read the -v output.

Written by NanoIP Team · Proxy infrastructure and customer support team

Related articles

Need help with your setup?

Our support team can check your proxy configuration with you.