Python httpx Tunnel Proxy: Four IP Control Scenarios with Async HTTP

httpx implements four proxy scenarios. httpx.Proxy(headers=...) injects Proxy-Tunnel at the CONNECT stage for HTTPS targets.

16Yun Engineering TeamMay 17, 20261 min read

Why httpx

httpx is a modern async-capable HTTP client for Python. Its key advantage over requests in proxy scenarios: httpx.Proxy(headers=...) injects custom headers at the CONNECT stage natively — no custom Adapter needed.

Setup

export PROXY_HOST=t.16yun.cn
export PROXY_PORT=31111
export PROXY_USERNAME=your-username
export PROXY_PASSWORD=your-password
export PROXY_TUNNEL=httpx-demo-12345

Verify Proxy

curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip

Scenario A: Force New Connection

Create a new httpx.Client per request, disable connection pooling.

import os, httpx
host, port = os.getenv("PROXY_HOST","t.16yun.cn"), os.getenv("PROXY_PORT","31111")
user, pwd = os.getenv("PROXY_USERNAME","user"), os.getenv("PROXY_PASSWORD","password")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"

for i in range(1, 4):
    with httpx.Client(proxy=proxy_url, timeout=15.0,
        limits=httpx.Limits(max_connections=1, max_keepalive_connections=0)) as client:
        resp = client.get("https://httpbin.org/ip",
            headers={"Connection":"close","Proxy-Connection":"close"})
        print(f"Request {i}: {resp.json()['origin']}")

Scenario B: Keep-Alive Same IP

Reuse one httpx.Client with connection pooling enabled.

with httpx.Client(proxy=proxy_url, timeout=15.0,
    limits=httpx.Limits(max_connections=5, max_keepalive_connections=5)) as client:
    for i in range(1, 4):
        resp = client.get("https://httpbin.org/ip",
            headers={"Connection":"keep-alive","Proxy-Connection":"keep-alive"})
        print(f"Request {i}: {resp.json()['origin']}")

Scenario C-HTTP: Proxy-Tunnel for HTTP

tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
with httpx.Client(proxy=proxy_url, timeout=15.0) as client:
    for i in range(1, 4):
        resp = client.get("http://httpbin.org/ip",
            headers={"Proxy-Tunnel":tunnel, "Connection":"keep-alive"})
        print(f"Request {i}: {resp.json()['origin']}")

Scenario C-HTTPS: Proxy-Tunnel for HTTPS

This is where httpx shines. Use httpx.Proxy(headers=...) to inject Proxy-Tunnel at the CONNECT stage.

import httpx
tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"

proxy = httpx.Proxy(url=proxy_url, headers={"Proxy-Tunnel": tunnel})

with httpx.Client(proxy=proxy, timeout=15.0) as client:
    for i in range(1, 4):
        resp = client.get("https://httpbin.org/ip",
            headers={"Connection":"keep-alive"})
        print(f"Request {i}: {resp.json()['origin']} (HTTPS Proxy-Tunnel)")

The headers in httpx.Proxy are sent during the HTTPS CONNECT handshake — no custom adapter required.

Scenario Comparison

Scenariohttpx ApproachCompared to requests
ANew Client per request, no poolSimilar
BReuse Client with poolSimilar
C-HTTPProxy-Tunnel header on requestSame
C-HTTPShttpx.Proxy(headers=...)Simpler, no custom adapter

Troubleshooting

StatusCauseFix
407Proxy auth failedVerify credentials
429Rate limitReduce concurrency
504Target timeoutRetry 2-3 times

Need an enterprise proxy plan?

We can tailor architecture to your target domains, concurrency, and reliability goals.