Choosing the Right ngrok Endpoint for Public HTTPS Access
When you need a stable, secure HTTPS URL for webhooks or mobile callbacks, ngrok offers several binding options. This guide compares temporary HTTP, reserved domains, custom domains, and TCP endpoints, then walks you through setting up a reserved domain with a traffic policy and how to validate it.
21 Sept 2025, 21:02 UTC

Decision and Constraints
When a third‑party service (e.g., Stripe, Twilio, or a mobile app) must reach a local development machine, you need a public HTTPS URL that forwards to a local port. The key constraints that shape the choice are:
- URL stability – the address should not change between agent restarts.
- TLS termination – ngrok’s edge handles TLS; the local service receives plain HTTP unless you add another layer.
- Inbound access control – restrict which IPs or subnets can reach the tunnel.
- Branding / DNS control – use a custom hostname if you need a recognizable domain.
These constraints narrow the field to four ngrok binding types: ephemeral HTTP, reserved domain, custom domain, and TCP endpoint.
Comparing Supported Endpoint Types
| Endpoint | URL Stability | TLS Termination | Cost | Inbound Control | DNS/Branding | Typical Use |
|---|---|---|---|---|---|---|
| Ephemeral HTTP | Random, changes on each restart | Edge TLS, no local cert required | Free | None – all traffic allowed | No DNS control; uses ngrok.io subdomain | Quick demos, internal testing |
| Reserved Domain (HTTP) | Persistent, stays the same | Edge TLS, local traffic plain HTTP | Paid (starts at $5/month) | Traffic Policies (IP allow/deny, header injection) | ngrok.io subdomain; no external DNS needed | Webhooks, callbacks that require a stable URL |
| Custom Domain (HTTP) | Persistent, using your own domain | Edge TLS; you provide cert or use ACME | Paid (similar to reserved domain) | Traffic Policies, plus DNS-level restrictions | Full DNS control; brandable hostname | Production‑grade services needing a branded URL |
| TCP Endpoint | Persistent if reserved; random if free | No TLS unless your local service handles it | Free for random; paid for reserved | Traffic Policies (IP allow/deny) | No DNS; uses ngrok.io port mapping | Raw protocols (SSH, RDP, database connections) |
Trade‑offs in Detail
Ephemeral HTTP
Zero configuration and free. The URL changes on every agent start, so it’s unsuitable for services that must be reachable by external clients over time. Use only for one‑off demos or internal testing.
Reserved Domain
Provides a stable ngrok.io subdomain and lets you attach Traffic Policies to filter traffic or add headers. It’s the cheapest way to get a persistent HTTPS endpoint, but you cannot brand the hostname beyond the ngrok.io prefix.
Custom Domain
Requires DNS ownership and certificate management. ngrok can automatically issue and renew certificates via ACME, but you must set up a CNAME or A record pointing to ngrok’s edge. This option is ideal when you need a fully branded domain and control over TLS certificates.
TCP Endpoint
Exposes a raw TCP stream. It does not terminate TLS, so your local service must handle encryption if needed. It’s useful for protocols that don’t fit HTTP, but you lose the convenience of ngrok’s HTTP inspection tools.
Concrete Implementation: Reserved Domain with Traffic Policy
Below is a step‑by‑step example that creates a stable HTTPS endpoint for a local web server on port 8080, restricts access to a single IP range, and injects a shared‑secret header required by a webhook provider.
Prerequisites
- ngrok account with a Reserved Domain entitlement (e.g.,
mywebhook.ngrok.io). - ngrok agent installed and authenticated (run
ngrok authtoken <token>). - Local service listening on
localhost:8080that responds to/healthz. - Provider IP range:
203.0.113.0/24.
1. Define the Traffic Policy
Create a JSON file policy.json that allows only the provider IP range and adds a header:
{
"name": "webhook-policy",
"rules": [
{
"action": "allow",
"ip": "203.0.113.0/24"
},
{
"action": "deny",
"ip": "0.0.0.0/0"
}
],
"headers": {
"X-Webhook-Secret": "s3cr3t"
}
}
Upload the policy via the ngrok API:
curl -X POST https://api.ngrok.com/traffic_policies \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d @policy.json
The response will include a policy_id you’ll use when starting the tunnel.
2. Start the ngrok Tunnel
Run the agent with the reserved domain and attach the policy:
ngrok http 8080 \
--domain=mywebhook.ngrok.io \
--traffic-policy=webhook-policy
Check the agent’s inspector at http://localhost:4040 to confirm the mywebhook.ngrok.io URL appears and that the policy is listed.
3. Validate the Endpoint
From a machine inside the allowed IP range:
curl -sS https://mywebhook.ngrok.io/healthz
Should return the service’s health response. From a blocked IP, ngrok will reject the connection at the edge; you’ll see a 403 Forbidden in the inspector.
4. Optional – Verify TLS Forwarding
ngrok terminates TLS on its edge. The local service receives plain HTTP. If you need end‑to‑end encryption, run a local TLS listener or configure mutual TLS in the Traffic Policy. For most webhook use‑cases, edge TLS is sufficient.
Limitations & Practical Checks
- Entitlement changes: free tiers no longer provide reserved domains; always check the current pricing page before provisioning.
- Secret leakage: never commit
policy.jsonor API tokens to source control. Store them in environment variables or a secrets manager. - Firewall bypass: exposing a local service can circumvent corporate egress rules. Coordinate with security teams before enabling TCP endpoints for databases or internal services.
- DNS conflicts: a reserved domain name is globally unique. If another account already owns
mywebhook.ngrok.io, you cannot claim it. - Inspection: use the inspector (
http://localhost:4040) to see real‑time request/response data and confirm policy enforcement.
Wrap‑Up
For most webhook or callback scenarios that require a stable HTTPS URL and simple inbound filtering, a reserved domain with a Traffic Policy offers the optimal balance of cost, stability, and control. Custom domains give you full branding but add DNS and certificate overhead. TCP endpoints are best for raw protocols, not HTTP. Ephemeral HTTP is handy for quick demos but unsuitable for production callbacks.
Follow the example above to spin up a secure, controlled tunnel and verify it with the inspector and external curl requests. Adjust the policy rules and header injection as your provider’s requirements evolve.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.