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.
gw.databay.co:8888Operating 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 control | Databay value | What to verify |
|---|---|---|
Proxy::all(url) | http://gw.databay.co:8888 | The scheme is http://; both destination schemes match |
.basic_auth(user, pass) | Complete dashboard username and proxy password | Read from the secret store, never passed to RequestBuilder::basic_auth |
ClientBuilder::proxy(proxy) | The configured Proxy | Added before build(); system-proxy discovery is now off |
| SOCKS5 proxy URL | socks5h://gw.databay.co:8888 | The 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 afterproxy()on a gateway client.- An explicit
Proxyhas no exclusion list until you attach one throughProxy::no_proxy(), passingNoProxy::from_env()orNoProxy::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_timeoutbounds the connect phase, which in the 0.13.5 connector spans the TCP connection to the gateway, theCONNECTor SOCKS5 handshake and, for HTTPS, destination TLS, so a stalled tunnel fails here. It needs a Tokio runtime with the timer enabled.timeoutis a total deadline from connecting until the body finishes;RequestBuilder::timeoutoverrides it per request.read_timeoutapplies 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.
| Evidence | Hop and layer | Next safe check |
|---|---|---|
is_dns() | Proxy hop: name resolution on the worker | Check the gw.databay.co spelling and local resolver; socks5:// also resolves the destination here |
is_connect() with is_timeout() | Proxy hop: TCP, tunnel or handshake | Confirm 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 407 | Proxy hop: gateway authentication | Confirm basic_auth sits on the Proxy actually added and the username is complete |
tunnel error: unsuccessful or error connecting to socks proxy | Proxy hop: tunnel refused or SOCKS5 failed | Check the scheme, socks feature and credentials; never switch identities to get around a refusal |
| Certificate or handshake error after the tunnel opens | Destination hop: TLS | Check the backend, trust roots and clock; keep verification on |
is_status() with 401, 403 or 429 | Destination hop: HTTP | Stop 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.
Questions specific to Rust reqwest
How do I set a proxy in Rust reqwest?
Does reqwest use HTTP_PROXY and HTTPS_PROXY automatically?
Why does reqwest fail with a 407 through an authenticated proxy?
How do I use a SOCKS5 proxy with reqwest?
Should I set danger_accept_invalid_certs when a proxied reqwest call hits a TLS error?
Does every reqwest request get a new exit IP?
Same gateway, different control surface
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
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.
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.