What happened?
In local development for Cloudflare Containers with outbound traffic interception enabled, the proxy-everything sidecar installs TPROXY rules in the mangle PREROUTING chain before excluding Docker bridge-to-bridge traffic.
This allows Docker bridge internal traffic, including local runtime / sidecar / container control-plane traffic, to enter the transparent proxy path. In a real local app this showed up as container readiness checks being aborted or timing out, and outbound interception callbacks becoming unreliable.
This report is intentionally separate from #6790. That issue describes a broader Sandbox terminal readiness timeout. This issue is narrower and focuses only on the local Containers sidecar networking rule ordering.
Minimal reproduction
Repository: https://github.com/iGmainC/workerd-container-sidecar-tproxy-repro
The repro contains only:
- one Worker entrypoint
- one
Container Durable Object
- one
outboundByHost virtual host
- one Node HTTP server in the container
- one script that inspects the local sidecar iptables rules
Run:
In another terminal:
curl -sS http://127.0.0.1:5173/egress
bun run inspect:sidecar
The /egress endpoint starts the container and makes it call:
http://sidecar-tproxy-repro.internal/echo
That virtual host is handled by EgressReproContainer.outboundByHost.
Observed behavior
On affected local workerd builds, the sidecar mangle PREROUTING chain lacks a Docker bridge bypass before the TPROXY / DIVERT rules. The relevant rule order looks like:
-P PREROUTING ACCEPT
-A PREROUTING -p tcp -m socket -j DIVERT
-A PREROUTING -p tcp -j DOCKER_PROXY_ANYTHING_TPROXY
-A PREROUTING -p udp -m udp --dport 53 -j DOCKER_PROXY_DNS_TPROXY
In a larger local app using the same Containers outbound interception feature, this led to logs like:
Error checking if container is ready: The operation was aborted
[ERROR] e = kj/timer.c++:30: overloaded: operation timed out
[ERROR] Container failed to start
Expected behavior
The documented feature is that outbound requests from the container can be handled by Worker handlers using outboundByHost / outbound interception:
https://developers.cloudflare.com/containers/platform-details/outbound-traffic/
The local sidecar should not break local Docker bridge control-plane traffic while implementing that interception. Docker bridge-to-bridge traffic should be excluded before the generic TPROXY / DIVERT rules.
Local mitigation verified
Inserting a Docker bridge CIDR bypass before the sidecar proxy rules fixes the local behavior:
iptables -t mangle -I PREROUTING 1 \
-s 172.17.0.0/16 \
-d 172.17.0.0/16 \
-j RETURN
With the rule installed first, the sidecar rule order becomes:
-P PREROUTING ACCEPT
-A PREROUTING -s 172.17.0.0/16 -d 172.17.0.0/16 -j RETURN
-A PREROUTING -p tcp -m socket -j DIVERT
-A PREROUTING -p tcp -j DOCKER_PROXY_ANYTHING_TPROXY
-A PREROUTING -p udp -m udp --dport 53 -j DOCKER_PROXY_DNS_TPROXY
The exact bridge CIDR may differ by Docker configuration. The runtime already knows the Docker bridge subnet when creating the sidecar, so this can be derived rather than hard-coded.
With this mitigation applied after sidecar start / recovery, local container startup and outbound interception callbacks complete normally.
Why this looks like a bug rather than expected behavior
The Containers docs describe local outbound interception as a way to route container outbound HTTP/HTTPS through Worker handlers. They do not document any requirement for application code to manually repair sidecar iptables rules or to avoid Docker bridge internal traffic.
The Containers FAQ also says user containers do not support arbitrary iptables manipulation, which reinforces that this should be handled by the local runtime / sidecar implementation rather than by application code.
Environment
OS: Linux
Docker: local Docker bridge network
wrangler: 4.95.0
@cloudflare/vite-plugin: 1.39.0
@cloudflare/containers: 0.3.4
Feature used: Containers outbound traffic interception / outboundByHost
Local dev command: vite --host 127.0.0.1
What happened?
In local development for Cloudflare Containers with outbound traffic interception enabled, the
proxy-everythingsidecar installs TPROXY rules in themangle PREROUTINGchain before excluding Docker bridge-to-bridge traffic.This allows Docker bridge internal traffic, including local runtime / sidecar / container control-plane traffic, to enter the transparent proxy path. In a real local app this showed up as container readiness checks being aborted or timing out, and outbound interception callbacks becoming unreliable.
This report is intentionally separate from #6790. That issue describes a broader Sandbox terminal readiness timeout. This issue is narrower and focuses only on the local Containers sidecar networking rule ordering.
Minimal reproduction
Repository: https://github.com/iGmainC/workerd-container-sidecar-tproxy-repro
The repro contains only:
ContainerDurable ObjectoutboundByHostvirtual hostRun:
In another terminal:
The
/egressendpoint starts the container and makes it call:That virtual host is handled by
EgressReproContainer.outboundByHost.Observed behavior
On affected local workerd builds, the sidecar
mangle PREROUTINGchain lacks a Docker bridge bypass before the TPROXY / DIVERT rules. The relevant rule order looks like:In a larger local app using the same Containers outbound interception feature, this led to logs like:
Expected behavior
The documented feature is that outbound requests from the container can be handled by Worker handlers using
outboundByHost/ outbound interception:https://developers.cloudflare.com/containers/platform-details/outbound-traffic/
The local sidecar should not break local Docker bridge control-plane traffic while implementing that interception. Docker bridge-to-bridge traffic should be excluded before the generic TPROXY / DIVERT rules.
Local mitigation verified
Inserting a Docker bridge CIDR bypass before the sidecar proxy rules fixes the local behavior:
With the rule installed first, the sidecar rule order becomes:
The exact bridge CIDR may differ by Docker configuration. The runtime already knows the Docker bridge subnet when creating the sidecar, so this can be derived rather than hard-coded.
With this mitigation applied after sidecar start / recovery, local container startup and outbound interception callbacks complete normally.
Why this looks like a bug rather than expected behavior
The Containers docs describe local outbound interception as a way to route container outbound HTTP/HTTPS through Worker handlers. They do not document any requirement for application code to manually repair sidecar iptables rules or to avoid Docker bridge internal traffic.
The Containers FAQ also says user containers do not support arbitrary iptables manipulation, which reinforces that this should be handled by the local runtime / sidecar implementation rather than by application code.
Environment