If you've ever opened your proxy service dashboard, you've seen this picture: the same address, the same login, and two ports side by side. One labeled HTTP, the other SOCKS5. Most people pick one at random or out of habit. Meanwhile, behind those two lines sit two completely different protocols that are structured differently at the byte level, see your traffic differently, and behave differently in real clients. This guide takes the difference apart down to the last byte and ends with practical selection tables.

Introduction: why one proxy is issued in two modes, and it's not marketing

Let's start with an honest answer to the question in the title. When Proxeon gives you an address with two ports, behind them is the same machine, the same outbound IP address, and the same account. The difference isn't where the traffic goes. The difference is what language your client speaks with the proxy server on the first leg of the path: from your application to the intermediary.

An HTTP proxy speaks HTTP. It accepts HTTP requests, reads them, understands what you want to retrieve, and fetches the resource itself. It can cache, add headers, and respond with status codes. For anything that isn't HTTP, it has one universal trick: the CONNECT method, which turns it into a dumb pipe.

SOCKS5 doesn't know what HTTP is at all. It's a session-layer protocol: the client says "connect me to this host and port," the proxy opens a TCP connection, and from that moment it simply shuffles bytes back and forth. It doesn't care what's inside: TLS, IMAP, SSH, a database protocol, or your own binary format.

Why not just offer one mode? Because their compatibility differs. Half of enterprise and desktop software only supports HTTP proxies through system settings. A significant portion of network libraries and practically all non-web traffic are more comfortable with SOCKS5. Offering both modes on a single IP means you choose the tool for the client rather than forcing the client to fit the tool.

What you'll learn in this article:

  • what a request to an HTTP proxy looks like at the text level and how it differs from a regular request to a website;
  • exactly what the proxy sees and can modify in transparent HTTP mode;
  • how the CONNECT method works and what remains visible to the intermediary after the tunnel is established;
  • the SOCKS5 byte-level handshake, authentication schemes, and the three ATYP address types;
  • why choosing between domain and IP in a SOCKS5 request affects geolocation and DNS privacy;
  • a comparison across non-HTTP protocols, UDP, overhead, caching, and logging;
  • a "task, protocol, why" table and a breakdown of compatibility in popular clients and libraries.

We won't cover the mechanics of the UDP ASSOCIATE command or the difference between socks5 and socks5h schemes in curl and Python in detail here: those topics have dedicated articles on the Proxeon blog, and we'll link to them where relevant.

Foundations: where the proxy lives in the network stack

For a discussion of protocols to make sense, let's agree on terminology. There isn't much of it.

Three participants and two connections

In any proxy setup there are three parties: the client (your browser, script, mail program), the proxy server (intermediary), and the target server (origin). Between them are two independent TCP connections. First: client to proxy. Second: proxy to target server. The target server only sees the second connection and, accordingly, only the proxy's IP address.

Everything we discuss in this article concerns exclusively the first connection. That's where the difference between HTTP and SOCKS5 lives. The second connection is structured the same way in both cases: a regular TCP connection from the proxy to the target host.

Model layers and why this matters

A useful analogy: imagine a courier service. An HTTP proxy in transparent mode is like a courier who opens your package, reads the address and contents, repackages it if necessary, and can even answer on his own if he has a copy in his warehouse. SOCKS5 is like a courier to whom you give the address and hand over the package sealed. He doesn't know and doesn't want to know what's inside.

In terms of the network model, an HTTP proxy operates at the application layer: it understands request semantics. SOCKS5 operates at the session layer: it deals with concepts like "host," "port," and "connection" and doesn't go any higher.

Where name resolution happens

A separate concept that runs like a red thread through this entire piece: DNS resolution. When you access example.com, someone has to turn the name into an IP address. Your client can do it locally, or the proxy can do it on its side. This determines whose DNS infrastructure you use, what regional response you get from a CDN, and whether information about visited domains leaks into the local network. Remember this point; it'll come up in both the HTTP and SOCKS5 sections.

Authentication

Both HTTP proxies and SOCKS5 can verify username and password, but they do it differently. HTTP uses the Proxy-Authorization header and a 407 response code. SOCKS5 uses a separate subprotocol with method number 0x02. There's also a protocol-independent alternative: authorization by client IP address, where the proxy lets in anyone coming from a pre-approved address. Proxeon supports both options, and the choice between them affects how easy it is to connect clients that can't transmit credentials.

HTTP proxy: absolute URI requests, what the proxy sees and can modify

A regular HTTP request to a website looks like this:

GET /catalog/items?page=2 HTTP/1.1
Host: shop.example

Notice: the request line contains only the path. The host is passed in a separate header. This format is called origin-form. When the client knows it's talking not to the website but to a proxy, it switches to absolute-form: the full URI goes into the request line.

GET http://shop.example/catalog/items?page=2 HTTP/1.1
Host: shop.example
Proxy-Authorization: Basic dXNlcjpwYXNz
User-Agent: my-parser/1.0
Accept: text/html

Why duplicate the host? Historically, absolute form appeared before the Host header and was the only way to tell the proxy where to go. The modern HTTP/1.1 standard requires proxies to accept absolute form and clients addressing a proxy to use it. The Host header is still preserved for compatibility and for the target server, to which the proxy forwards the request in origin-form.

