Routing a cURL request through an explicit proxy keeps outbound tests predictable when a network policy, jump host, or debug run must use a specific egress path. That matters when reproducing browser-independent traffic, proving whether a proxy is altering behavior, or checking that a restricted host can still reach an external service.

Current cURL builds can select HTTP, HTTPS, SOCKS4a, SOCKS5, or SOCKS5-with-remote-DNS from the same --proxy option. The proxy URL scheme decides the transport: http:// or https:// uses an HTTP proxy, socks5h:// lets the proxy resolve the target hostname, and socks5:// resolves the hostname locally before the SOCKS connection starts. The older --socks5 and --socks5-hostname options still work, but current curl documentation notes that the scheme-based --proxy form already covers those modes.

The important choice is where name resolution and bypass logic happen. socks5h:// keeps target DNS on the proxy side, socks5:// exposes the lookup to the local resolver, and --noproxy or NO_PROXY can force selected hosts to skip the proxy entirely. Use --disable during testing so a local ~/.curlrc file does not quietly add or override proxy behavior.

The proxy names, service hostnames, and documentation IP addresses below are masked examples that preserve realistic routing and verification patterns without exposing live infrastructure values.

Steps to use HTTP and SOCKS proxies with cURL:

  1. Send a plain HTTP request through an HTTP proxy with an explicit proxy URL.
    $ curl --disable --silent --show-error --verbose \
      --proxy http://egress-proxy.example.net:3128 \
      http://api.edge.example.net/health -o /dev/null
    * Connected to egress-proxy.example.net (198.51.100.24) port 3128
    > GET http://api.edge.example.net/health HTTP/1.1
    > Host: api.edge.example.net
    > User-Agent: curl/8.7.1
    > Proxy-Connection: Keep-Alive
    < HTTP/1.1 200 OK
    < Via: 1.1 egress-proxy.example.net
    < Content-Type: application/json

    An HTTP proxy relays plain HTTP requests directly, so the request line contains the full target URL rather than only the destination path.

  2. Send an HTTPS request through the HTTP proxy and confirm that the proxy opens a CONNECT tunnel first.
    $ curl --disable --silent --show-error --verbose \
      --proxy http://egress-proxy.example.net:3128 \
      https://api.edge.example.net/health -o /dev/null
    * Establish HTTP proxy tunnel to api.edge.example.net:443
    > CONNECT api.edge.example.net:443 HTTP/1.1
    > Host: api.edge.example.net:443
    < HTTP/1.1 200 Connection established
    * CONNECT tunnel established, response 200
    * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
    > GET /health HTTP/2
    < HTTP/2 200

    If the proxy itself is TLS-protected, change the proxy URL to https://egress-proxy.example.net:443 so cURL negotiates HTTPS to the proxy before tunneling.

  3. Use socks5h:// when the SOCKS proxy should resolve the destination hostname.
    $ curl --disable --silent --show-error --verbose \
      --proxy socks5h://socks-gateway.example.net:1080 \
      https://api.edge.example.net/health -o /dev/null
    * SOCKS5 connect to api.edge.example.net:443 (remotely resolved)
    * SOCKS5 request granted.
    * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
    > GET /health HTTP/2
    < HTTP/2 200

    socks5h:// keeps the target hostname out of the local resolver path, which is usually the safer default for remote-network or privacy-sensitive proxy use.

  4. Use socks5:// only when local DNS resolution is intended before the SOCKS connection starts.
    $ curl --disable --silent --show-error --verbose \
      --proxy socks5://socks-gateway.example.net:1080 \
      https://api.edge.example.net/health -o /dev/null
    * Host api.edge.example.net:443 was resolved.
    * IPv4: 192.0.2.25
    * SOCKS5 connect to 192.0.2.25:443 (locally resolved)
    * SOCKS5 request granted.
    < HTTP/2 200

    socks5:// exposes destination lookups to the local resolver. For legacy SOCKS servers, socks4a:// keeps proxy-side DNS and socks4:// keeps local DNS, but prefer SOCKS5 when the proxy supports it.

  5. Exclude hosts that must go direct with --noproxy so a single command can bypass the proxy without changing the base proxy definition.
    $ curl --disable --silent --show-error --verbose \
      --proxy http://egress-proxy.example.net:3128 \
      --noproxy api.edge.example.net \
      https://api.edge.example.net/health -o /dev/null
    * Host api.edge.example.net:443 was resolved.
    * IPv6: 2001:db8:40::25
    * Connected to api.edge.example.net (2001:db8:40::25) port 443
    * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
    < HTTP/2 200

    The environment form NO_PROXY has the same matching behavior, and current curl documentation notes that it can override an explicit --proxy choice for matching hosts.