HTTPS Proxy CONNECT: How the Tunnel Works and How to Debug It

When you send an HTTPS request through an HTTP proxy, your client first sends a plain-text CONNECT host:443 request. The proxy opens a TCP connection to that host and port and answers with a 2XX status. After that it forwards raw bytes in both directions without reading them. Your TLS handshake then runs end to end with the destination site, so the proxy never sees the content.
That one handshake explains most of the confusing behavior engineers run into: why a proxy that serves plain HTTP fine rejects HTTPS, why a 407 shows up before any page loads, and why you can't read or cache HTTPS traffic at the proxy. This guide walks through the exchange, shows it in curl and Python, and lists the failure modes in the order we would check them.
TL;DR
CONNECTasks a proxy to open a blind TCP tunnel to a host and port. Any 2XX reply means the proxy has switched to tunnel mode.- TLS is negotiated between your client and the destination, not the proxy. The proxy can authenticate you and filter by host and port, but it cannot inspect the encrypted stream.
- Most failures come from three places: proxy credentials (407), a port or host the proxy won't tunnel to (403), or a proxy that doesn't allow
CONNECTat all. CONNECTcarries TCP only. UDP-based traffic such as HTTP/3 needs newer mechanisms.
Table of Contents
- What the CONNECT method does
- "HTTPS proxy" can mean two different things
- Making a CONNECT request in practice
- Reading the status line: where CONNECT fails
- What CONNECT can't do
- Where CONNECT shows up in server and gateway setups
- Our perspective: why CONNECT behavior matters for mobile proxies
- A short checklist for a CONNECT that won't connect
- Try it on real mobile IPs
- FAQ
- Sources
What the CONNECT method does
An ordinary HTTP proxy request names a full URL. The proxy reads it, fetches the page, and returns the response. That works because the proxy can see everything. HTTPS breaks that model, because the request is encrypted before it leaves your machine.
The fix is to ask the proxy for a pipe instead of a page. MDN describes CONNECT as a request for the proxy to establish an HTTP tunnel to a destination server and, if that succeeds, blindly forward data both ways until the tunnel closes. The request target is unusual: it holds only the host and port, separated by a colon.
Here is the whole exchange on the wire:
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Proxy-Authorization: Basic dXNlcjpwYXNz
HTTP/1.1 200 Connection established
(TLS ClientHello goes here, straight to example.com)
Three things to notice:
- The first message is plain text, even though the next one is encrypted. That is why the proxy can read your
Proxy-Authorizationheader and your target host, and nothing else. - The proxy's job after the 200 is only to move bytes. MDN's proxy guide frames this as using a higher-level protocol (HTTP) to carry a lower-level one (TCP).
- The target port is nearly always 443, but the method doesn't require it. That is a security question for the proxy operator, covered below.
Why you can't see inside the tunnel
Because the TLS handshake happens between your client and the destination, the certificate your client validates belongs to the real site. The proxy cannot decrypt, cache, or modify the stream. For scraping and data collection this is a feature: your requests reach the target exactly as your client built them, and the proxy sees only a host, a port, and byte counts.
There are proxies that do decrypt HTTPS, by terminating TLS themselves and presenting their own certificate. That is a different design, usually found in corporate inspection setups, and your client has to trust the proxy's certificate for it to work. It is not what CONNECT tunneling does.
"HTTPS proxy" can mean two different things
The phrase causes real confusion, and it is worth separating the two meanings before you debug anything.
| What people say | What it means | What you configure |
|---|---|---|
| HTTPS through a proxy | Your traffic to an HTTPS site travels over a CONNECT tunnel. The connection to the proxy itself is usually plain HTTP. | A normal http://proxy:port URL |
| HTTPS proxy (TLS to the proxy) | The connection between you and the proxy is itself wrapped in TLS, then a CONNECT runs inside it. | A proxy URL starting with https:// |
The first is the common case, and it is the one most proxy providers mean. Your credentials in the CONNECT request travel unencrypted to the proxy in that setup, which matters on untrusted networks. The second adds a TLS layer on the first hop. For a deeper look at the trade-off, see our HTTP vs HTTPS proxy decision rules.
In both cases, the traffic to the destination is protected by the end-to-end TLS session, and the https:// scheme in the proxy URL only describes the first hop.
Making a CONNECT request in practice
With curl
The everything curl guide notes that curl treats whatever you pass to -x or --proxy as an HTTP proxy by default, and uses port 1080 if you don't give one. When the target URL is HTTPS, curl issues CONNECT on its own.
curl -v -x http://USER:[email protected]:8080 https://httpbin.org/ip
Run it with -v and read the output. You will see the CONNECT httpbin.org:443 line go out, the proxy's status line come back, and only then the TLS handshake. If the status line is anything other than 2XX, the problem is the proxy, not the website.