What an HTTP proxy sees

In transparent mode (no encryption between client and target site), the proxy sees absolutely everything in the request and response:

  • the method, the full URL including query parameters;
  • all request headers: User-Agent, Cookie, Authorization, Referer;
  • the entire request body: forms, JSON, uploaded files;
  • the response status, response headers, and response body.

This isn't a side effect. It's a fundamental architectural feature: to forward a request, the proxy must parse it. And since it parsed it, it can do anything it wants with it.

What an HTTP proxy can modify

The standard divides headers into end-to-end and hop-by-hop. Hop-by-hop headers relate to one specific connection and must be removed by the proxy before forwarding. These include Connection, Keep-Alive, Proxy-Authorization, Proxy-Authenticate, TE, Trailer, Transfer-Encoding, Upgrade. That's why your proxy login and password don't fly off to the target site: the Proxy-Authorization header is stripped at the proxy per the standard.

Beyond mandatory cleanup, the proxy can:

  • add a Via header with its name and protocol version; the standard requires this, but in practice anonymous proxies omit it;
  • add X-Forwarded-For with the real client IP; corporate proxies do this, and a proxy you buy for working with external resources should never do it;
  • serve a response from its cache without contacting the target server if the response is marked as cacheable;
  • modify body encoding, add or remove compression, rewrite links in HTML;
  • reject the request with its own response, e.g. 403 or 407.

The 407 Proxy Authentication Required response deserves a special mention. If the proxy requires authorization and the client didn't send it, the proxy responds with 407 and a Proxy-Authenticate header listing the supported schemes. Good clients then repeat the request with Proxy-Authorization. Bad clients show the user an incomprehensible error. Hence the typical setup problem: the application "doesn't see the proxy," when in fact it just can't handle 407.

Let's break it down in practice

The easiest way to see all this with your own eyes: curl with the -v flag.

curl -v -x http://user:pass@gate.proxeon.net:8080 http://httpbin.org/get

In the output you'll see a line like GET http://httpbin.org/get HTTP/1.1 and the Proxy-Authorization header. That's absolute form.

The same request by hand over a socket in Python, so no magic remains:

import socket, base64

creds = base64.b64encode(b"user:pass").decode()
req = (
"GET http://httpbin.org/get HTTP/1.1\r\n"
"Host: httpbin.org\r\n"
f"Proxy-Authorization: Basic {creds}\r\n"
"Connection: close\r\n\r\n"
)
s = socket.create_connection(("gate.proxeon.net", 8080))
s.sendall(req.encode())
print(s.recv(65535).decode(errors="replace"))

There's not a single proxy library here. Just a socket and a correctly composed string. An HTTP proxy in transparent mode is so simple you can write one in an evening, and that's both its strength and its weakness.

Where the name is resolved in HTTP mode

In absolute form, the client passes the hostname to the proxy as-is. The proxy performs resolution. The client doesn't need to know the target server's IP address, and no local DNS query is made. This is convenient, but it leads us to the main limitation: the described scheme only works for unencrypted HTTP. For HTTPS, absolute form is useless because the TLS connection must be established between client and target server, and the proxy can't stand in the middle without breaking the certificate. That's what CONNECT was invented for.

The CONNECT method: turning an HTTP proxy into a TCP tunnel

CONNECT is an HTTP method that asks the proxy not to forward a request, but to establish a TCP connection to the specified host and port, after which it becomes a transparent pipe. The request looks like this:

CONNECT shop.example:443 HTTP/1.1
Host: shop.example:443
Proxy-Authorization: Basic dXNlcjpwYXNz
Proxy-Connection: Keep-Alive

Note the target format: host and port only, no scheme or path. This is the authority-form of a request, the third format after origin-form and absolute-form.

If the proxy agrees, it responds:

HTTP/1.1 200 Connection established

The text after the code can be anything; clients only look at the 2xx. From this point, HTTP is over. Everything the client writes to the socket, the proxy forwards byte-for-byte to the target server, and vice versa. The client begins the TLS handshake right in that socket, as if it were connected to the server directly.

What the intermediary sees after CONNECT

Now here's where it gets interesting. The proxy, which a moment ago was all-seeing, suddenly goes blind. After a successful CONNECT, the proxy knows:

  • the hostname and port from the CONNECT line; this is the only semantic information it received;
  • the time the connection was established and closed;
  • the volume of bytes transferred in each direction;
  • the contents of the TLS ClientHello, if there's TLS inside the tunnel: it contains the SNI (server name) in the clear, the list of supported ciphers, extensions; the modern Encrypted Client Hello extension hides even the SNI, but its support isn't yet universal;
  • nothing at the HTTP level: no URL, no headers, no cookies, no body.

In other words, after CONNECT, an HTTP proxy sees exactly as much as SOCKS5. Host, port, timings, volumes. The visibility difference between the two protocols exists only for unencrypted HTTP traffic, and in 2026 there's very little of that left in real tasks.

CONNECT doesn't have to lead to HTTPS

