Jul 17, 2026
Jul 17, 2026
Software teams need to work quickly, securely, and collaboratively. They need to focus on building solutions that make their products unique and worry about as few infrastructure details as possible. That includes providing ingress to the services they’re building. Whether they’re developing on their laptop at home, behind a corporate firewall, or deploying to the cloud, they need to provide secure access to their services.
In this guide, we’ll cover how ngrok and Cloudflare Tunnels share the same core feature set, but with ngrok you get more flexibility in how you run it and far more control over your traffic once it’s flowing. You can run ngrok as an interactive CLI, as a background service, as an SDK embedded directly in your Go, Rust, Python, or JavaScript app, in Docker, or as the ngrok Kubernetes Operator. And with Traffic Policy, you can authenticate, filter, rate limit, and transform requests at the edge with a few lines of YAML — capabilities that on Cloudflare typically mean stitching together Tunnels, Access, and Workers. ngrok is also leveraged by our customers to access external networks they don’t control — such as a customer’s network.
If you’re a current user of Cloudflare Tunnels and looking to make the move to ngrok, this guide will help you make the transition.
One of the first things you probably need to think about is how your current configuration will relate to the new system.
A common config.yml for Cloudflare Tunnels may look something like this, where you have a tunnel identified by an ID, a credentials-file pointing to the tunnel’s JSON credentials, and a set of ingress rules mapping hostnames to local services:
1tunnel: <Tunnel-UUID>2credentials-file: /root/.cloudflared/<Tunnel-UUID>.json3ingress:4 - hostname: app.example.com5 service: http://localhost:80006 - service: http_status:404Remember when you created that tunnel in Cloudflare, you needed to run a create command in their CLI, find the UUID of the created tunnel, write the config.yml that mapped that UUID to your ingress rules, then run another command to assign a CNAME record that directed traffic to the tunnel subdomain.
With ngrok, there are no tunnel UUIDs, credential files, or DNS records to manage for ngrok-managed domains. You define endpoints — URLs that route traffic to your services — and ngrok handles the rest.
With ngrok, you can create and configure endpoints in various ways, whether it’s entirely through the ngrok agent CLI, or using a combination of the CLI and the ngrok agent configuration file. You can also embed ngrok in your application code with one of our SDKs — ngrok-go, ngrok-rust, ngrok-python, or ngrok-javascript — so your app gets its own ingress with no separate agent process at all. Or, you can provide ingress to your clusters with the ngrok Kubernetes Operator, which supports the Kubernetes Gateway API, Ingress resources, and ngrok’s own CRDs.
For this post, we’ll focus on using the ngrok CLI and the agent config file, which are most similar to the Cloudflare Tunnels setup. What you’ll need to know to create endpoints in ngrok is the port your service is running on and the domain you want to use.
After signing up for an ngrok account and installing the ngrok agent, you need to connect the agent to your account. You do this by taking the ngrok authtoken shown in your ngrok dashboard and pasting it into the following command in your terminal.
ngrok config add-authtoken <TOKEN>This command writes the authtoken to your ngrok agent configuration file to be used with all your interactions with the ngrok platform. At this point, you are ready to use ngrok. Assuming you have an application listening on port 80 on your machine, you could run the following and create a secure connection from the internet to that port.
ngrok http 80The resulting message from ngrok would look like this:

Now, all traffic sent to https://67e072b9e16f.ngrok.app is passing through the ngrok infrastructure, which takes care of all the necessary DNS entries, TLS certificates, load balancing, DDoS protection, and everything else needed to create the connection and securely route traffic to port 80 on my machine.
Want a URL that doesn’t change between sessions? Every ngrok account — including free accounts — gets a static domain, and you can bring your own custom domain, too:
ngrok http 80 --url https://app.example.comUsing the agent configuration file, you can run multiple endpoints simultaneously and tap into more advanced settings. Defining endpoint configurations is helpful because you may then start pre-configured endpoints by name from your command line without remembering all of the right arguments every time. You may also use this method to start as many endpoints as you like from a single ngrok agent.
To find your config file, run the following command:
ngrok config checkOpen the file at the path returned using your favorite text editor.
Endpoints are defined as a list under the endpoints property in your configuration file.
For example, if you wanted to create two endpoints named httpbin and demo, the configuration would look like this:
1version: 32 3endpoints:4 - name: httpbin5 url: https://alan-httpbin.ngrok.dev6 upstream:7 url: 80008 - name: demo9 url: https://demo.inconshreveable.com10 upstream:11 url: 9090Each endpoint’s url is where it’s reachable on the internet — an ngrok subdomain like alan-httpbin.ngrok.dev, or your own custom domain like demo.inconshreveable.com. The upstream block tells ngrok where to route that traffic locally.
This maps almost one-to-one from Cloudflare’s ingress rules: each hostname/service pair becomes an endpoint with a url and an upstream.
Once you have your endpoints defined, start one by name:
ngrok start httpbinOr start everything at once:
ngrok start --allIf you want the agent to survive reboots and run without a terminal session — like cloudflared service install — ngrok does that too:
1ngrok service install --config /path/to/ngrok.yml2ngrok service startHere’s where the migration gets you more than parity. On Cloudflare, protecting a tunnel usually means configuring Access policies in a separate product, and transforming requests means writing and deploying Workers. With ngrok, Traffic Policy lives right in your endpoint definition.
Want to put Google OAuth in front of an internal tool and only allow your team’s domain? That’s a few lines of YAML on the endpoint:
1version: 32 3endpoints:4 - name: httpbin5 url: https://alan-httpbin.ngrok.dev6 upstream:7 url: 80008 traffic_policy:9 on_http_request:10 - actions:11 - type: oauth12 config:13 provider: google14 - expressions:15 - "!actions.ngrok.oauth.identity.email.endsWith('@example.com')"16 actions:17 - type: custom-response18 config:19 status_code: 40320 body: Access denied.Traffic Policy includes actions for IP restrictions, rate limiting, JWT validation, header manipulation, URL rewrites, redirects, and more — all composable with CEL expressions, no extra products or deploy steps required.
As I mentioned, this is only one way to create ingress to your applications. If you’re interested in learning more about how you could utilize ngrok in production, we’ve got you covered:
Questions or comments? Hit us up on X (aka Twitter) @ngrokhq or LinkedIn, or join our community on Slack.