To force a tunnel for a plain HTTP target, add --proxytunnel (-p). It is rarely needed, but it helps when you want to rule out proxy-side rewriting.
With Python requests
import requests
proxies = {
"http": "http://USER:[email protected]:8080",
"https": "http://USER:[email protected]:8080",
}
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
print(r.status_code, r.text)
Note that the https key names the scheme of the target URL, not the scheme of the proxy. Both entries usually point at the same http:// proxy address. Putting https:// in the proxy value tells the library to speak TLS to the proxy, which only works if the proxy listens for TLS.
In other stacks
The same pattern holds almost everywhere: you give the library a proxy URL, and it runs CONNECT whenever the target is HTTPS. Language-specific details differ mostly in where credentials go. We cover the common ones in our guides for Node.js with Axios, Java and Apache HttpClient, and C# HttpClient with SocketsHttpHandler. Some HTTP clients also document CONNECT tunneling alongside SOCKS support, as the httpx proxy plugin wiki does for Ruby.
Reading the status line: where CONNECT fails
Most debugging comes down to the response to the CONNECT. Check it before you touch your scraper code.
| Response to CONNECT | Likely cause | First thing to check |
|---|---|---|
| 200 then TLS error | Tunnel works; the problem is between you and the site | Certificate, SNI, TLS version, system clock |
| 407 Proxy Authentication Required | Missing or wrong proxy credentials | Username format, URL-encoded special characters, auth scheme |
| 403 Forbidden | Proxy policy blocks the host or port | Target port, allowlist, account permissions |
| 405 or 501 | Proxy doesn't support or allow CONNECT | Proxy type and configuration |
| 502 or 504 | Proxy could not reach the destination | Target host, DNS, upstream health |
| Connection reset or timeout before any status | Network path or proxy port is wrong | Proxy host and port, firewalls |
A useful habit: separate the layers. The proxy hop, the tunnel, and the TLS session with the destination each fail in different ways. Our proxy error troubleshooting guide goes through finding the failing layer fast.
407 on the CONNECT, not on the page
A 407 during a tunnel setup surprises people because they expect authentication to happen on the HTTPS request. It can't: that request is encrypted and the proxy can't read it. Credentials have to be presented on the plain-text CONNECT. If your client sends them only after the tunnel opens, they never reach the proxy.
Common causes include special characters in the password that aren't URL-encoded, a client that waits for a challenge it should answer preemptively, and credentials sent for the wrong proxy in a chain. Our walkthrough on fixing 407s with curl covers the auth schemes in detail.
The proxy handles GET but refuses CONNECT
This is the classic trap. Wikipedia's HTTP tunnel article is the reference for the observation that a proxy forwarding plain HTTP requests may still have tunneling disabled or restricted. If HTTP URLs work and HTTPS URLs fail with 403, 405 or 501, test the same proxy with curl -v against an HTTPS target and read the status line. Then ask the proxy's operator whether CONNECT is permitted for your account and the port you need.
Port restrictions
The method itself doesn't limit the port, so operators do. An open proxy that tunnels anywhere can be abused to relay spam over SMTP or to reach internal SSH servers, which is why MDN flags this risk and many administrators allow only specific destinations. In practice that often means port 443 only. If your tool connects to a non-standard HTTPS port and gets a 403 from the proxy, the access control list rejected it before the request left the network.
Chained proxies
CONNECT is hop-by-hop. MDN notes that a proxy forwards a CONNECT request only when another proxy sits in front of the origin, since most origin servers don't implement the method. If you chain proxies, every hop must allow CONNECT, and a failure at the second hop can look like a failure at the first. Test each hop alone with curl before combining them.
What CONNECT can't do
CONNECT tunnels TCP. It has no native way to carry UDP, which matters for QUIC and HTTP/3. Cloudflare's primer on proxies explains why HTTP-based tunneling became a standard, reusable building block, and the newer MASQUE work exists to cover what CONNECT can't. One of those standards, RFC 9484, defines how to proxy IP packets in HTTP.
For scraping and data collection this rarely bites, since the vast majority of target sites still negotiate HTTP/1.1 or HTTP/2 over TCP, and clients fall back automatically. If you need a protocol-level choice between tunneling HTTP and a general-purpose relay, see our comparison of SOCKS5 and HTTP proxies, including DNS leak tests.