A common thinking error: CONNECT is only needed for HTTPS. In fact, the standard doesn't limit the tunnel's contents. CONNECT can establish a connection to an IMAP server on port 993, to SSH on port 22, to any TCP service. The only question is whether the proxy's configuration allows it. Many public and corporate HTTP proxies only allow CONNECT to port 443 and sometimes 80 to prevent abuse. Proxeon allows CONNECT to arbitrary ports, but if your software supports SOCKS5, it remains the more natural choice for non-HTTP protocols, as explained below.

Example: TLS through CONNECT by hand

The openssl utility can go through an HTTP proxy on its own:

openssl s_client -proxy gate.proxeon.net:8080 -connect shop.example:443 -servername shop.example

And here's what it looks like in Python using the standard library, with no external dependencies:

import http.client, ssl

conn = http.client.HTTPSConnection("gate.proxeon.net", 8080,
 context=ssl.create_default_context())
conn.set_tunnel("shop.example", 443,
headers={"Proxy-Authorization": "Basic dXNlcjpwYXNz"})
conn.request("GET", "/")
resp = conn.getresponse()
print(resp.status, resp.getheader("server"))

The set_tunnel method does exactly what's described above: sends CONNECT, waits for 200, then wraps the socket in TLS. Note that the TLS context validates the certificate of shop.example, not the proxy. The proxy in this scheme can't substitute the certificate without triggering an error on the client.

CONNECT in HTTP/2 and HTTP/3

In HTTP/2 the CONNECT method is preserved, but it works inside a single multiplexed connection: each tunnel is a separate stream. This lets you hold dozens of tunnels through one TCP connection to the proxy and save on handshakes. Extended CONNECT (with the :protocol pseudo-header) is used for WebSocket over HTTP/2. In HTTP/3 based on QUIC, the CONNECT-UDP specification appeared, which formally allows tunneling UDP through an HTTP proxy. However, this is still exotic in client libraries, and in practice, if you need UDP through a proxy, you'll look toward SOCKS5.

What CONNECT can't do

  • Cache: the tunnel's contents are opaque.
  • Modify headers: they simply aren't visible.
  • Multiplex several target hosts through one tunnel in HTTP/1.1: one CONNECT equals one TCP connection.
  • Transmit UDP in HTTP/1.1 and HTTP/2.

SOCKS5: handshake, authentication, and ATYP

SOCKS5 is described in RFC 1928, and its username/password authentication scheme in RFC 1929. Both specifications fit on a few pages, and that's one of the protocol's advantages: implementing it from scratch isn't hard, so there are many implementations and they rarely diverge in interpretation.

SOCKS5 is a binary protocol. No text, just bytes of a fixed structure. Let's look at the full exchange for a CONNECT command.

Step 1: greeting and authentication method selection

The client sends its version and the list of authentication methods it supports:

05 02 00 02
VER=5 NMETHODS=2 METHODS: 00 (no auth), 02 (username/password)

The server selects one method and replies with two bytes:

05 02
VER=5 METHOD=02 (server requires username/password)

If the server replies 05 FF, it means "none of the proposed methods are acceptable," and the client must close the connection. This is exactly what it looks like at the byte level when you forgot to specify a password and the Proxeon proxy is configured for username authentication.

Step 2: authentication per RFC 1929

If method 02 is selected, the client sends:

01 04 75 73 65 72 04 70 61 73 73
VER=1 ULEN=4 UNAME="user" PLEN=4 PASSWD="pass"

Note: the subprotocol version here is 01, not 05. This is a common source of errors in hand-rolled clients. The server replies:

01 00
VER=1 STATUS=00 (success; any other value means rejection)

Username and password are transmitted in plaintext. If there's an untrusted network between you and the proxy, it's worth remembering. In practice, the connection to the proxy usually goes through your provider's own channel, and the issue is solved at the transport level or by switching to IP authorization.

Step 3: connection request

Now the most important message:

05 01 00 03 0C 73 68 6F 70 2E 65 78 61 6D 70 6C 65 01 BB
VER=5 CMD=01 (CONNECT) RSV=00 ATYP=03 (domain)
LEN=12 ADDR="shop.example" PORT=0x01BB (443)

The CMD field takes three values: 01 CONNECT (outbound TCP connection), 02 BIND (waiting for an inbound connection, practically unused), 03 UDP ASSOCIATE (creating a UDP relay). We covered the mechanics of UDP ASSOCIATE and its pitfalls in a separate article about UDP in SOCKS5; here we'll just note: it's the only one of the two protocols that has UDP natively.

ATYP: domain vs IP

The ATYP field determines the form in which the client passed the destination address:

  • 0x01 IPv4: the next 4 bytes are the address;
  • 0x03 domain name: one length byte, then the name without a trailing zero;
  • 0x04 IPv6: the next 16 bytes are the address.

Seems like a technical detail. In fact, it's one of the most important decisions a client makes, and here's why.

