Skip to content
1 GB of residential proxies, free. $0 today, card required.
Builder-time routing runbook

Rust reqwest Proxy Setup: Auth, SOCKS5, and 407 Errors

Configure a reqwest 0.13 proxy with Proxy::all and basic_auth, control system-proxy discovery, add SOCKS5, set timeouts, verify the exit, and fix 407, DNS and TLS errors.

Rust reqwest → DatabayBind the gateway when the Client is built
Rust reqwestHTTP client library
Databay gateway modesClient support is covered below
gw.databay.co:8888
By Databay Research Team10 min runbook

Operating principle

Attach the gateway and credentials in ClientBuilder, keep one pooled Client per route, and observe the exit before any real destination.

Set a reqwest Proxy on the ClientBuilder, Not the Request

reqwest sets proxies on the ClientBuilder, so every request from the built Client follows the same rules. A reqwest::Proxy pairs a proxy URL with an interception rule chosen by its constructor: Proxy::http takes http:// destinations, Proxy::https takes https:// destinations, and Proxy::all takes both. The URL scheme describes the gateway hop, so Databay's endpoint stays http://gw.databay.co:8888 for HTTPS destinations: reqwest opens a CONNECT tunnel and runs destination TLS inside it.

Proxy::basic_auth(user, pass) carries the gateway credential. RequestBuilder::basic_auth sets an Authorization header for the destination instead: it cannot answer the gateway's 407, and any credential it carries is sent toward the destination. Use this setup only for destinations you own or are permitted to access, and follow each destination's terms.

reqwest controlDatabay valueWhat to verify
Proxy::all(url)http://gw.databay.co:8888The scheme is http://; both destination schemes match
.basic_auth(user, pass)Complete dashboard username and proxy passwordRead from the secret store, never passed to RequestBuilder::basic_auth
ClientBuilder::proxy(proxy)The configured ProxyAdded before build(); system-proxy discovery is now off
SOCKS5 proxy URLsocks5h://gw.databay.co:8888The socks feature is compiled; Proxy::all lets HTTPS match

Choose reqwest Cargo Features Before Writing Proxy Code

crates.io lists reqwest 0.13.5 as the current stable release on 2026-10-24, and this guide follows its docs.rs pages. Default features are default-tls, http2, charset and system-proxy, and the feature page shows default-tls enabling rustls. SOCKS URLs need socks, the synchronous client needs blocking, and in 0.13 the json, form and query helpers each need their own feature.

[dependencies]
# Defaults cover HTTP proxying and CONNECT; "socks" adds SOCKS5 URLs.
reqwest = { version = "0.13.5", features = ["socks"] }
tokio = { version = "1", features = ["full"] }

default-features = false also drops system-proxy and the default TLS backend, so name a TLS feature or HTTPS destinations lose TLS support. Per the README, native-tls uses the operating system TLS framework on Windows and macOS and OpenSSL on Linux, where the build fails without OpenSSL unless native-tls-vendored compiles a copy. Leave the unstable http3 feature out: HTTP/3 uses QUIC over UDP, which the Databay gateway does not carry.

Async reqwest Proxy Example With Credentials From the Environment

The example reads the dashboard-issued credential from injected variables, attaches it with basic_auth, and checks the exit before any real destination.

use std::{env, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Injected from the secret store; never hard-coded.
    let user = env::var("DATABAY_PROXY_USER")?;
    let pass = env::var("DATABAY_PROXY_PASS")?;

    let proxy = reqwest::Proxy::all("http://gw.databay.co:8888")?
        .basic_auth(&user, &pass);

    let client = reqwest::Client::builder()
        .proxy(proxy) // also switches off system-proxy discovery
        .connect_timeout(Duration::from_secs(10))
        .timeout(Duration::from_secs(30))
        .pool_idle_timeout(Duration::from_secs(30))
        .build()?;

    // Observe the exit before any real destination.
    let exit = client
        .get("https://api.ipify.org?format=json")
        .send()
        .await?
        .error_for_status()?
        .text()
        .await?;
    println!("observed exit: {exit}");
    Ok(())
}

Prefer build()? to Client::new(), which panics when TLS or resolver setup fails. error_for_status() turns a 4xx or 5xx reply into an Err, so an error page is never read as exit evidence.

Compare the returned IP and country estimate with the username's route, and record the time. The ipify reply, like Databay's What Is My IP page and its https://databay.com/what-is-my-ip/json endpoint, reports one observed exit; it is not proof of anonymity and does not predict the next connection. Response::remote_addr() describes the socket reqwest used, the gateway side of a proxied request, so it cannot replace this check.

Ready to run this for real?

Credentials appear in your dashboard in minutes, on the same gateway and username format this Rust reqwest guide uses.

System Proxy Discovery, NO_PROXY and ClientBuilder::no_proxy()

