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

  1. An init container sets up iptables rules to redirect outbound HTTP/HTTPS traffic to MockServer's port
  2. MockServer resolves the original destination using a multi-strategy chain (first match wins), in this priority order:
    1. 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.
    2. 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.
    3. 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.
    4. 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.
    5. 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.
    6. Host header fallback: if no other strategy resolves the destination, MockServer reads the Host header from the HTTP request.
    (A PROXY protocol v1 / v2 header, when sent by a fronting load balancer such as AWS NLB, HAProxy, or nginx, is detected and consumed earlier in the pipeline — before this chain runs.)
  3. If an expectation matches, MockServer returns the mock response
  4. Otherwise, MockServer forwards the request to the original target

Configuration

PropertyDefaultDescription
transparentProxyEnabledfalseEnable transparent proxy mode
transparentProxyTproxyfalseEnable 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

  1. Enable the webhook in the Helm chart: --set webhook.enabled=true
  2. Label the target namespace: kubectl label namespace my-namespace mockserver.org/sidecar-injection=enabled
  3. Annotate pods that should receive the sidecar: mockserver.org/inject: "true"
  4. 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 transparentProxyEnabled is true
  • No new dependencies -- both the v1 text format and the v2 binary format are hand-parsed (no netty-codec-haproxy needed)
  • 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_conntrack must 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.

ContextResolution StrategyNotes
Kubernetes sidecar with iptables REDIRECTConntrack, then Host headerStandard sidecar pattern
Behind AWS NLB / HAProxy (PROXY protocol)PROXY protocol v1 / v2Automatic detection, no config needed
OS-level transparent proxyConntrack, then Host headeriptables on host
Cloud route-based interceptionHost header fallbackWhen original-dst is not available

Limitations

  • Conntrack lookup is O(n) with a cap -- the /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.
  • 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; requires CAP_BPF).
 

Related Pages