If the client uses ATYP=0x01 or 0x04, it means it performed the DNS resolution itself before sending the request. Your machine queried its DNS server, got an address, and passed the ready IP to the proxy. The consequences:

  • the DNS query left through your local network and is visible to your provider or administrator;
  • you got the IP that DNS returned for your region; for sites behind a CDN, this means a proxy located in another country will contact a "foreign" edge server, which slows the connection and may look anomalous;
  • if your machine doesn't have IPv6, you'll never get an AAAA record and won't use the proxy's IPv6 route even if it has one;
  • if DNS in your network behaves non-standardly, the proxy will get the wrong address, and you'll spend a long time hunting for the cause.

If the client uses ATYP=0x03, the proxy performs the resolution. It uses its own DNS infrastructure, gets an address relevant to its location, and your local network doesn't see which domains you access. For geotargeted tasks, this is critical: the point of a proxy in a certain country is partly lost if the target server is selected by your home network's DNS.

How do you force the client to pass the domain? Depends on the client. In curl and Python libraries this is governed by choosing the socks5 versus socks5h scheme, and that's the subject of a separate breakdown. Here it's important to understand the reason: the letter h stands for "hostname" and enables ATYP=0x03. Without it, the library resolves the name locally.

Step 4: server response

05 00 00 01 C0 A8 01 0A 1F 90
VER=5 REP=00 (success) RSV=00 ATYP=01 BND.ADDR=192.168.1.10 BND.PORT=8080

The REP field contains the result code. It's useful to know them by heart when debugging:

  • 00 success;
  • 01 general server failure;
  • 02 connection not allowed by rules;
  • 03 network unreachable;
  • 04 host unreachable;
  • 05 connection refused by the target server;
  • 06 TTL expired;
  • 07 command not supported;
  • 08 address type not supported.

Code 08 appears on old or simplified implementations that don't support ATYP=0x03 or IPv6. Proxeon supports all three address types.

Why SOCKS5 doesn't parse contents

After the REP=00 response, the SOCKS5 protocol is over. Everything the client writes afterward, the proxy moves into the target connection without analysis. This isn't an implementation limitation; it's a design property. SOCKS5 has no concept of "request" or "header." It doesn't know what HTTP, IMAP, or TLS is. It was given an address and port; it connected two pipes.

Several practical consequences follow:

  • SOCKS5 can't cache: it doesn't understand where one response ends and another begins;
  • SOCKS5 can't add headers or substitute content; the most it can do is close the connection;
  • SOCKS5 can't filter by URL, only by host and port;
  • SOCKS5 works equally well with any TCP protocol, including one you invented yesterday.

The complete SOCKS5 handshake in Python

import socket, struct

def socks5_connect(proxy, user, pwd, host, port):
s = socket.create_connection(proxy)
s.sendall(b"\x05\x02\x00\x02")
ver, method = s.recv(2)
if method == 0x02:
u, p = user.encode(), pwd.encode()
s.sendall(b"\x01" + bytes([len(u)]) + u + bytes([len(p)]) + p)
if s.recv(2)[1] != 0:
raise RuntimeError("auth failed")
elif method != 0x00:
raise RuntimeError("no acceptable auth method")
h = host.encode()
s.sendall(b"\x05\x01\x00\x03" + bytes([len(h)]) + h + struct.pack("!H", port))
reply = s.recv(4)
if reply[1] != 0:
raise RuntimeError(f"connect failed, REP={reply[1]}")
atyp = reply[3]
s.recv({1: 4, 4: 16}.get(atyp, 0) if atyp != 3 else s.recv(1)[0])
s.recv(2)
return s

sock = socks5_connect(("gate.proxeon.net", 1080), "user", "pass", "shop.example", 443)
# sock can then be wrapped in ssl.wrap_socket or handed to any protocol

Thirty lines and you have a working SOCKS5 client that passes the domain (ATYP=0x03) and leaves resolution to the proxy server. It's this simplicity that makes SOCKS5 the de facto standard for programmable access.

Comparison by criteria: where each one wins

Now that the mechanics of both protocols are taken apart down to the bytes, the comparison stops being a matter of taste and becomes a list of measurable differences.

Non-HTTP protocols