System proxies are on by default. Without an explicit proxy, a Client reads HTTP_PROXY or http_proxy for HTTP destinations, HTTPS_PROXY or https_proxy for HTTPS destinations, and ALL_PROXY or all_proxy for both, with the scheme-specific variable winning. The default system-proxy feature adds Windows and macOS settings. reqwest 0.13 delegates the lookup to hyper-util, whose matcher documentation treats these variables and NO_PROXY as curl does and consults the operating system only when they are unset. An inherited variable or desktop setting can therefore reroute a plain Client::new().

  • ClientBuilder::proxy() disables automatic system-proxy use.
  • ClientBuilder::no_proxy() clears every proxy added so far and disables system proxies. Use it for a direct control client, never after proxy() on a gateway client.
  • An explicit Proxy has no exclusion list until you attach one through Proxy::no_proxy(), passing NoProxy::from_env() or NoProxy::from_string("localhost, .internal.example"). Entries are comma-separated hosts, IPs or CIDR ranges, and * matches every host.

The environment route also forces the credential into a URL such as http://USER:PASS@gw.databay.co:8888, which can leak through shell history, CI output and crash reports. Prefer the explicit Proxy with basic_auth, and audit variable names, never values.

Route reqwest Through SOCKS5 With socks5h://

The gateway accepts SOCKS5 on the same port; reqwest needs the socks feature for it. The Proxy documentation passes a socks5:// URL to Proxy::http, which matches only http:// destinations, so use Proxy::all when HTTPS traffic must use SOCKS5 too.

// Same credentials and imports as the async example.
let proxy = reqwest::Proxy::all("socks5h://gw.databay.co:8888")?
    .basic_auth(&user, &pass);

let client = reqwest::Client::builder()
    .proxy(proxy)
    .connect_timeout(Duration::from_secs(10))
    .timeout(Duration::from_secs(30))
    .build()?;

The scheme decides who resolves the destination name. The prose documentation shows only socks5://, but the 0.13.5 connector source maps socks5 to local resolution, where the worker sends an IP address, and socks5h to proxy resolution, where the gateway resolves the hostname. reqwest's source also shows basic_auth stored on the proxy URL, where the SOCKS connector reads it for SOCKS5 username and password authentication, although the method's doc text describes the HTTP header.

SOCKS5 adds no encryption of its own; destination TLS still protects HTTPS content. Prefer HTTP CONNECT unless the workload has a tested reason for SOCKS5; HTTP versus SOCKS5 proxies covers the trade-offs.

Timeouts, Pool Reuse and One reqwest Client per Route

The async Client has no request timeout by default, so set each budget:

  • connect_timeout bounds the connect phase, which in the 0.13.5 connector spans the TCP connection to the gateway, the CONNECT or SOCKS5 handshake and, for HTTPS, destination TLS, so a stalled tunnel fails here. It needs a Tokio runtime with the timer enabled.
  • timeout is a total deadline from connecting until the body finishes; RequestBuilder::timeout overrides it per request.
  • read_timeout applies per read and resets after each successful read, which suits streamed bodies.

A Client keeps its pool internally and already uses an Arc, so build one and reuse it. Idle connections stay reusable for pool_idle_timeout, 90 seconds by default, and pool_max_idle_per_host caps how many are kept. A new proxy connection may select an available exit, while a reused connection or tunnel may keep the same one, so consecutive requests can share an exit and a different IP is never promised.

The proxy is fixed at build(), so keep one Client per routing configuration, such as one per dashboard username, and clone it where needed; a Client per request discards the pool.

Blocking reqwest Client or Async Client

The async reqwest::Client requires Tokio. The blocking feature adds reqwest::blocking::Client, which blocks the current thread but takes the same Proxy values and documents the same proxy() and no_proxy() rules; port the example by switching the type and dropping #[tokio::main] and .await. Its timeout covers connect, read and write operations and defaults to 30 seconds, while the async client has none. Never call it inside an async runtime, where it panics when attempting to block; use the async client or tokio::task::spawn_blocking there.

Troubleshoot reqwest Proxy Errors by Hop

Classify the first failing layer before changing anything. Print the error and its source() chain locally: the top-level message names the destination URL and the cause sits deeper. In code, branch on is_connect(), is_timeout(), is_dns() and is_status(), not on message text.

EvidenceHop and layerNext safe check
is_dns()Proxy hop: name resolution on the workerCheck the gw.databay.co spelling and local resolver; socks5:// also resolves the destination here
is_connect() with is_timeout()Proxy hop: TCP, tunnel or handshakeConfirm egress to port 8888, then retest once with a justified budget
HTTPS: send() fails with tunnel error: proxy authorization required; HTTP: a Response with status 407Proxy hop: gateway authenticationConfirm basic_auth sits on the Proxy actually added and the username is complete
tunnel error: unsuccessful or error connecting to socks proxyProxy hop: tunnel refused or SOCKS5 failedCheck the scheme, socks feature and credentials; never switch identities to get around a refusal
Certificate or handshake error after the tunnel opensDestination hop: TLSCheck the backend, trust roots and clock; keep verification on
is_status() with 401, 403 or 429Destination hop: HTTPStop and follow the destination's terms and Retry-After

