`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.
It's a TPROXY based docker container sidecar to proxy all traffic from a docker container to wherever you want.
- `proxy-everything` is interesting because it turns interception into a policy decision, not just a routing trick.
- The repo’s signature move is selective treatment: it can inspect TLS enough to decide whether a connection should be decrypted or passed through untouched.
- Its Linux plumbing matters because TPROXY, marks, and namespace sharing let it hijack traffic without changing the application container.
- The project sits in a narrow niche between service mesh, transparent proxy, and tunnel, which is exactly why it is useful.
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.
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.
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.
| Tool | Scope | Requires app changes? | Selective TLS inspection? | Per-container isolation? | Operational complexity |
|---|---|---|---|---|---|
| proxy-everything | Single container egress | No | Yes | Yes | Medium |
| Istio or Linkerd | Service-to-service traffic | Usually no | Sometimes | Cluster-wide | High |
| mitmproxy or squid | HTTP or web flows | Often yes | Yes | Not by default | Medium |
| sshuttle or VPN | Host or subnet tunnel | No | No | No | Low to medium |
| Manual iptables plus proxy wiring | Whatever you script | No | Sometimes | Depends on setup | High |
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.
- DNS is intercepted instead of ignored, which matters because name resolution is part of the decision surface.
- The proxy can recover the original destination instead of guessing where a packet was meant to go.
- Half-close handling keeps asymmetric protocol shutdowns from breaking.
- Loop prevention keeps the proxy from catching its own outbound connections.
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.
| Category | What it optimizes for | Where it falls short | Why proxy-everything is different |
|---|---|---|---|
| Service mesh | Cluster policy and observability | Heavy operational footprint | This is container-local and narrower. |
| Transparent proxy | Capturing HTTP flows | Usually less selective about TLS | This can choose per connection. |
| VPN or tunnel | Broad traffic transport | Little protocol awareness | This inspects just enough to decide. |
| Manual iptables setup | Maximum flexibility | High setup burden | This 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.