Securing ngrok tunnels with mutual TLS: a practical setup guide
Learn how to enforce client‑certificate authentication on ngrok HTTP and TCP tunnels using the built‑in mTLS feature, with a step‑by‑step example and notes on latency and certificate renewal.
13 Feb 2026, 14:34 UTC

Problem: Exposing a local service without client authentication
When you expose a development API or internal database through ngrok, anyone who knows the public URL can reach your service. Adding authentication inside the application often requires code changes or redeployment, which isn’t always feasible for quick testing or legacy systems.
Thesis: ngrok’s built‑in mutual TLS (mTLS) lets you enforce client‑certificate validation at the tunnel edge, protecting the service without touching the application.
By uploading a trusted Certificate Authority (CA) to the ngrok Dashboard and enabling verify: true in the agent configuration, ngrok will perform a TLS handshake that requires a valid client certificate signed by that CA. If the handshake fails, the connection is dropped before it reaches your local process.
Configuration steps
- Prepare a CA and client certificate (you can use OpenSSL or mkcert). For example:
# Generate a CA key and self‑signed cert openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.pem -subj "/CN=example-ngrok-ca" # Generate a client key and cert signed by the CA openssl genrsa -out client.key 2048 openssl req -new -key client.key -out client.csr -subj "/CN=example-client" openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem -days 365 -sha256
Run these commands in a terminal with sufficient file‑system permissions to write the PEM files. - Upload the CA to ngrok
- Log in to the ngrok Dashboard.
- Navigate to Security → TLS Certificates.
- Click Add Certificate, paste the contents of
ca.pem, and save.
The free tier allows one uploaded CA; paid plans support multiple CAs and rotation.
- Edit
ngrok.ymlAdd a
tlssection under the tunnel definition or at the top level to apply mTLS globally:tls: verify: true client_cas: - /path/to/ca.pem # Example tunnel tunnels: web: proto: http addr: 8080Replace
/path/to/ca.pemwith the absolute path to the CA file you saved earlier. The agent must have read permission on this file. - Start the agent
Run the ngrok CLI from the directory containing
ngrok.yml(or specify the config with-config):ngrok start web
The agent will print a forwarding URL such as
https://abcd1234.ngrok.io.
Worked example: verifying the mTLS enforcement
After the tunnel is up, you can test the behavior with curl.
1. Request without a client certificate (should be rejected)
curl -v https://abcd1234.ngrok.io
You should see a TLS handshake failure, for instance:
* SSL certificate problem: self signed certificate * Closing connection 0 curl: (60) SSL certificate problem: self signed certificate
The exact wording depends on your curl version, but the connection will not reach your local service.
2. Request with the client certificate (should succeed)
curl -v --cert /path/to/client.pem --key /path/to/client.key https://abcd1234.ngrok.io
If the client cert is valid and signed by the uploaded CA, the handshake completes and you receive the response from your local application.
These checks confirm that ngrok is enforcing mTLS at the tunnel edge.
Trade‑offs and limitations
- Latency overhead: Enabling mTLS adds an extra round‑trip for the certificate exchange. For latency‑sensitive services (e.g., high‑frequency trading APIs), benchmark the handshake time with and without mTLS to ensure it stays within your budget.
- Certificate renewal: The ngrok agent does not automatically reload updated CA or client certificates. If a certificate expires or is revoked, existing tunnels continue to work until the agent restarts, which could temporarily allow unauthorized access. Plan a restart or use a process manager to reload ngrok after certificate updates.
- Free‑tier CA limit: The free account permits only one uploaded CA. If you need to trust multiple independent CAs (e.g., for different client groups), you must upgrade to a paid plan.
Actionable closing
Mutual TLS in ngrok offers a straightforward way to add client‑certificate authentication to any TCP or HTTP tunnel without modifying the underlying service. By generating a CA, uploading it to the Dashboard, enabling verify: true in ngrok.yml, and testing with curl, you can confirm that only authorized clients reach your local application. Keep in mind the extra TLS handshake latency and the need to restart the agent when certificates change, and incorporate those considerations into your deployment workflow.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.