HTTP CONNECT Tunneling: How HTTPS Works Through Proxies
The HTTP CONNECT method is the mechanism that allows encrypted HTTPS traffic to flow through proxy servers. When your browser or application needs to access an HTTPS website through a proxy, it sends a CONNECT request asking the proxy to establish a raw TCP tunnel to the destination. Once the tunnel is established, the proxy simply relays bytes in both directions without inspecting or modifying the encrypted content.
The Problem CONNECT Solves
HTTP proxies can naturally handle HTTP traffic because they understand the protocol — they read the request, forward it, and relay the response. But HTTPS traffic is encrypted, creating a fundamental problem:
The Problem:
Client wants to access https://bank.com through a proxy.
If proxy tries to forward the request normally:
1. Client sends encrypted data to proxy
2. Proxy cannot read the data (encrypted with bank.com's certificate)
3. Proxy does not know what to do with it
4. Connection fails
The Solution — CONNECT creates a TCP tunnel:
1. Client tells proxy: "Connect me to bank.com:443"
2. Proxy opens TCP connection to bank.com:443
3. Proxy tells client: "Connection established"
4. Client performs TLS handshake directly with bank.com THROUGH the tunnel
5. Proxy just relays encrypted bytes back and forthCONNECT Method Step by Step
The Full Flow
Client Proxy Server Target (bank.com:443)
| | |
| 1. CONNECT bank.com:443 | |
| HTTP/1.1 | |
| Host: bank.com:443 | |
| Proxy-Authorization: ... | |
|-----------------------------> |
| | 2. TCP connect to |
| | bank.com:443 |
| |------------------------------->
| | |
| | 3. TCP connection |
| | established |
| |<-------------------------------|
| | |
| 4. HTTP/1.1 200 | |
| Connection Established | |
|<-----------------------------| |
| |
| 5. TLS ClientHello ════════════════════════════════════════>|
| 6. TLS ServerHello + Certificate <═════════════════════════|
| 7. TLS Key Exchange ══════════════════════════════════════>|
| 8. TLS Finished <═════════════════════════════════════════|
| |
| ═══════════ Encrypted Application Data ═══════════════════|
| GET /account HTTP/1.1 |
| Cookie: session=abc123 |
| (proxy CANNOT read any of this) |Raw HTTP Headers
-- Step 1: Client sends CONNECT request to proxy --
CONNECT bank.com:443 HTTP/1.1
Host: bank.com:443
Proxy-Authorization: Basic dXNlcjpwYXNz
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0
-- Step 4: Proxy responds with tunnel confirmation --
HTTP/1.1 200 Connection Established
Proxy-Agent: Squid/5.7
-- Steps 5-8: TLS handshake (binary data, not readable) --
-- After TLS: All data is encrypted end-to-end --What the Proxy Can and Cannot See
What the Proxy Sees
✓ Destination hostname: bank.com
✓ Destination port: 443
✓ Your source IP address
✓ Amount of data transferred (bytes)
✓ Connection duration
✓ Connection timing (when established, when closed)What the Proxy Cannot See
✗ URL path: /account/balance?id=12345
✗ Query parameters: ?search=something
✗ Request headers: Cookie, Authorization, User-Agent
✗ Request body: POST data, form submissions
✗ Response headers: Set-Cookie, Content-Type
✗ Response body: HTML, JSON, images, etc.
✗ Any application-layer data whatsoeverImplementation Examples
Python — How Requests Library Handles CONNECT
import requests
# When you make an HTTPS request through a proxy:
proxies = {"https": "http://user:pass@proxy.example.com:8080"}
response = requests.get("https://bank.com/account", proxies=proxies)
# Behind the scenes, the requests library:
# 1. Connects to proxy.example.com:8080 via TCP
# 2. Sends: CONNECT bank.com:443 HTTP/1.1
# Proxy-Authorization: Basic dXNlcjpwYXNz
# 3. Receives: HTTP/1.1 200 Connection Established
# 4. Performs TLS handshake with bank.com through the tunnel
# 5. Sends the actual GET request encrypted within the tunnel
# 6. Receives encrypted response through the tunnelManual CONNECT with Sockets
import socket
import ssl
import base64
def connect_via_proxy(proxy_host, proxy_port, target_host, target_port,
proxy_user=None, proxy_pass=None):
"""Manually establish a CONNECT tunnel"""
# Step 1: TCP connection to proxy
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((proxy_host, proxy_port))
# Step 2: Send CONNECT request
connect_request = f"CONNECT {target_host}:{target_port} HTTP/1.1\r\n"
connect_request += f"Host: {target_host}:{target_port}\r\n"
if proxy_user and proxy_pass:
credentials = base64.b64encode(
f"{proxy_user}:{proxy_pass}".encode()
).decode()
connect_request += f"Proxy-Authorization: Basic {credentials}\r\n"
connect_request += "\r\n"
sock.sendall(connect_request.encode())
# Step 3: Read proxy response
response = b""
while b"\r\n\r\n" not in response:
response += sock.recv(4096)
status_line = response.split(b"\r\n")[0].decode()
if "200" not in status_line:
raise Exception(f"CONNECT failed: {status_line}")
print(f"Tunnel established: {status_line}")
# Step 4: Wrap with TLS
context = ssl.create_default_context()
tls_sock = context.wrap_socket(sock, server_hostname=target_host)
# Step 5: Send HTTP request through encrypted tunnel
request = f"GET / HTTP/1.1\r\nHost: {target_host}\r\n\r\n"
tls_sock.sendall(request.encode())
# Step 6: Read response
data = tls_sock.recv(4096)
print(data.decode())
tls_sock.close()
# Usage
connect_via_proxy(
proxy_host="proxy.example.com",
proxy_port=8080,
target_host="httpbin.org",
target_port=443,
proxy_user="user",
proxy_pass="pass"
)Node.js — Manual CONNECT
const http = require('http');
const tls = require('tls');
function connectViaProxy(proxyHost, proxyPort, targetHost, targetPort) {
return new Promise((resolve, reject) => {
const req = http.request({
host: proxyHost,
port: proxyPort,
method: 'CONNECT',
path: `${targetHost}:${targetPort}`,
headers: {
'Proxy-Authorization': 'Basic ' +
Buffer.from('user:pass').toString('base64')
}
});
req.on('connect', (res, socket) => {
if (res.statusCode !== 200) {
reject(new Error(`CONNECT failed: ${res.statusCode}`));
return;
}
// Wrap with TLS
const tlsSocket = tls.connect({
socket: socket,
servername: targetHost
}, () => {
// Send request through encrypted tunnel
tlsSocket.write(
`GET / HTTP/1.1\r\nHost: ${targetHost}\r\n\r\n`
);
});
tlsSocket.on('data', (data) => {
resolve(data.toString());
tlsSocket.end();
});
});
req.end();
});
}CONNECT and Proxy Authentication
Authentication happens during the CONNECT phase, before the tunnel is established:
Authentication Flow:
Attempt 1 (no credentials):
Client → CONNECT target:443 HTTP/1.1
Proxy → 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="Proxy"
Attempt 2 (with credentials):
Client → CONNECT target:443 HTTP/1.1
Proxy-Authorization: Basic dXNlcjpwYXNz
Proxy → 200 Connection Established
Important: Authentication is in plaintext (Base64 encoded)
unless the connection to the proxy itself uses TLSError Handling
Common CONNECT errors and their meanings:
| Status Code | Meaning | Solution |
|---|---|---|
| 200 | Connection Established | Success — proceed with TLS |
| 403 | Forbidden | Proxy blocks this destination or your IP |
| 407 | Auth Required | Add/fix Proxy-Authorization header |
| 502 | Bad Gateway | Proxy cannot reach target server |
| 503 | Service Unavailable | Proxy is overloaded |
| 504 | Gateway Timeout | Target server did not respond in time |
def handle_connect_errors(response_line):
status_code = int(response_line.split()[1])
errors = {
403: "Proxy forbids this connection. Check ACLs or destination whitelist.",
407: "Authentication required. Provide Proxy-Authorization header.",
502: "Proxy cannot reach target. Check target host:port.",
503: "Proxy overloaded. Retry after delay.",
504: "Target timed out. Increase timeout or check target availability."
}
if status_code != 200:
raise Exception(errors.get(status_code, f"Unknown error: {status_code}"))Security Implications
Why CONNECT Is Secure
Security guarantees of CONNECT tunneling:
1. End-to-end encryption: TLS between client and target
- Proxy cannot decrypt (does not have target's private key)
- No man-in-the-middle possible (certificate validation)
2. Content integrity: TLS ensures data is not modified
- Proxy cannot inject content
- Proxy cannot modify headers
- Any tampering breaks TLS and triggers errors
3. Authentication isolation:
- Proxy auth (Basic) is separate from target auth
- Target auth happens inside encrypted tunnel
- Proxy never sees target credentialsWhen CONNECT Can Be Attacked
Attack: SSL/TLS Interception (SSL Bumping)
Corporate proxy with custom CA certificate:
1. Client sends CONNECT
2. Proxy accepts, but generates its own certificate for target
3. Client's TLS connects to PROXY (not target)
4. Proxy's TLS connects to TARGET
5. Proxy decrypts, inspects, re-encrypts
Detection:
- Certificate issuer shows proxy CA, not target's real CA
- Certificate pinning fails
- Some browsers show warning
This only works when proxy's CA is trusted by client OS
(corporate environments install custom CA certificates)Frequently Asked Questions
Does every HTTP proxy support the CONNECT method?
Most modern HTTP proxies support CONNECT, but some restrict which ports are allowed. Many proxies only permit CONNECT to port 443 (HTTPS) and block other ports to prevent abuse (like using CONNECT to tunnel non-HTTPS traffic). Check your proxy provider’s documentation for port restrictions.
Is the CONNECT request itself encrypted?
No. The CONNECT request (including the destination hostname and any proxy authentication) is sent in plaintext. Only the traffic after the tunnel is established is encrypted by TLS. To encrypt the CONNECT request itself, you need a TLS connection to the proxy (connecting to the proxy over HTTPS).
Can CONNECT be used for non-HTTPS traffic?
Technically yes — CONNECT creates a raw TCP tunnel that can carry any protocol. However, most proxy servers restrict CONNECT to port 443 for security reasons. If allowed, you could tunnel SSH (port 22), SMTP (port 587), or any other TCP protocol through CONNECT.
Why does my proxy URL start with http:// even for HTTPS targets?
The http:// in the proxy URL refers to the protocol used to communicate with the proxy server — not the target. You connect to the proxy using HTTP (to send the CONNECT request), then establish an encrypted tunnel to the HTTPS target through the proxy. This is standard and correct behavior.
How does CONNECT affect proxy performance?
CONNECT tunnels add minimal overhead. The proxy only handles the initial handshake, then simply relays TCP packets in both directions without inspection. This is actually less work than HTTP proxying (which requires header parsing), making CONNECT tunnels slightly more efficient for high-throughput transfers. For more on proxy performance, see our how proxy rotation works guide.
Conclusion
HTTP CONNECT is the essential mechanism that enables secure HTTPS traffic through proxy servers. By creating a raw TCP tunnel, it allows end-to-end TLS encryption while giving the proxy only minimal metadata (destination hostname and port). Understanding CONNECT is fundamental to working with any proxy infrastructure that handles modern web traffic.
For related topics, see our guides on HTTP vs HTTPS proxies and proxy authentication methods.
- Datacenter vs Residential Proxies: Complete Comparison
- Docker Proxy Setup: Configure Containers to Use Proxies
- Anti-Bot Detection Glossary: 50+ Terms Defined
- Anti-Bot Terminology Glossary: Complete A-Z Reference 2026
- Backconnect Proxies Deep Dive: Architecture and Real-World Performance
- Best Proxies in Southeast Asia: Singapore, Thailand, Indonesia, Philippines
- Datacenter vs Residential Proxies: Complete Comparison
- Docker Proxy Setup: Configure Containers to Use Proxies
- Anti-Bot Detection Glossary: 50+ Terms Defined
- Anti-Bot Terminology Glossary: Complete A-Z Reference 2026
- Backconnect Proxies Deep Dive: Architecture and Real-World Performance
- Best Proxies in Southeast Asia: Singapore, Thailand, Indonesia, Philippines
- Datacenter vs Residential Proxies: Complete Comparison
- Docker Proxy Setup: Configure Containers to Use Proxies
- 403 Forbidden Error: What It Means & How to Fix It
- 407 Proxy Authentication Required: Fix Guide
- Anti-Bot Detection Glossary: 50+ Terms Defined
- Anti-Bot Terminology Glossary: Complete A-Z Reference 2026
Related Reading
- Datacenter vs Residential Proxies: Complete Comparison
- Docker Proxy Setup: Configure Containers to Use Proxies
- 403 Forbidden Error: What It Means & How to Fix It
- 407 Proxy Authentication Required: Fix Guide
- Anti-Bot Detection Glossary: 50+ Terms Defined
- Anti-Bot Terminology Glossary: Complete A-Z Reference 2026