Enforcing Mutual TLS on Ngrok Tunnels: Configuration and Limits
Learn how to require client certificates for Ngrok TLS tunnels, see a full command example, and understand the feature's limits and typical pitfalls.
06 Mar 2026, 21:24 UTC

Useful answer
Ngrok can enforce mutual TLS (mTLS) on its tunnels, requiring every connecting client to present a valid client certificate signed by a trusted certificate authority. This encrypts and authenticates both ends of the connection before traffic is forwarded to your local service.
How Ngrok Mutual TLS Works
When you start an ngrok TLS tunnel with the --client-ca flag, ngrok terminates the incoming TLS connection, verifies the client certificate against the supplied CA, and only then forwards the decrypted traffic to the local endpoint. If the client certificate is missing, expired, or not signed by the trusted CA, ngrok aborts the handshake and the connection fails.
Configuration Example
The following command exposes a local TLS service listening on port 443, enforces mTLS, and uses a custom hostname:
ngrok tls \
--hostname=example.com \
--cert=./server.crt \
--key=./server.key \
--client-ca=./ca.crt \
443
Where:
--certand--keyare the server certificate and private key that ngrok presents to clients.--client-cais the PEM‑encoded certificate authority (or bundle) used to validate client certificates.- The final argument (
443) is the local port where your TLS‑terminated service runs.
Run this command in a terminal where you have read access to the certificate files and the ngrok binary is in your PATH. No special OS privileges are required beyond those needed to bind to the local port.
Limits
- Mutual TLS is available only on paid ngrok plans (Pro or Enterprise). Free tiers reject the
--client-caflag. - The feature applies to TLS‑terminated tunnels (e.g.,
ngrok tlsorngrok httpwith TLS termination). It cannot be used on raw TCP tunnels (ngrok tcp) because ngrok does not terminate TLS there. - Verifying the client certificate adds a small amount of latency to each handshake, typically a few milliseconds.
Common Mistakes
- Omitting the client CA file – without
--client-cangrok treats the tunnel as server‑only TLS; any client presenting a certificate will cause a handshake failure. - Using a self‑signed server certificate without adding it to ngrok’s trust store – ngrok will reject the server cert during its own TLS setup, leading to
tls: bad certificateerrors. - Attempting mTLS on an HTTP tunnel – ngrok terminates TLS before forwarding to the HTTP process; the
--client-caflag is ignored and client certificates are not validated. - Missing intermediate certificates in the client chain – if the client certificate relies on intermediates not present in the
--client-cabundle, ngrok cannot build a trusted chain and will abort the connection.
Verification Steps
- Start ngrok with the command shown above.
- From a client machine, run a test request, substituting your actual file paths and the ngrok‑assigned subdomain:
- Open the ngrok inspector at
http://127.0.0.1:4040, select the tunnel, and verify that the “Client Certificate” field shows the subject of the certificate you sent.
curl --verbose \
--cert ./client.crt \
--key ./client.key \
--cacert ./ca.crt \
https://<subdomain>.ngrok.io
Look for a successful TLS handshake (* SSL connection using TLSv1.3) and an HTTP 200 (or whatever your service returns).
Practical Risks
Misconfiguring mTLS can block legitimate clients, effectively denying service. Always test with a known‑good client certificate before exposing the tunnel to production traffic. Remember that mTLS protects only the transport layer; you still need application‑level authentication (e.g., tokens, signatures) for sensitive data.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.