{"id":463,"date":"2026-07-16T03:06:27","date_gmt":"2026-07-16T00:06:27","guid":{"rendered":"https:\/\/mexela.com\/blog\/curl-proxy\/"},"modified":"2026-07-16T04:19:18","modified_gmt":"2026-07-16T01:19:18","slug":"curl-proxy","status":"publish","type":"post","link":"https:\/\/mexela.com\/blog\/curl-proxy\/","title":{"rendered":"cURL Proxy Setup: Auth, SOCKS5, and Testing"},"content":{"rendered":"<p>This cURL proxy guide explains HTTP tunneling, cURL proxy authentication, cURL proxy username password handling, a cURL SOCKS5 proxy, the cURL SOCKS5h DNS choice, cURL proxy environment variables, cURL NO_PROXY rules, and a repeatable cURL proxy command for diagnostics.<\/p>\n<p class=\"mexela-answer\">To use a proxy with cURL, pass its URL with <code>--proxy<\/code>, supply proxy credentials separately with <code>--proxy-user<\/code>, set explicit connection and total time limits, and verify the observed route against an endpoint you own or are authorized to test. Use <code>socks5h:\/\/<\/code> when the proxy should resolve the destination hostname, and use <code>NO_PROXY<\/code> only for destinations that must intentionally bypass the proxy.<\/p>\n<p>A successful command is only one piece of evidence. Reliable cURL proxy testing distinguishes the client-to-proxy connection, proxy authentication, DNS resolution, the proxy-to-destination connection, TLS validation, and the destination&#8217;s HTTP response. The examples below use reserved <code>.invalid<\/code> hostnames and environment variables so they do not expose a real endpoint, password, or customer destination. Replace them only inside an approved test environment.<\/p>\n<h2>Start with an explicit HTTP proxy command<\/h2>\n<p>The smallest useful cURL proxy command identifies the proxy scheme, proxy host, proxy port, destination, and time budget. The <a href=\"https:\/\/everything.curl.dev\/usingcurl\/proxies\/index.html\">Everything curl proxy overview<\/a> documents <code>-x<\/code> and <code>--proxy<\/code>. If the proxy URL has no scheme, cURL treats it as HTTP, but writing <code>http:\/\/<\/code> explicitly makes reviews and incident evidence clearer.<\/p>\n<pre><code class=\"language-bash\">export PROXY_URL=\"http:\/\/proxy.example.invalid:3128\"\nexport APPROVED_TEST_URL=\"https:\/\/status.example.invalid\/proxy-check\"\n\ncurl --proxy \"$PROXY_URL\" \n  --connect-timeout 5 \n  --max-time 20 \n  --fail-with-body \n  --silent --show-error \n  \"$APPROVED_TEST_URL\"<\/code><\/pre>\n<p>For an HTTPS destination reached through an HTTP proxy, cURL normally asks the proxy to create a tunnel with the HTTP CONNECT method. The destination TLS session then travels through that tunnel. The <a href=\"https:\/\/everything.curl.dev\/usingcurl\/proxies\/http.html\">official HTTP proxy chapter<\/a> explains this behavior. The proxy scheme and destination scheme describe different legs of the route, so an <code>https:\/\/<\/code> destination does not automatically require an <code>https:\/\/<\/code> proxy endpoint.<\/p>\n<p>Keep certificate verification enabled. Options such as <code>--insecure<\/code> can make a broken trust path appear healthy and are deliberately absent from these examples. If an approved enterprise gateway inspects TLS, install the correct trusted certificate chain for that environment instead of suppressing validation.<\/p>\n<h2>Separate proxy authentication from destination authentication<\/h2>\n<p>Use <code>--proxy-user<\/code> for the proxy&#8217;s username and password. The shorter form is <code>-U<\/code>. <code>-u<\/code> is for destination credentials and is a separate concern, and mixing the two can send a secret to the wrong authentication layer. The <a href=\"https:\/\/everything.curl.dev\/usingcurl\/proxies\/auth.html\">official proxy authentication guide<\/a> documents the distinction and the available proxy authentication options.<\/p>\n<pre><code class=\"language-bash\">export PROXY_URL=\"http:\/\/proxy.example.invalid:3128\"\nexport PROXY_USERNAME=\"approved-user\"\nexport PROXY_PASSWORD=\"read-from-a-secret-store\"\nexport APPROVED_TEST_URL=\"https:\/\/status.example.invalid\/proxy-check\"\n\n# Short equivalent for proxy credentials:\ncurl -U \"$PROXY_USERNAME:$PROXY_PASSWORD\" --proxy \"$PROXY_URL\" \"$APPROVED_TEST_URL\"\n\ncurl --proxy \"$PROXY_URL\" \n  --proxy-user \"$PROXY_USERNAME:$PROXY_PASSWORD\" \n  --proxy-anyauth \n  --connect-timeout 5 \n  --max-time 20 \n  --silent --show-error \n  \"$APPROVED_TEST_URL\"<\/code><\/pre>\n<p>This is cURL proxy authentication, not application login. A proxy commonly returns HTTP 407 when credentials are missing, invalid, or unacceptable for the requested method. A destination commonly returns 401 or 403 for its own authorization rules. Record which hop produced the response before rotating a password or changing application credentials. The broader <a href=\"\/blog\/proxy-authentication-methods\/\">proxy authentication methods guide<\/a> compares username\/password access with source-IP allowlisting.<\/p>\n<p>The phrase cURL proxy username password often leads to examples with credentials embedded directly in a URL. That can leak through shell history, process listings, screenshots, logs, or copied support tickets. Separate variables improve readability but are not automatically a secure vault. Inject secrets through the operating system, container platform, or CI secret mechanism, restrict access, and redact command traces. Never enable shell tracing around a credential-bearing command.<\/p>\n<h2>Choose SOCKS5 or SOCKS5h from the DNS requirement<\/h2>\n<p>A cURL SOCKS5 proxy can resolve the destination hostname on either side of the connection. With <code>socks5:\/\/<\/code>, cURL resolves the destination hostname locally. With <code>socks5h:\/\/<\/code>, the hostname is sent to the proxy for resolution. The final <code>h<\/code> is therefore an operational DNS decision, not a cosmetic spelling difference. The <a href=\"https:\/\/everything.curl.dev\/usingcurl\/proxies\/socks.html\">official SOCKS proxy documentation<\/a> describes both forms.<\/p>\n<pre><code class=\"language-bash\">export SOCKS_PROXY_HOST=\"proxy.example.invalid:1080\"\nexport APPROVED_TEST_URL=\"https:\/\/status.example.invalid\/proxy-check\"\n\ncurl --socks5-hostname \"$SOCKS_PROXY_HOST\" \n  --connect-timeout 5 \n  --max-time 20 \n  --silent --show-error \n  \"$APPROVED_TEST_URL\"<\/code><\/pre>\n<p>Use cURL SOCKS5h when remote DNS is required for a split-DNS environment, an internal destination known only to the proxy-side resolver, or a controlled test that must avoid local destination lookups. Use local DNS when that is the intended architecture. Neither choice alone proves privacy or suitability. Compare protocol capabilities in the <a href=\"\/blog\/http-vs-socks5-proxies\/\">HTTP versus SOCKS5 guide<\/a>, then validate the actual application path.<\/p>\n<p>DNS can still occur outside the expected path through the application, an operating-system helper, a browser feature, or a second connection. A command-line test covers cURL&#8217;s request, not every program on the device. If DNS exposure matters, use the <a href=\"\/blog\/proxy-dns-webrtc-leaks\/\">proxy DNS and WebRTC leak guide<\/a> to define what must be observed and where.<\/p>\n<h2>Use proxy environment variables deliberately<\/h2>\n<p>cURL proxy environment variables are useful for package jobs, maintenance scripts, and controlled command sessions. According to the <a href=\"https:\/\/everything.curl.dev\/usingcurl\/proxies\/env.html\">official environment variable documentation<\/a>, cURL checks scheme-specific variables such as <code>http_proxy<\/code> and <code>HTTPS_PROXY<\/code>, then <code>ALL_PROXY<\/code> as a general fallback. The lowercase form of <code>http_proxy<\/code> is intentionally required; cURL does not accept uppercase <code>HTTP_PROXY<\/code> because of long-standing security concerns around CGI environments.<\/p>\n<pre><code class=\"language-bash\">export http_proxy=\"http:\/\/proxy.example.invalid:3128\"\nexport HTTPS_PROXY=\"http:\/\/proxy.example.invalid:3128\"\nexport ALL_PROXY=\"socks5h:\/\/proxy.example.invalid:1080\"\nexport NO_PROXY=\"localhost,.internal.example.invalid\"\n\ncurl --connect-timeout 5 \n  --max-time 20 \n  --silent --show-error \n  \"https:\/\/status.example.invalid\/proxy-check\"<\/code><\/pre>\n<p>Command-line options are easier to audit for a one-off diagnostic because the route is visible beside the request. Environment variables are helpful when several commands intentionally share a policy, but they can also create surprising behavior in child processes or scheduled jobs. Document where they are set, scope them to the smallest practical process, and clear them after the test. Do not assume that a browser, SDK, or language runtime interprets the same names identically.<\/p>\n<h2>Define NO_PROXY bypass rules narrowly<\/h2>\n<p>A cURL NO_PROXY value is a comma-separated list of hosts or domains that should bypass the configured proxy. It can also contain IP addresses and, in current cURL versions, CIDR network notation. A leading dot is commonly used to match a domain suffix. The exact rule matters because bypassed traffic leaves directly and will not use proxy authentication, proxy DNS, or proxy egress.<\/p>\n<pre><code class=\"language-bash\">export HTTPS_PROXY=\"http:\/\/proxy.example.invalid:3128\"\nexport NO_PROXY=\"localhost,.internal.example.invalid\"\n\ncurl --noproxy \"$NO_PROXY\" \n  --connect-timeout 3 \n  --max-time 10 \n  --silent --show-error \n  \"https:\/\/health.internal.example.invalid\/ready\"\n\nunset HTTPS_PROXY NO_PROXY<\/code><\/pre>\n<p>Do not use a wildcard bypass merely to make a failing command work. Begin with the exact owned host, confirm why direct routing is required, and review the rule as a network-policy exception. If the direct request still fails, compare DNS, firewall, certificate trust, and destination authorization rather than widening the list. The <a href=\"\/blog\/proxy-troubleshooting-guide\/\">proxy troubleshooting guide<\/a> provides a hop-by-hop diagnostic order.<\/p>\n<h2>Record status, timings, and the observed route<\/h2>\n<p>A robust check should produce structured evidence without printing secrets or complete response bodies. cURL&#8217;s <code>--write-out<\/code> option can report the HTTP response code, remote address, connection time, TLS time, and total duration. The <a href=\"https:\/\/curl.se\/docs\/manpage.html\">official cURL manual<\/a> is the authoritative reference for these variables and for the options available in the installed cURL version.<\/p>\n<pre><code class=\"language-bash\">export PROXY_URL=\"http:\/\/proxy.example.invalid:3128\"\nexport APPROVED_TEST_URL=\"https:\/\/status.example.invalid\/proxy-check\"\n\ncurl --proxy \"$PROXY_URL\" \n  --connect-timeout 5 \n  --max-time 20 \n  --output \/dev\/null \n  --silent --show-error \n  --write-out 'status=%{response_code} remote=%{remote_ip} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}n' \n  \"$APPROVED_TEST_URL\"<\/code><\/pre>\n<p>The remote address reported by cURL must be interpreted in context: with an HTTP proxy, it may be the proxy endpoint rather than the final site&#8217;s address. Your approved diagnostic endpoint should return the source address it observes in a minimal response, allowing you to compare the expected egress. The article on <a href=\"\/blog\/how-to-check-if-a-proxy-is-working\/\">how to check whether a proxy is working<\/a> separates connectivity, identity, location, DNS, and stability checks.<\/p>\n<p>Run a direct baseline first, then one proxied request, then a small bounded sample. Classify failures instead of averaging them away. A connection failure before authentication, an HTTP 407, a TLS validation error, a destination 403, and a read timeout need different corrections. Store timestamps, cURL version, destination name, expected route, response class, and timings, while redacting proxy credentials, tokens, cookies, query strings, and personal data.<\/p>\n<h2>Diagnose common cURL proxy failures by layer<\/h2>\n<p>Start with <code>curl --version<\/code> so the installed protocols and features are known. Then test the destination directly if policy allows, verify that the proxy host and port are reachable, add authentication, and finally compare DNS and TLS behavior. Change one variable at a time. A verbose trace can expose headers and secrets, so use it only in a protected environment, capture the smallest necessary interval, and sanitize it before sharing.<\/p>\n<ul>\n<li><strong>Could not resolve proxy:<\/strong> check the proxy hostname, local DNS, and the network used to reach the proxy.<\/li>\n<li><strong>Connection refused or timed out:<\/strong> verify the port, firewall path, allowlist, and service status before changing credentials.<\/li>\n<li><strong>HTTP 407:<\/strong> confirm that proxy credentials and the required authentication method are correct.<\/li>\n<li><strong>TLS certificate error:<\/strong> inspect the trust chain and proxy inspection policy; do not suppress verification.<\/li>\n<li><strong>HTTP 401 or 403 from the destination:<\/strong> inspect the destination&#8217;s access policy, account state, request identity, and rate limits.<\/li>\n<li><strong>Correct proxy but wrong observed location:<\/strong> confirm the assigned endpoint, provider metadata, and the diagnostic service&#8217;s database rather than assuming one lookup is definitive.<\/li>\n<\/ul>\n<p>If the same route works in cURL but fails in application code, compare how the application handles environment variables, authentication, certificates, redirects, and DNS. The <a href=\"\/blog\/python-requests-proxy\/\">Python Requests proxy guide<\/a> demonstrates the corresponding client configuration. cURL is an excellent controlled probe, but it does not reproduce every browser or SDK behavior.<\/p>\n<h2>Build a responsible production checklist<\/h2>\n<p>Before turning a successful command into a job, define the authorized destinations, allowed request rate, data minimization rules, error budget, retry policy, secret rotation process, and owner. Prefer a documented API when one exists. Respect destination terms, robots guidance where applicable, privacy requirements, and rate limits. A proxy changes routing; it does not grant permission or remove responsibility for the traffic.<\/p>\n<ul>\n<li>Pin or record the cURL version used in production.<\/li>\n<li>Write an explicit proxy scheme, host, and port.<\/li>\n<li>Keep proxy credentials in an approved secret mechanism.<\/li>\n<li>Use <code>--proxy-user<\/code> only for proxy authentication.<\/li>\n<li>Keep TLS certificate verification enabled.<\/li>\n<li>Choose <code>socks5<\/code> or <code>socks5h<\/code> from the DNS design.<\/li>\n<li>Scope environment variables and NO_PROXY entries narrowly.<\/li>\n<li>Set both connection and total time limits.<\/li>\n<li>Use bounded retries only for operations that are safe to repeat.<\/li>\n<li>Record response classes and timings without logging secrets.<\/li>\n<li>Verify the route through an owned or approved endpoint.<\/li>\n<li>Test the real application before increasing traffic.<\/li>\n<\/ul>\n<p>If you are still choosing an endpoint, use the <a href=\"\/blog\/how-to-choose-a-proxy\/\">proxy selection checklist<\/a> to map protocol, authentication, location, concurrency, and support requirements. You can then compare those requirements with Mexela&#8217;s <a href=\"https:\/\/mexela.com\/private-proxies\/\">private proxy service<\/a> instead of selecting a plan from one command alone.<\/p>\n<h2>Frequently asked questions<\/h2>\n<div class=\"mexela-faq\">\n<h3>How do I set a proxy in cURL?<\/h3>\n<p>Pass an explicit proxy URL with <code>--proxy<\/code> or <code>-x<\/code>, add connection and total timeouts, and request an owned or approved test endpoint. For example, an HTTP proxy URL can carry an HTTPS destination through a CONNECT tunnel.<\/p>\n<h3>How do I add proxy authentication without confusing it with site login?<\/h3>\n<p>Use <code>--proxy-user<\/code> or <code>-U<\/code> for proxy credentials. Keep destination authorization separate, load secrets from a protected mechanism, and diagnose an HTTP 407 as a proxy-layer response.<\/p>\n<h3>What is the difference between socks5 and socks5h in cURL?<\/h3>\n<p>With <code>socks5:\/\/<\/code>, cURL resolves the destination hostname locally. With <code>socks5h:\/\/<\/code>, the proxy resolves it. Choose from the intended DNS architecture and verify the observed path.<\/p>\n<h3>Which cURL proxy environment variables should I use?<\/h3>\n<p>Use the lowercase <code>http_proxy<\/code> variable for HTTP destinations, scheme-specific variables such as <code>HTTPS_PROXY<\/code>, or <code>ALL_PROXY<\/code> as a fallback. Scope them narrowly because child processes can inherit them.<\/p>\n<h3>How does NO_PROXY work with cURL?<\/h3>\n<p><code>NO_PROXY<\/code> lists hosts, domain suffixes, addresses, or supported network ranges that should connect directly. Every entry is a bypass exception, so keep the list narrow and verify that direct routing is intentional.<\/p>\n<h3>How can I verify that cURL actually used the proxy?<\/h3>\n<p>Compare a direct baseline with a proxied request to an approved endpoint that reports the source address it observes. Record status and timing data with <code>--write-out<\/code>, then classify authentication, TLS, destination, and timeout failures separately.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Configure a cURL proxy with HTTP or SOCKS5, separate proxy credentials safely, control environment variables and bypass rules, and verify each network hop.<\/p>\n","protected":false},"author":1,"featured_media":462,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[189],"tags":[196,190,191,197,195,192,193,194],"_links":{"self":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts\/463"}],"collection":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/comments?post=463"}],"version-history":[{"count":1,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts\/463\/revisions"}],"predecessor-version":[{"id":464,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts\/463\/revisions\/464"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/media\/462"}],"wp:attachment":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/media?parent=463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/categories?post=463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/tags?post=463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}