Transparent Proxy / Sidecar Mode
MockServer can run as a Kubernetes sidecar with transparent HTTP proxy interception. This enables service mesh integration patterns where MockServer intercepts traffic destined for external services without any application code changes.
Transparent Proxy Mode
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.
How it works
- An init container sets up iptables rules to redirect outbound HTTP/HTTPS traffic to MockServer's port
- MockServer resolves the original destination using a multi-strategy chain (first match wins), in this priority order:
- TPROXY (IP_TRANSPARENT): with the native epoll transport, the TPROXY iptables target preserves the original destination as the socket's local address. Enabled with
transparentProxyTproxy=true. - eBPF socket metadata: reads the pre-NAT destination from a pinned BPF map keyed by socket cookie (populated by an external BPF program). Enabled with
transparentProxyEbpf=true. - SO_ORIGINAL_DST: with the native epoll transport, reads the pre-REDIRECT destination via a socket option — an O(1) alternative to the conntrack table scan.
- Linux conntrack: reads the original destination from the kernel conntrack table (
/proc/net/nf_conntrack), which records the pre-REDIRECT destination. This works even when the Host header is missing or incorrect. - DNS-intent: if the client resolved a hostname via MockServer's own DNS server and then connected to the returned IP, MockServer recovers the intended hostname from the DNS answer it handed out — so matching and forwarding work by name. Active only when the DNS server is enabled.
- Host header fallback: if no other strategy resolves the destination, MockServer reads the
Hostheader from the HTTP request.
- TPROXY (IP_TRANSPARENT): with the native epoll transport, the TPROXY iptables target preserves the original destination as the socket's local address. Enabled with
- If an expectation matches, MockServer returns the mock response
- Otherwise, MockServer forwards the request to the original target
Configuration
| 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. |
Environment variables: MOCKSERVER_TRANSPARENT_PROXY_ENABLED, MOCKSERVER_TRANSPARENT_PROXY_TPROXY
iptables init container example
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
Helm Chart
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).
Automatic Sidecar Injection (Admission Webhook)
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.
How it works
- Enable the webhook in the Helm chart:
--set webhook.enabled=true - Label the target namespace:
kubectl label namespace my-namespace mockserver.org/sidecar-injection=enabled - Annotate pods that should receive the sidecar:
mockserver.org/inject: "true" - When a pod is created in a labelled namespace with the opt-in annotation, the webhook injects:
- An iptables init container (with UID-exclusion loop avoidance)
- A MockServer sidecar container (with
MOCKSERVER_TRANSPARENT_PROXY_ENABLED=true) - An idempotency marker annotation (
mockserver.org/injected: "true") to prevent double-injection
Enabling the webhook
The 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 mockserver/mockserver \
--set webhook.enabled=true
# Or with cert-manager for TLS (if cert-manager is installed)
helm install mockserver mockserver/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:6.1.1-SNAPSHOT docker/webhook
Annotating pods
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 values
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.
Original Destination Resolution
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.
PROXY Protocol (v1 and v2) — resolved before the chain
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:
- No configuration needed -- detection is automatic when
transparentProxyEnabledistrue - No new dependencies -- both the v1 text format and the v2 binary format are hand-parsed (no
netty-codec-haproxyneeded) - Fail-safe -- if the first bytes are not a PROXY header, they pass through unchanged
Strategy 1: TPROXY (IP_TRANSPARENT)
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.
Strategy 2: eBPF socket metadata
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.
Strategy 3: SO_ORIGINAL_DST getsockopt
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.
Strategy 4: Linux Conntrack
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:
- Linux only -- on other OSes, MockServer gracefully falls back to the next strategy
- nf_conntrack module -- must be loaded and
/proc/net/nf_conntrackmust be readable - iptables REDIRECT -- the rule must use
-j REDIRECT - NET_ADMIN capability -- required for the iptables init container
Strategy 5: DNS-Intent
When 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.
Strategy 6: Host Header Fallback
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.
Deployment Contexts
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 |
Limitations
- Conntrack lookup is O(n) with a cap -- the
/proc/net/nf_conntrackfile 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. - Linux only for conntrack -- original-destination resolution via conntrack requires Linux. On other OSes, the transparent proxy falls back to Host-header resolution.
- iptables not automatic without the webhook -- without the admission webhook, an init container or external mechanism must configure traffic redirection manually. With the webhook enabled, iptables rules are injected automatically.
- SO_ORIGINAL_DST and TPROXY need the native transport -- these kernel-level strategies require the native (epoll) transport on Linux and
CAP_NET_ADMIN. The eBPF socket-metadata strategy is also available (it reads a pinned BPF map populated by an external BPF program; requiresCAP_BPF).
Related Pages
- Transparent Interception Recipes — ready-to-use iptables REDIRECT / TPROXY recipes for routing real traffic through MockServer
- Chaos Testing & Fault Injection — inject latency and errors into the traffic this in-path proxy intercepts
- Isolating Single Service — use MockServer as a reverse proxy to isolate one service for testing or debugging