Quoted strings come from current reqwest and hyper-util sources and may change; RFC 9110 makes 407 the proxy's own challenge, unlike a destination's 401. For TLS, confirm the backend: defaults use rustls, enabling native-tls makes it the default, and tls_backend_rustls() or tls_backend_native() forces one per client. Add a private CA with tls_certs_merge(), not the deprecated add_root_certificate. Never use tls_danger_accept_invalid_certs or its deprecated alias danger_accept_invalid_certs: the documentation warns that any certificate for any site would then be trusted, and neither can fix a 407 or a refused tunnel.

Databay Username Controls and Credential Hygiene for Rust Services

Routing lives in the Databay username, so the Rust code is unchanged when the route changes. Copy the complete username from the dashboard; documented examples are USER-zone-residential-countryCode-us for a US residential exit and USER-zone-residential-countryCode-us-sessionId-abc123 to request a sticky session. Do not invent segments for other pools, and rerun the exit check after each change.

  • Premium Residential takes one country, state, city, ZIP, coordinate or ASN selector at a time.
  • Residential Flex, Datacenter and Mobile target by country or continent.
  • A sticky session requests continuity for up to 1440 minutes on Premium Residential and Residential Flex where available, or up to 120 minutes on Datacenter and Mobile. The IP can change before the window ends. All pools are shared, no product reserves an IP for one customer, and traffic is billed per GB.

Keep the credential in the platform's secret store, inject it as DATABAY_PROXY_USER and DATABAY_PROXY_PASS, and keep it out of source control, images, fixtures, tickets, chat and screenshots. In 0.13.5, basic_auth writes the pair into the proxy URL that the Proxy type's Debug output prints, so never log a configured Proxy with {:?}. Errors may include the destination URL; call without_url() before logging if a query string holds a secret, and rotate the credential after any exposure.

Compare networks on the proxy product overview and reproduce a failing request outside Rust with the cURL proxy guide.

Troubleshooting desk

Questions specific to Rust reqwest

How do I set a proxy in Rust reqwest?
Create the proxy with reqwest::Proxy::all("http://gw.databay.co:8888"), attach the dashboard credentials with basic_auth, and pass it to ClientBuilder::proxy before build(). Reuse that Client, and verify the exit with https://api.ipify.org?format=json before calling the real destination.
Does reqwest use HTTP_PROXY and HTTPS_PROXY automatically?
Yes. System proxies are enabled by default: HTTP_PROXY applies to HTTP destinations, HTTPS_PROXY to HTTPS destinations and ALL_PROXY to both, and the default system-proxy feature also applies Windows and macOS settings. Adding a Proxy or calling ClientBuilder::no_proxy() turns that automatic discovery off.
Why does reqwest fail with a 407 through an authenticated proxy?
The gateway did not receive valid proxy credentials. For an HTTPS destination the 407 answers the CONNECT request, so send() returns an error instead of a Response. Check that basic_auth is on the Proxy you added and the username is complete, and do not use RequestBuilder::basic_auth, which authenticates to the destination.
How do I use a SOCKS5 proxy with reqwest?
Enable the socks Cargo feature, then build the proxy with Proxy::all("socks5h://gw.databay.co:8888") and basic_auth. Proxy::all also covers HTTPS destinations. With socks5h the gateway resolves destination names, while socks5 resolves them on the worker first.
Should I set danger_accept_invalid_certs when a proxied reqwest call hits a TLS error?
No. That method, deprecated in reqwest 0.13 in favor of tls_danger_accept_invalid_certs, makes the client trust invalid certificates for any site and cannot fix proxy authentication or tunnel failures. Identify the TLS backend and trust roots instead, and add a private CA with tls_certs_merge only when your environment requires one.
Does every reqwest request get a new exit IP?
Not necessarily. A Client pools connections, and reuse of a pooled connection or tunnel may keep the same exit. A new proxy connection may select an available exit, but a different IP is not promised. Use a sessionId username to request continuity, and verify the observed exit.
Adjacent runbooks

Same gateway, different control surface

  • cURL

    Command-line client

    curl -> proxy auth -> CONNECT or SOCKS -> approved destination

  • Node.js fetch

    HTTP client library

    fetch -> env opt-in or same-package dispatcher -> proxy evidence

  • Python Requests

    HTTP client library

    Session -> HTTPAdapter policy -> proxy hop -> approved destination

  • .NET HttpClient

    HTTP client library

    HttpClient -> SocketsHttpHandler.Proxy -> CONNECT or SOCKS5 -> observed exit

  • Go net/http

    HTTP client library

    http.Client -> Transport.Proxy -> CONNECT or SOCKS5 -> observed exit

  • Java HttpClient

    HTTP client library

    HttpClient.Builder -> ProxySelector.of -> Authenticator on 407 -> observed exit

Pick the network once the route works. Residential for home-connection exits with state, city, ZIP and ASN targeting; datacenter for fast server IPs on public websites. Switching is one word in the username.

Residential →Datacenter →

Where teams run Rust reqwest behind the gateway: Proxies for web scraping · Proxies for market research

Ship Rust reqwest to production

Create an account, drop in your gateway credentials, and route your first Rust reqwest request in minutes.

Pricing, order minimums, and traffic validity vary by product.