SOCKS5 works with any TCP protocol natively: CONNECT command, host, port, done. An HTTP proxy can also do it via CONNECT, but with caveats: the client must be able to send CONNECT for non-HTTP traffic (mail clients can, most CLI tools can't), and the proxy must allow the needed port. Winner: SOCKS5.

UDP

SOCKS5 has UDP ASSOCIATE. An HTTP proxy in versions 1.1 and 2 has nothing, and CONNECT-UDP from HTTP/3 is practically unsupported by clients. If the task involves direct DNS queries, QUIC, voice protocols, or gaming traffic, there's no choice. Winner: SOCKS5, with the caveat that not every SOCKS5 server enables UDP, so check your plan's documentation.

Connection setup overhead

Let's count in round-trips (RTT) between client and proxy, on top of the TCP handshake itself:

  • HTTP proxy, transparent mode, no auth: 0 additional RTT, the request goes out immediately;
  • HTTP CONNECT with auth in the first request: 1 RTT (CONNECT, 200 response);
  • SOCKS5 without auth: 2 RTT (greeting, request);
  • SOCKS5 with username and password: 3 RTT (greeting, authentication, request).

In bytes, the difference is reversed: a complete SOCKS5 handshake with auth fits in about 40 bytes, while CONNECT with Host, Proxy-Authorization, and User-Agent headers easily takes 150 or more. But in real tasks, RTT decides, not bytes. With 50 ms latency to the proxy, SOCKS5 with auth adds 150 ms to each new connection versus 50 ms for CONNECT. If the client reuses connections (keep-alive, pools), this is a one-time cost. If every request opens a new socket, the difference accumulates. Winner by RTT: HTTP. The way to narrow the gap for SOCKS5: IP-based authorization, which removes one RTT.

Caching

Only an HTTP proxy in transparent mode. Not CONNECT, not SOCKS5. Moreover, only unencrypted traffic can be cached, and there's little of that today, so this criterion has gone from decisive to niche. It's relevant for internal build systems, package mirrors, and repeated API queries without TLS inside a trusted perimeter. Winner: HTTP, but with a narrow scope.

Logging

This point is often misunderstood. What can a proxy write to the log in each mode?

  • HTTP transparent: full URL, method, headers, body if desired; response status; volumes.
  • HTTP CONNECT: host and port from the CONNECT line; time; volumes; SNI from ClientHello if desired.
  • SOCKS5 with ATYP=0x03: domain name and port; time; volumes; SNI if desired.
  • SOCKS5 with ATYP=0x01/0x04: only IP and port; the proxy doesn't know the domain; time; volumes; SNI.

For encrypted traffic, CONNECT and SOCKS5 give the intermediary the same visibility. The difference appears only where a SOCKS5 client passes an IP instead of a domain, and then the proxy knows even less. But the target server also receives the request from the "wrong" region in that case, see the ATYP section. A draw with nuances.

Error diagnostics

An HTTP proxy responds with human-readable codes: 407 means auth, 403 means forbidden, 502 means the target is unreachable, 504 means a timeout. Some implementations add a body with an explanation. SOCKS5 responds with a single REP byte, and not every library translates it into a clear message. When debugging in an unfamiliar environment, an HTTP proxy is easier to diagnose. Winner: HTTP.

Multiplexing

An HTTP/2 proxy allows many CONNECT tunnels through a single connection. SOCKS5 requires a separate TCP connection per target. For clients with hundreds of parallel connections, this noticeably reduces load on the network stack and the proxy. But HTTP/2 support toward the proxy in clients is still fragmented. Potential winner: HTTP, actual parity.

Ability to intervene in traffic

An HTTP proxy in transparent mode can change everything. In CONNECT mode and in SOCKS5, it can only tear down the connection. For a client wanting guarantees of traffic integrity, SOCKS5 or CONNECT with TLS inside is best. Winner on predictability: SOCKS5.

Authentication

Both support username and password. HTTP additionally supports Digest, NTLM, and Negotiate schemes, which matters for corporate environments. SOCKS5 formally has the GSSAPI method, but in commercial proxies it's practically never seen. For working with a service like Proxeon this doesn't matter: Basic or an IP whitelist is used there.

What to choose for the task: a table

Let's collect the conclusions into a working tool. The table assumes both modes are available on a single IP, as Proxeon does, and the only question is which port to specify.

TaskRecommended protocolWhy
Browser for manual work or testingHTTP (with CONNECT for HTTPS)All browsers support HTTP proxies with authentication through system settings or extensions; SOCKS5 with username and password in Chromium browsers doesn't work via system proxy, authorization is only possible by IP
HTTP client, scraper, data collector in Python, Node.js, GoSOCKS5 with domain passed (ATYP=0x03)Resolution on the proxy side yields correct regional CDN addresses, libraries support both modes, and SOCKS5 doesn't risk intervening in headers
Scraper with many short connections without keep-aliveHTTP CONNECT or SOCKS5 with IP-based authEvery handshake RTT is multiplied by the number of connections; CONNECT saves 1-2 RTT versus SOCKS5 with a password
Mail client (IMAP, SMTP, POP3)SOCKS5Mail protocols aren't HTTP; desktop clients support SOCKS5 directly, whereas via HTTP proxy they'd require CONNECT to non-standard ports
SSH, database clients, RDP, any TCP protocolSOCKS5Native support in OpenSSH via ProxyCommand or ProxyJump-compatible wrappers, natively in most DB clients; HTTP CONNECT doesn't work everywhere
Applications using UDP: DNS clients, QUIC, voiceSOCKS5 with UDP ASSOCIATEThe only one of the two protocols that has UDP in its specification
Caching proxy for internal builds and HTTP package mirrorsHTTP transparentOnly it understands response semantics and can cache them
Corporate application that only supports Windows system proxyHTTPWinHTTP and Windows system settings work with HTTP proxies; SOCKS support there is limited and without auth
Mobile app on Android or iOS in a test environmentHTTPWi-Fi system settings on both platforms only support HTTP proxies; SOCKS5 would require an app-level proxyifier
Custom software with direct socket workSOCKS5A 30-line implementation, binary format with no parsing, support for any protocol on top, explicit control over where resolution happens
Command-line tools: curl, wget, gitHTTP for wget; SOCKS5 or HTTP for curl and gitwget doesn't support SOCKS at all; curl and git support both modes
Monitoring site availability from different regionsSOCKS5 with ATYP=0x03You need DNS resolution to come from the proxy's region, otherwise you're checking the wrong edge server
Debugging when something's broken and you don't know whyHTTPCodes 407, 403, 502, 504 are clearer than a REP byte, and curl -v shows the entire dialog with the proxy

A four-step selection algorithm

  1. Determine the protocol inside. If it's not HTTP and not HTTPS, take SOCKS5 and don't overthink it.
  2. Check what the client supports. Open its documentation and search for socks5, proxy, CONNECT. If SOCKS5 isn't there or is unsupported without auth, the choice is made for you.
  3. Decide where the domain should be resolved. If the region matters (CDN, geo-dependent content, monitoring), take SOCKS5 with domain passing or HTTP CONNECT: in both cases the proxy resolves.
  4. Assess your connection profile. Many short connections without a pool: look at handshake RTT, choose HTTP CONNECT, or enable IP-based auth.

Compatibility in popular clients and libraries

Theory ends where real clients begin. Below is a breakdown of the behavior of the most common tools as of 2026. Check current versions: behavior changes from release to release.

curl

Supports everything. Schemes in the -x parameter or environment variables: http://, https:// (TLS to the proxy itself), socks4://, socks4a://, socks5://, socks5h://. The difference between socks5 and socks5h is covered in a separate article; here just remember: for resolution at the proxy you need socks5h.

curl -x socks5h://user:pass@gate.proxeon.net:1080 https://shop.example/
curl -x http://user:pass@gate.proxeon.net:8080 https://shop.example/

The environment variables http_proxy, https_proxy, all_proxy are read automatically; all_proxy also accepts SOCKS schemes.

wget

HTTP proxy only. SOCKS isn't supported in any form. If you need wget through SOCKS5, you'll need a system proxyifier.

Python: requests

HTTP proxy out of the box. For SOCKS5 you need the extra PySocks package (installed as requests[socks]).

import requests

proxies = {
"http": "socks5h://user:pass@gate.proxeon.net:1080",
"https": "socks5h://user:pass@gate.proxeon.net:1080",
}
r = requests.get("https://shop.example/api/items", proxies=proxies, timeout=15)
print(r.status_code, r.headers.get("cf-ray"))

For HTTPS through an HTTP proxy, requests automatically uses CONNECT. For HTTP through an HTTP proxy, absolute form is used.

Python: httpx

HTTP proxy out of the box, SOCKS5 via the socksio package (httpx[socks]). The socks5:// scheme in httpx passes the domain to the proxy server. Supports async, which makes it convenient for parallel tasks.

import httpx, asyncio

async def main():
async with httpx.AsyncClient(proxy="socks5://user:pass@gate.proxeon.net:1080") as c:
r = await c.get("https://shop.example/")
print(r.status_code)

asyncio.run(main())

Python: aiohttp

HTTP proxy natively. SOCKS5 via the aiohttp-socks package with the ProxyConnector class, whose rdns parameter controls where resolution happens.

Node.js: fetch and undici

The built-in fetch in Node.js uses undici, which has ProxyAgent for HTTP proxies. For SOCKS5, a separate agent from the ecosystem is used, such as socks-proxy-agent for the http/https modules.

import { ProxyAgent, fetch } from "undici";

const agent = new ProxyAgent({
 uri: "http://gate.proxeon.net:8080",
 token: "Basic " + Buffer.from("user:pass").toString("base64"),
});
const res = await fetch("https://shop.example/", { dispatcher: agent });
console.log(res.status);

Go

The standard net/http supports HTTP proxies via Transport.Proxy and environment variables. Starting with Go 1.13, the socks5:// scheme in HTTP_PROXY is also accepted by the standard library. For fine-grained control, the golang.org/x/net/proxy package is used.

package main

import (
"fmt"
"net/http"
"net/url"
)

func main() {
u, _ := url.Parse("socks5://user:pass@gate.proxeon.net:1080")
tr := &http.Transport{Proxy: http.ProxyURL(u)}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://shop.example/")
if err != nil {
panic(err)
}
fmt.Println(resp.Status)
}

In Go, the socks5 scheme passes the domain to the proxy: no local resolution is performed.

Java

HTTP proxy via system properties http.proxyHost, https.proxyHost or the Proxy object with Type.HTTP. SOCKS via socksProxyHost and Proxy.Type.SOCKS. Auth via the Authenticator class. Starting with JDK 8u111, Basic auth for HTTPS through CONNECT is disabled by default via the jdk.http.auth.tunneling.disabledSchemes property; you have to clear it, otherwise you'll get a 407 with no explanation. This is one of the most common support requests.

.NET

HttpClient with SocketsHttpHandler supports HTTP proxies via WebProxy. Support for SOCKS4, SOCKS4a, and SOCKS5 appeared in .NET 6 and is enabled by the same WebProxy construction with an address like socks5://host:port.

Browsers

Chromium browsers use system proxy settings or the --proxy-server flag. HTTP proxies with auth work: the browser shows a login dialog. SOCKS5 via system settings works without auth; username and password can't be passed. For SOCKS5 with a password you need an extension with the proxy API or IP-based auth. Firefox has its own proxy settings, supports SOCKS5 and the "Proxy DNS when using SOCKS v5" option, which enables ATYP=0x03. Authentication for SOCKS5 isn't natively provided in Firefox either.

Mail clients

Thunderbird uses proxy settings similar to Firefox's and supports SOCKS5 for IMAP and SMTP. Many other desktop mail clients have a dedicated SOCKS5 proxy section in account settings. Mail works through an HTTP proxy only if the client can send CONNECT to ports 993 and 465, which is rare.

System proxyifiers

For applications without their own proxy settings, there are programs that intercept network calls at the system level and redirect them to a SOCKS5 or HTTP proxy. Practically all of them prefer SOCKS5 as transport precisely because it's protocol-independent inside. If your task involves such a tool, have the SOCKS5 port ready.

Compatibility checklist

  • Does the client support SOCKS5? Can it pass username and password in SOCKS5?
  • Does the client resolve the domain itself or hand it to the proxy? Is there a remote DNS setting?
  • Does the client handle 407 correctly and repeat the request with authorization?
  • Does the client use CONNECT for HTTPS or try to send an absolute URI with an https scheme (some ancient libraries do this, and it doesn't work)?
  • Does the client reuse connections to the proxy or open a new one for every request?

Cases from engineering practice

The numbers below are typical for the scenarios described and are given to convey the order of magnitude of the effect, not as a guaranteed result.

Case 1: monitoring storefronts from different regions

A team monitored the availability and prices on its own regional storefronts through proxies from several countries. They used Python and requests with the socks5:// scheme. Periodically the metrics showed the "wrong" price for a region even though the storefront was working correctly. The cause: the library resolved the domain locally, in the office's country, and passed the proxy a ready IP of a CDN edge server. The proxy from another country honestly connected to that address, and the CDN served content determining the region by its own node rather than the client IP. Switching the scheme to socks5h moved resolution to the proxy. The share of anomalous measurements fell to practically zero, and median response time dropped by about a third because the proxy started hitting the CDN node nearest to it.

Case 2: a fleet of data collectors with short connections

An open-price aggregation service made up to several hundred thousand requests per day through SOCKS5 with username and password, opening a new connection for each request. Profiling showed that three handshake RTTs per connection at about 40 ms latency to the proxy added 120 ms of overhead per request, about a quarter of the total time. Two changes: enabled connection pooling in the HTTP client and switched to IP-based auth, removing one RTT. Total time to work through the list dropped by about 30 percent without changing the number of proxies. The protocol stayed SOCKS5, because switching to HTTP CONNECT would have yielded less than pooling.

Case 3: mailboxes and IMAP

A support team was deploying a desktop mail client for several regional offices, where each mailbox had to connect to the mail server through an IP from a specific region. The first attempt through an HTTP proxy failed: the client couldn't do CONNECT for IMAP. Switching to the SOCKS5 port in Proxeon solved the task in minutes, because the client had a native SOCKS5 setting for each account. No additional software.

Case 4: a Java application and the mysterious 407

A corporate integrator was connecting a Java service to an external API through an HTTP proxy with Basic auth. The proxy consistently returned 407 even though the credentials were correct, and curl with the same parameters worked. The cause: starting with a certain JDK update, Basic authentication for CONNECT tunnels is disabled by default. One JVM flag clearing jdk.http.auth.tunneling.disabledSchemes solved the problem. What helped here was precisely that an HTTP proxy responds with a readable code: 407 immediately pointed in the right direction, whereas SOCKS5 would have returned 05 FF in a similar situation, which would be harder to understand without protocol knowledge.

Common misconceptions

  • "SOCKS5 is more secure than an HTTP proxy." For encrypted traffic, both protocols give the intermediary the same visibility: host, port, timings, volumes, SNI. Content security is provided by TLS, not the proxy protocol. The difference exists only for unencrypted HTTP, where a transparent HTTP proxy sees everything.
  • "HTTP proxy doesn't work with HTTPS." It works via CONNECT. It's a standard and ubiquitous mechanism; that's how all browsers reach HTTPS sites through corporate proxies.
  • "SOCKS5 is faster because it's binary." For connection setup, SOCKS5 with auth spends more RTT than HTTP CONNECT. For data transfer, both add nothing: after the handshake it's a pure TCP pipe in both cases. Speed is determined by the proxy channel, not the protocol.
  • "CONNECT is only needed for port 443." The standard doesn't limit the port. The specific proxy's configuration imposes limits.
  • "SOCKS5 always resolves the domain at the proxy." Only if the client passes ATYP=0x03. Many libraries resolve locally by default and pass an IP.
  • "HTTP proxy always adds X-Forwarded-For and reveals my IP." That's the behavior of specific corporate setups, not a property of the protocol. Commercial proxies don't add such headers, and in CONNECT mode it's physically impossible to add them.
  • "The proxy sees my proxy password in the clear, so it sees my site password too." The proxy password is passed to the proxy and per the standard isn't forwarded further. The site password inside a TLS tunnel isn't visible to the proxy.
  • "Since SOCKS5 doesn't parse contents, it can't be restricted." A proxy can restrict by target host, port, volume, speed, and number of connections. Just not by URL.
  • "HTTP and SOCKS5 ports from the same provider are different servers." As a rule, it's the same server and the same outbound IP; only the protocol on the input differs. That's how it is with Proxeon.
  • "In a browser, SOCKS5 with a password is configured the same way as HTTP." No, the system settings of Chromium and Firefox don't pass credentials in SOCKS5. You need IP-based auth or an extension.

FAQ

Can the target site tell whether I came through an HTTP proxy or SOCKS5?

No. The target server only sees the second connection, from the proxy to itself, and in both cases it's a regular TCP connection from the proxy's IP address. The only exception: a transparent HTTP proxy that adds Via or X-Forwarded-For headers. In CONNECT mode and in SOCKS5 that's impossible.

If I use an HTTP proxy for HTTPS, can the proxy peek at or substitute the contents?

Only if it performs TLS interception with certificate substitution, and then your client will see a certificate validation error unless you manually installed that proxy's trusted root certificate. In normal operation, after CONNECT the proxy sees an encrypted stream and can neither read nor modify its contents.

Why doesn't SOCKS5 with a password work in Chrome, while an HTTP proxy with a password does?

Chromium's network stack implementation supports an authentication dialog for HTTP proxies via the 407 mechanism but doesn't implement method 0x02 from RFC 1929 for SOCKS5. This is a decision by the browser developers, not a protocol limitation. The solution: IP-based authorization in the Proxeon dashboard or an extension that manages the proxy via API.

What to do if the proxy returns REP=05 in SOCKS5?

Code 05 means the target server refused the TCP connection: the port is closed, the service isn't running, or the target's firewall is blocking the proxy IP. Check that you passed the correct port and try another proxy address. The proxy itself is working correctly; the problem is on the second half of the path.

What's the difference between REP=02 in SOCKS5 and 403 from an HTTP proxy?

Semantically they're the same thing: the proxy refused to establish the connection per its rules. Usually this means the target port or host is forbidden by the proxy's policy. An HTTP proxy sometimes includes an explanation in the 403 response body; SOCKS5 has only a byte.

Can I use the same username and password for the HTTP and SOCKS5 ports?

With Proxeon, yes: the account is shared, only the port and protocol differ. You don't need to change credentials when switching protocols.

How can I tell whether my client resolves the domain locally or at the proxy?

The most reliable way: run a traffic capture on your interface and see whether a DNS query for the target domain goes out before connecting to the proxy. A simpler way: temporarily point the target domain in your hosts file to a deliberately wrong address. If requests through the proxy keep working, the proxy resolves. If they break, the client resolves.

Should I use HTTP/2 to the proxy if my library supports it?

If you have many parallel connections to different targets and the client actually multiplexes CONNECT streams, the gain will be noticeable: fewer TCP connections, fewer handshakes. But support for this in clients and proxy servers is uneven for now. Check your client's documentation and confirm whether your plan supports HTTP/2 on the input.

Why does an HTTP proxy use an absolute URI if there's a Host header?

The HTTP/1.1 standard requires the client to use absolute form when addressing a proxy so the proxy unambiguously understands that the request must be forwarded rather than handled locally. The Host header is preserved because the proxy forwards the request to the target server in origin-form, and Host is mandatory there. The duplication is the price of compatibility.

What matters more for scraping: HTTP or SOCKS5?

For HTTPS targets there's no difference in visibility, only in how the library behaves. If the library works well with SOCKS5 and passes the domain, take SOCKS5: it doesn't risk intervening in headers and gives correct regional resolution. If the library is finicky with SOCKS5 or you have many short connections without a pool, HTTP CONNECT is no worse. The main piece of advice: don't open a new connection to the proxy for every request, that's more expensive than any protocol choice.

Conclusion

The two ports in your dashboard aren't a marketing pair of "basic and advanced." They're two different languages for talking to the same machine. An HTTP proxy speaks the language of requests and responses, understands semantics, can cache, and explains errors with readable codes, and for anything it doesn't understand it has CONNECT, which turns it into a TCP tunnel. SOCKS5 speaks the language of "host and port," doesn't parse contents, supports any TCP protocol and UDP, and lets you explicitly control where the domain is resolved.

For encrypted traffic, both protocols give the intermediary the same visibility. The choice between them is determined not by security but by three practical things: what your client supports, what protocol is inside, and where you want names resolved.

What to do now

  1. Determine the protocol inside your task. Not HTTP: go straight to SOCKS5.
  2. Check your client's documentation for SOCKS5 with authentication and the remote resolution option.
  3. If you work with geo-dependent resources, make sure the domain reaches the proxy: socks5h, remote DNS, ATYP=0x03, or HTTP CONNECT.
  4. Enable connection pooling or keep-alive to the proxy. That'll give you more than any protocol switch.
  5. If the client can't pass a username in SOCKS5, configure IP-based authorization in the Proxeon dashboard.
  6. When debugging, start with curl -v: it'll show the entire dialog with the proxy and immediately separate a client problem from a network problem.

And finally. Both protocols are older than most engineers who use them, and both still work without fundamental changes. This is a rare case where simplicity of design won out. By understanding exactly what happens in the first forty bytes of a connection, you stop choosing a port at random and start choosing a tool.