Where CONNECT shows up in server and gateway setups
If you run infrastructure rather than a scraper, you will meet CONNECT from the other side. The NGINX documentation on a CONNECT forward proxy and the Envoy Gateway task on HTTP CONNECT tunnels both describe tunnels used for HTTPS traffic through a proxy. The Squid wiki on HTTPS lays out the choices a proxy has when a client requests an https:// URL: tunnel it, or intercept it. Whichever you run, keep the allowlist tight: restrict destination ports, require authentication, and log the CONNECT targets.
Our perspective: why CONNECT behavior matters for mobile proxies
We run a mobile proxy network with real US carrier IPs in 46 cities, and most support questions we see about HTTPS come back to the same few points. Almost everything a customer's client does with our proxies starts with a CONNECT. So the handshake is the first place we look, and it should be yours too.
A few habits we recommend to teams building scrapers and monitoring jobs:
- Read the CONNECT status first. A 200 means the proxy hop is healthy. If the page then fails, the cause is on the destination side: TLS, rate limits, or the site's own defenses. A 407 means credentials, full stop.
- Match session type to the job. Sticky sessions keep one IP for a stretch of related requests, which suits logins and multi-step flows, and rotating sessions spread independent requests across IPs. Each new tunnel is a new
CONNECT, so how often your client reconnects decides how often your exit IP can change. Our notes on session management for stable proxy workflows go through this. - Test with curl before code. One verbose curl call against a known endpoint takes seconds and tells you whether the proxy, your credentials and your network path all work. It removes your scraper from the list of suspects.
- Keep credentials per person or per job. Separate credentials make it easy to see who generated which traffic and to revoke one without disturbing the rest. We built credential management for teams and organizations around that idea.
The tunnel is what makes real mobile IPs usable for HTTPS targets: your client talks TLS directly to the destination, and the destination sees a carrier IP rather than a datacenter range. That is the reason we build on carrier IPs and support HTTP, HTTPS and SOCKS5 across common environments.
— Jon
A short checklist for a CONNECT that won't connect
- Confirm host and port. A typo here looks like a timeout or reset with no status line at all.
- Run
curl -vthrough the proxy to an HTTPS URL. Find theCONNECTline and the status that follows. - If 407, fix credentials. URL-encode special characters and confirm the username format your provider expects.
- If 403, check the target port and host. Standard 443 is the safest assumption for HTTPS.
- If 405 or 501, ask whether CONNECT is enabled for your account or proxy type.
- If 200 but TLS fails, look past the proxy. Check the clock, TLS version and certificate store on your machine.
- Only then debug your application code. Retries, timeouts and concurrency come last.
If you're comparing providers for a scraping or monitoring project, the features data teams should compare first is a good criteria list, and access control for teams is covered in private proxy benefits for secure team access.
Try it on real mobile IPs
If you want to run the curl test above against real US carrier IPs, Masklabs gives you HTTP, HTTPS and SOCKS5 access with sticky or rotating sessions and city-level targeting across 46 US cities. Billing is metered per byte, and you set up credentials yourself, with no sales call. Plans on the pricing page start with Starter at $30.00 per month, then Basic at $100.00, Advanced at $500.00 and Scale at $1,000.00 per month. There is also a free trial with limited data, which is plenty for a handful of CONNECT tests.
FAQ
What is an HTTP CONNECT proxy?
It is a proxy that accepts the CONNECT method and opens a TCP tunnel to the host and port you name. After the proxy replies with a 2XX status, it passes bytes between you and the destination without reading them. This is how HTTPS traffic crosses an HTTP proxy.
Can a proxy see my HTTPS traffic through a CONNECT tunnel?
Not the content. The proxy sees the destination host and port from the CONNECT line, your proxy credentials, and how much data moves. The TLS session runs between your client and the destination, so page content, headers and cookies stay encrypted. The exception is a proxy that deliberately intercepts TLS, which requires your client to trust its certificate.
Do I use http:// or https:// in the proxy URL?
Use http:// unless your provider says its proxy endpoint accepts TLS connections. The scheme describes how you talk to the proxy, not how you reach the target site. HTTPS targets work fine over an http:// proxy URL because the client issues CONNECT and then negotiates TLS with the site.
Why does my proxy return 403 or 405 on CONNECT?
A 403 usually means the proxy's policy blocks that destination host or port, and many operators allow only port 443. A 405 or 501 means the proxy doesn't support or allow the method at all. Confirm with curl -v against an HTTPS URL, then check your account's permissions with the operator.
Does CONNECT work for HTTP/3 or UDP?
No. CONNECT tunnels TCP only. Newer mechanisms such as MASQUE address UDP and IP proxying, but for typical scraping over HTTP/1.1 or HTTP/2, a standard CONNECT proxy is all you need.
Sources
- CONNECT request method, MDN
- Proxy servers and tunneling, MDN
- HTTP proxy, everything curl
- HTTP tunnel, Wikipedia
- A Primer on Proxies, Cloudflare Blog
- RFC 9484: Proxying IP in HTTP
- HTTP CONNECT Tunnels, Envoy Gateway
- Feature: HTTPS, Squid Web Cache wiki
- Proxy plugin, httpx wiki