---
title: Transparent Proxy
(Sidecar & Host-level Interception)
shortTitle: Transparent Proxy
description: Run MockServer as a transparent proxy that intercepts outbound traffic with no application changes, on any Linux host (containers, VMs, bare metal) or as a Kubernetes sidecar, for mocking, recording, or chaos.
layout: page
pageOrder: 3
section: 'Chaos Testing'
subsection: true
sitemap:
priority: 0.7
changefreq: 'monthly'
lastmod: 2026-06-01T08:00:00+00:00
keywords: sidecar proxy, transparent proxy, kubernetes sidecar, iptables redirect, mockserver sidecar, conntrack, proxy protocol, NLB, HAProxy
---
MockServer can run as a transparent proxy that intercepts outbound HTTP(S) traffic with no application code or proxy-configuration changes. It works on any Linux host — containers, VMs, or bare metal — using iptables/eBPF interception; running it as a Kubernetes sidecar is the most common deployment, but not the only one (it also fronts traffic behind an AWS NLB / HAProxy or as an OS-level proxy on a host — see Deployment Contexts).
This page is about the interception mechanism — how traffic transparently reaches MockServer — independent of what MockServer then does with it (mock, record, or inject faults). If you instead want to inject faults into real upstream calls using explicit Kubernetes routing (swapping a Service, setting HTTP_PROXY, or a sidecar with a fixed remote host), see Chaos Proxy in Kubernetes.
How MockServer intercepts traffic transparently, the resolver strategies it uses to find the original destination, and how to deploy it automatically:
| Setup & interception | Resolution & deployment |
|---|---|
|
|
When transparentProxyEnabled is set to true, MockServer treats all incoming HTTP connections as proxy requests. Instead of requiring clients to send explicit HTTP CONNECT requests or configure proxy settings, it uses the Host header from each request to determine the forwarding target.
This works with Linux iptables REDIRECT rules that redirect outbound traffic to MockServer's port, making the interception completely transparent to the application.
transparentProxyTproxy=true.transparentProxyEbpf=true./proc/net/nf_conntrack), which records the pre-REDIRECT destination. This works even when the Host header is missing or incorrect.Host header from the HTTP request.| Property | Default | Description |
|---|---|---|
transparentProxyEnabled | false | Enable transparent proxy mode |
transparentProxyTproxy | false | Enable TPROXY (IP_TRANSPARENT) original-destination resolution. Requires the native epoll transport on Linux and CAP_NET_ADMIN. Used together with transparentProxyEnabled. |
transparentProxyEbpf | false | Enable eBPF socket-metadata original-destination resolution. Requires the native epoll transport on Linux and CAP_BPF. MockServer reads the pinned BPF map only — an external BPF program must populate it. Used together with transparentProxyEnabled. |
transparentProxyEbpfMapPath | /sys/fs/bpf/mockserver_orig_dst | Path to the pinned BPF map read by the eBPF resolver (a hash map keyed by socket cookie). Only used when transparentProxyEbpf is true. |
Environment variables: MOCKSERVER_TRANSPARENT_PROXY_ENABLED, MOCKSERVER_TRANSPARENT_PROXY_TPROXY, MOCKSERVER_TRANSPARENT_PROXY_EBPF, MOCKSERVER_TRANSPARENT_PROXY_EBPF_MAP_PATH
Add an init container to your Pod spec to redirect outbound traffic to MockServer:
initContainers:
- name: iptables-init
image: alpine:3.19
securityContext:
capabilities:
add: ["NET_ADMIN"]
command:
- sh
- -c
- |
# RETURN first -- exclude MockServer's own egress (UID 65534) to prevent redirect loop.
# The UID must match app.runAsUser (default 65534 in the Helm chart).
iptables -t nat -I OUTPUT -m owner --uid-owner 65534 -j RETURN
# Then REDIRECT HTTP and HTTPS to MockServer
iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 1080
iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 1080
The MockServer Helm chart includes sidecar configuration values:
sidecar:
enabled: false
transparentProxy: false
iptables:
enabled: false
excludeUid: 65534 # must match app.runAsUser to prevent redirect loop
When sidecar.transparentProxy is true, the chart sets MOCKSERVER_TRANSPARENT_PROXY_ENABLED=true in the deployment.
When sidecar.iptables.enabled is true, the chart renders an init container that adds a UID-based RETURN rule (to exclude MockServer's own egress) before any REDIRECT rules, preventing an infinite redirect loop. The excludeUid must match app.runAsUser (both default to 65534).
Instead of manually adding the sidecar container and iptables init container to every Deployment, you can enable the MockServer admission webhook. The webhook is a MutatingAdmissionWebhook that automatically injects the MockServer transparent-proxy sidecar and iptables init container into pods that opt in.
--set webhook.enabled=truekubectl label namespace my-namespace mockserver.org/sidecar-injection=enabledmockserver.org/inject: "true"MOCKSERVER_TRANSPARENT_PROXY_ENABLED=true)mockserver.org/injected: "true") to prevent double-injectionThe webhook Docker image (mockserver/mockserver-webhook) is published to Docker Hub and ECR Public by the release pipeline alongside the main MockServer image. Install with the webhook enabled:
# Install with the admission webhook enabled
helm install mockserver oci://ghcr.io/mock-server/charts/mockserver \
--set webhook.enabled=true
# Or with cert-manager for TLS (if cert-manager is installed)
helm install mockserver oci://ghcr.io/mock-server/charts/mockserver \
--set webhook.enabled=true \
--set webhook.certManager.enabled=true
To build the webhook image locally (for development):
# Build the webhook fat jar
cd mockserver && ./mvnw package -pl mockserver-k8s-webhook -DskipTests && cd ..
# Copy the jar into the Docker build context and build
cp mockserver/mockserver-k8s-webhook/target/mockserver-k8s-webhook-*-jar-with-dependencies.jar \
docker/webhook/mockserver-webhook.jar
docker build -t mockserver/mockserver-webhook:{{ site.mockserver_snapshot_version }} docker/webhook
Add the mockserver.org/inject: "true" annotation to your pod template:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
mockserver.org/inject: "true"
spec:
containers:
- name: my-app
image: my-app:latest
webhook:
enabled: false # enable the admission webhook
failurePolicy: Ignore # Ignore = pods created even if webhook is down
sidecar:
iptablesImage: "alpine:3.19"
serverPort: 1080
redirectPorts: "80,443"
runAsUser: 65534 # must match the UID exclusion for loop avoidance
logLevel: "INFO"
certManager:
enabled: false # use cert-manager instead of self-signed TLS
namespaceSelector: {} # default: mockserver.org/sidecar-injection=enabled
The webhook uses failurePolicy: Ignore by default so pods are created normally if the webhook is unavailable. TLS is bootstrapped automatically via a self-signed CA (Helm post-install hook that generates a CA, creates a TLS Secret, and patches the caBundle into the MutatingWebhookConfiguration) or via cert-manager if webhook.certManager.enabled=true.
What "the original destination" is, and why it must be recovered: it is the host and port the client was actually trying to reach (for example api.stripe.com:443). Because transparent interception redirects the connection to MockServer's own address, the original destination is overwritten — so by the time the request arrives, MockServer no longer knows where the client meant to go. It must recover the original destination to do two things: match an expectation by host, and forward the request on to the real upstream.
MockServer uses a pluggable, ordered chain of strategies to resolve the original destination of transparently intercepted connections. The first strategy that returns a result wins; if none do, MockServer falls back to the Host header. The strategies below are listed in the real priority order MockServer applies them: TPROXY, then eBPF, then SO_ORIGINAL_DST, then conntrack, then DNS-intent, then the Host header. A PROXY protocol header, when present, is detected and consumed earlier in the pipeline — before this resolver chain runs.
When MockServer is deployed behind a load balancer that prepends PROXY protocol headers (e.g., AWS Network Load Balancer with proxy_protocol_v2.enabled, HAProxy with send-proxy / send-proxy-v2, nginx with proxy_protocol on), MockServer automatically detects and parses the header to extract the original destination address. Both the v1 (text) and v2 (binary) formats are recognised on the same listener -- MockServer dispatches on the first byte.
The PROXY protocol v1 header is a single ASCII line prepended to the TCP connection:
PROXY TCP4 192.168.1.1 93.184.216.34 56324 80\r\n
PROXY TCP6 2001:db8::1 2001:db8::2 56324 443\r\n
PROXY UNKNOWN\r\n
The PROXY protocol v2 header is a 12-byte binary signature followed by the version/command byte, the address-family/transport byte, a 2-byte address-block length, and the address block. MockServer extracts the destination for the PROXY command on the INET (IPv4) and INET6 families; LOCAL (health-check) headers and UNIX-socket families are consumed and resolution falls through to the next strategy.
Key points:
transparentProxyEnabled is truenetty-codec-haproxy needed)The highest-priority strategy. With the native (epoll) transport on Linux, the TPROXY iptables target (enabled with transparentProxyTproxy=true) preserves the original destination as the socket's local address, so MockServer reads it directly with no table lookup. Requires the native transport and the CAP_NET_ADMIN capability.
An eBPF socket-metadata strategy (enable with transparentProxyEbpf=true): an external BPF program records the original destination in a pinned BPF map keyed by socket cookie, which MockServer reads (Linux, native transport, CAP_BPF; MockServer reads the map only — it does not load the BPF program). Automatic init-container injection is available via the Kubernetes admission webhook.
With the native (epoll) transport on Linux, MockServer reads the pre-REDIRECT destination via the SO_ORIGINAL_DST socket option — an O(1) alternative to the conntrack table scan. Requires the native transport and the CAP_NET_ADMIN capability.
On Linux with the nf_conntrack kernel module loaded, MockServer reads the original destination of intercepted connections from /proc/net/nf_conntrack. This provides accurate target resolution even when the Host header is absent or incorrect.
Requirements:
/proc/net/nf_conntrack must be readable-j REDIRECTWhen MockServer's own DNS server is enabled and answers a query (an A/AAAA record mapping a hostname to an IP), it records that answered IP → hostname mapping. If a client then connects to that IP (DNS-steering: the name was pointed at MockServer), this strategy recovers the intended hostname so expectation matching and forwarding work by name even though the client connected by IP.
It runs after conntrack, so a real iptables-REDIRECT original destination always wins; DNS-intent only fills the gap when conntrack returns nothing. The recovered hostname is resolved by the downstream forwarding logic, and MockServer's existing loop-prevention header guards against a DNS-to-self loop.
If no other strategy resolves the destination, MockServer reads the Host header from the HTTP request. This always works but requires a valid Host header.
The resolver chain supports multiple deployment patterns. For a full catalogue of every mechanism that can deliver traffic to MockServer for transparent interception — including OS firewall rules, DNS steering, cloud route tables, browser proxy, and CI networks — see Transparent Interception Recipes.
| Context | Resolution Strategy | Notes |
|---|---|---|
| Kubernetes sidecar with iptables REDIRECT | Conntrack, then Host header | Standard sidecar pattern |
| Behind AWS NLB / HAProxy (PROXY protocol) | PROXY protocol v1 / v2 | Automatic detection, no config needed |
| OS-level transparent proxy | Conntrack, then Host header | iptables on host |
| Cloud route-based interception | Host header fallback | When original-dst is not available |
/proc/net/nf_conntrack file is parsed per connection, capped at 200,000 lines. If the conntrack table exceeds this limit, MockServer falls back to Host-header resolution. For high-throughput production use, consider a dedicated transparent proxy.CAP_NET_ADMIN. The eBPF socket-metadata strategy is also available (it reads a pinned BPF map populated by an external BPF program; requires CAP_BPF).