`proxy-everything`: The Docker Sidecar That Decides What Your Container Gets to Say

A deep dive into a Go-based transparent proxy that hijacks all container egress, peeks into TLS just enough to choose a path, and can even intercept DNS without touching application code.

8 to 10 min read • View on GitHub • More from cloudflare

A Docker container sits inside a lattice of routed packet paths, with outbound traffic pulled through a narrow gate that splits into two exits. One exit leads to a locked inspection chamber, while the other continues as an untouched tunnel, with tiny DNS packets diverted along the same boundary. This illustrates the repo’s central idea: every connection is intercepted first, then judged.
The whole project in one scene: total interception, then a policy fork at the gateway.

It's a TPROXY based docker container sidecar to proxy all traffic from a docker container to wherever you want.

Key Takeaways

Most proxy tools try to move bytes. proxy-everything tries to make a decision. It catches outbound traffic from a container before the application ever knows there was a proxy, then asks one question: should this connection be opened up, or left encrypted and sent on its way?

A Container With a Gatekeeper

The basic shape is simple and slightly uncanny. A sidecar joins the target container’s network namespace, intercepts egress, and forwards it to a gateway over HTTP CONNECT. The app container stays unchanged. The network behavior changes completely.

A WSJ-style hedcut portrait of gabivlj, rendered from a verified GitHub avatar, on a pure white background. This identifies the project’s visible contributor and grounds the article in a real maintainer rather than a fictional persona.

The Real Trick Is Not Routing. It Is Decision-Making.

The project’s cleverness lives in the fork. It peeks into the TLS ClientHello, extracts SNI, asks the gateway what to do, and then splits the connection into one of two futures. In one, the proxy terminates TLS and the gateway sees plaintext. In the other, it acts like a blind pipe and leaves the stream encrypted.

A close-up of a translucent TLS ClientHello envelope under a desk lamp, with the SNI line exposed just enough for a hand to stamp either MITM or PASS THROUGH. One branch breaks the packet into plaintext segments, while the other keeps it sealed and moving forward. This image explains how the proxy chooses between inspection and forwarding without treating every flow the same.
The signature move is not forwarding. It is choosing whether a connection should be opened or preserved.

This mini-app shows the whole control loop in one glance: intercept, inspect, decide, then either decrypt or pass through.

How TPROXY Makes the Container Look Haunted

The Linux side is what makes the trick invisible. iptables mangle rules mark traffic, policy routing sends the marked packets back to localhost, and SO_TRANSPARENT lets the proxy bind in a way that preserves the original destination. The app thinks it is talking to the internet. The kernel has already moved the walls.

1. Packet leaves container
2. iptables mangle rule marks it
3. Policy routing sends marked traffic to local listener
4. Proxy reads original destination
5. Proxy decides: CONNECT, MITM, or pass through

That is why the system feels more like a border checkpoint than a network redirect. It does not simply reroute traffic. It intercepts, identifies, and then chooses the treatment.

The Sidecar Pattern, Taken to Its Logical Extreme

The deployment model is the whole product. The proxy lives beside the app, not inside it. It gets the privileges needed to change routing, while the application container keeps its own file system and process model clean.

ToolScopeRequires app changes?Selective TLS inspection?Per-container isolation?Operational complexity
proxy-everythingSingle container egressNoYesYesMedium
Istio or LinkerdService-to-service trafficUsually noSometimesCluster-wideHigh
mitmproxy or squidHTTP or web flowsOften yesYesNot by defaultMedium
sshuttle or VPNHost or subnet tunnelNoNoNoLow to medium
Manual iptables plus proxy wiringWhatever you scriptNoSometimesDepends on setupHigh

DNS, Half-Closes, and Other Signs the Author Actually Tried It

The maturity shows up in the edge cases. DNS over UDP gets its own path. Original destinations are recovered from out-of-band data. Half-close behavior is preserved so protocols that depend on it do not hang. Loop prevention is handled with socket options and marks so the proxy does not swallow its own traffic.

Why This Is Not Istio, mitmproxy, or a VPN

The point is not that proxy-everything competes with every networking tool. It does not. It occupies a narrow niche: per-container transparent interception with a runtime decision about whether to decrypt at all.

CategoryWhat it optimizes forWhere it falls shortWhy proxy-everything is different
Service meshCluster policy and observabilityHeavy operational footprintThis is container-local and narrower.
Transparent proxyCapturing HTTP flowsUsually less selective about TLSThis can choose per connection.
VPN or tunnelBroad traffic transportLittle protocol awarenessThis inspects just enough to decide.
Manual iptables setupMaximum flexibilityHigh setup burdenThis packages the whole pattern into a sidecar.

What the Repo Suggests About Cloudflare’s Networking Culture

The code reads like something written by people who are comfortable near the kernel but still want a clean operator experience. The result is not a giant platform. It is a small machine that makes low-level control feel composable.

That is the real story here. proxy-everything turns a Docker container into a programmable network subject, then uses protocol inspection only when the policy needs it. It is precise, a little severe, and unusually honest about what it is doing.