Capturing HTTPS on a Server: GoReplay vs mitmproxy vs Speedscale
HTTPS on the wire is ciphertext. Anything that claims to “capture HTTPS on a server” is doing one of three jobs:
- Terminate TLS in front of the app and record the clear HTTP that remains (load balancer / sidecar / local
:httpport). - Become a man-in-the-middle with a custom CA, so clients (or a sidecar) trust the intercepting proxy.
- Instrument the process (eBPF, library hook, service mesh sidecar) and export requests from inside the TLS boundary.
Those are not interchangeable. Mixing them up is why teams install mitmproxy in production, then wonder why latency and certificate errors showed up.
This is a head-to-head of three tools people actually search for when the job is server-side HTTPS: GoReplay, mitmproxy, and Speedscale.
The short version
| GoReplay | mitmproxy | Speedscale | |
|---|---|---|---|
| How it sees HTTPS | Usually after TLS termination (--input-raw on the clear port). Not a TLS-terminating proxy. | MITM proxy. Clients must trust its CA. Decrypts TLS in the proxy. | Agent / collector in the cluster. Captures at the service, then sanitizes and replays. |
| On the user path? | No. Sniffs a port the service already binds. | Yes, unless you only attach it to a debug sidecar. | Agent sits next to the workload; not a public reverse proxy, but it is in-cluster software. |
| Primary job | Record production HTTP and replay it (shadow, load, file). | Interactive inspect / modify of HTTPS for a client or a lab. | Kubernetes-native traffic replay, mocks, and CI evidence. |
| Right default | Production capture behind the LB. | Local or staging intercept. | Teams already on Kubernetes who want a commercial capture-and-replay platform. |
If you terminate TLS at nginx / Envoy / an AWS ALB and the app speaks HTTP on 127.0.0.1:8080, GoReplay on that port is the usual production layout. If you need to see inside a TLS connection from a laptop to api.example.com, mitmproxy is the usual lab layout. If you want a managed Kubernetes capture pipeline with sanitization and generated tests, Speedscale is the commercial layout.
GoReplay: capture behind TLS, then replay
GoReplay listens on a network interface or port (--input-raw :8080) and copies HTTP. It does not terminate TLS for you and it is not a MITM. That is a feature in production: user traffic never has to be pointed at Gor.
Typical HTTPS topology:
clients --TLS--> load balancer --HTTP--> app :8080
^
`-- gor --input-raw :8080
sudo gor --input-raw :8080 --output-file=requests.gor
sudo gor --input-raw :8080 --output-http http://staging.internal
When people say “capture HTTPS with GoReplay,” they mean this: TLS already ended, HTTP is on the loopback or the private NIC, Gor sniffs that. If you terminate TLS in the same process as the app (Go ListenAndServeTLS, Node https.createServer), Gor on that port sees ciphertext and you get nothing useful. Move termination to the LB, or capture on a dual-bind clear port used only on the private network.
Replay is the point. Shadow a candidate: --output-http=http://staging. Load from a file: --input-file "requests.gor|200%". Middleware can drop Authorization and rewrite hosts. PRO adds S3, WebSockets, and TCP session grouping — see GoReplay PRO and shadow testing.
Use GoReplay when: you already terminate TLS in front of the service, you want production HTTP as a replay artifact, and you do not want a proxy on the request path.
Do not use it when: you need to intercept a client that talks HTTPS end-to-end to a third party, or you need an interactive breakpoint UI for one request.
mitmproxy: decrypt by becoming the TLS peer
mitmproxy is a TLS-aware intercepting proxy. It presents its own certificate (from a CA you install on the client), decrypts, lets you inspect or rewrite, then re-encrypts to the upstream. That is the correct tool for:
- Debugging a mobile app or a misbehaving HTTP client
- Security research and local API exploration
- Forcing a lab client through a known CA so you can read HTTPS
It is the wrong default for capturing production user traffic on a server. To MITM production you must either install that CA on every client (impossible for public users) or terminate TLS yourself and then also run a proxy hop. You have now put extra latency and a new failure domain on the critical path.
mitmproxy can dump flows and replay them in a limited way (mitmdump, client replay). That replay is “the requests this proxy saw,” which is excellent for a test client and poor as a sample of real production mix. It is not a shadow-testing system.
Use mitmproxy when: you control the client, you can install a CA, and the job is inspect-and-modify — not “copy yesterday’s production onto staging.”
Do not use it when: the clients are real users on the public internet, or you need lossless, always-on capture without being in the path.
Speedscale: Kubernetes capture as a product
Speedscale instruments workloads (typically Kubernetes) to record traffic, redact sensitive fields, and replay it as tests or load. HTTPS is handled inside the cluster: sidecars / agents see plaintext after the mesh or after the container’s own TLS, depending on how you install it.
Compared with GoReplay:
- Speedscale is a platform (UI, sanitization policies, generated tests, CI gates). GoReplay is a binary you run with flags.
- Speedscale assumes Kubernetes (and a commercial contract). GoReplay OSS runs on a single VM with
libpcap. - Speedscale’s answer to “HTTPS on the server” is “install the agent where the service already decrypted, or where the mesh did.” Same topology idea as Gor, packaged.
Compared with mitmproxy: Speedscale is not an interactive MITM for a developer laptop. It is not a replacement for reading one bad TLS handshake.
Use Speedscale when: you are on Kubernetes, you want vendor-backed sanitization and test generation, and you will pay for that workflow.
Do not use it when: you need a 10MB static binary on a fleet of VMs, or the job is local HTTPS debugging.
Decision rule
Ask two questions.
Who terminates TLS? If a load balancer already does, capture the clear port. GoReplay (or Speedscale’s agent) fits. If nobody terminates TLS except the app process, you must change that topology or you will be looking at ciphertext.
Do you need to be in the path? If yes, because you must modify or break TLS on a client you control → mitmproxy. If no, because production users should not know you are recording → GoReplay or Speedscale.
For a public site with nginx/ALB in front, the honest setup is: terminate TLS there, run GoReplay on the backend port, replay onto staging before you ship. Product pages: load testing with production traffic, monitoring / shipping HTTP to ES and Kafka. Docs: https://docs.goreplay.org/untitled.