# Cloudflare Tunnel vs ngrok vs Tailscale Funnel: Which to Use

> Cloudflare Tunnel, ngrok, and Tailscale Funnel compared on accounts, public reach, access control, expiry, and limits, with a source for every value.

Source: https://layerv.ai/compare/cloudflare-tunnel-vs-ngrok-vs-tailscale-funnel/

---

[← All Comparisons](https://layerv.ai/compare/) 

# Cloudflare Tunnel vs ngrok vs Tailscale Funnel

Which one fits which job, and when qURL™ fits better because nobody else should reach the app.

All three give your app a public address. Cloudflare Tunnel puts it on your own domain and can add Cloudflare Access in front; ngrok gives you a free dev domain once you add an authtoken; Tailscale Funnel publishes a ts.net name anyone can reach. If one person or agent needs one private app for a while, qURL sends them an expiring link and gives the app no public address.

Facts checked October 1, 2026 against each vendor’s documentation or our tests. [Download the data](https://layerv.ai/data/localhost-tunnels/tunnels.json)

## Which one to use

__Which tool to use for each job, and why__
| If you need                                                              | Use                                                                                                     | Why                                                                                                                                             |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Webhooks, or a public API anyone can call                                | [ngrok](https://layerv.ai/compare/qurl-vs-ngrok/)                                                       | A stable public dev domain on the free plan, and Traffic Policy for OAuth, OIDC, or IP rules when you need them.                                |
| A lasting hostname on your own domain, behind your company sign-in       | [Cloudflare Tunnel with Cloudflare Access](https://layerv.ai/compare/qurl-vs-cloudflare-tunnel-access/) | The hostname lives on your Cloudflare domain, and Access policies decide who gets through.                                                      |
| A public demo from a device already on your tailnet                      | [Tailscale Funnel](https://layerv.ai/compare/qurl-vs-tailscale-funnel/)                                 | One command on a tailnet device, on ports 443, 8443, or 10000\. Anyone on the internet can open it.                                             |
| Teammates who are already on your tailnet                                | [Tailscale Serve, not Funnel](https://layerv.ai/compare/qurl-vs-tailscale-funnel/)                      | Serve keeps access private to authorized Tailscale users and passes viewer identity to the app.                                                 |
| Give an agent access to a private app that needs an Authorization header | [qURL](https://github.com/layervai/qurl-integrations/blob/main/apps/cli/README.md)                      | qURL can add the app’s credential to requests, so you do not need to build a separate proxy. Requires an advanced CLI setup; see the reference. |
| One person or agent needs one private app, for a while                   | [qURL](https://layerv.ai/cli/)                                                                          | No account and no public address. Each recipient gets a link that is single-use by default and expires within 24 hours.                         |

## The command to a first shareable URL

__What each tool needs installed and the commands to a first shareable URL__
| Tool                      | What you install                                                   | Command to the first shareable URL                                                                                       |
| ------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| Cloudflare Tunnel (named) | cloudflared                                                        | Create the tunnel in the dashboard, run the cloudflared install command it shows, then add a published application route |
| ngrok (free plan)         | ngrok agent                                                        | ngrok config add-authtoken <TOKEN> ngrok http 8080                                                                       |
| Tailscale Funnel          | Tailscale client 1.38.3 or later (an open-source variant on macOS) | tailscale funnel 3000                                                                                                    |
| qURL CLI                  | qurl CLI (Homebrew or release download)                            | qurl publish http://127.0.0.1:3000 qurl share <CRID>                                                                     |

## All four, side by side

__Cloudflare Tunnel, ngrok, Tailscale Funnel, and the qURL CLI compared, with the source for each value__
| Question                            | Cloudflare Tunnel (named)                                                                                                                                                                                   | ngrok (free plan)                                                                                                                                         | Tailscale Funnel                                                                                                                                                    | qURL CLI                                                                                                                                                                                        |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Account needed before the first URL | Yes: account plus a domain on Cloudflare [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/)              | Yes: account and authtoken [ngrok.com](https://ngrok.com/docs/share-localhost/quickstart)                                                                 | Yes: a tailnet with MagicDNS, HTTPS certificates, and the funnel node attribute [tailscale.com](https://tailscale.com/kb/1223/funnel)                               | No. The first publish creates the device identity [our test](https://layerv.ai/research/qurl-behaviour)                                                                                         |
| What the URL looks like             | Stable hostname on your own domain [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/)                    | One assigned dev domain per account (ngrok-free.app / ngrok-free.dev), stable [ngrok.com](https://ngrok.com/docs/gateway/domains)                         | Stable machine-name.tailnet-name.ts.net; machine names are published in Certificate Transparency logs [tailscale.com](https://tailscale.com/kb/1153/enabling-https) | A qurl.link access link per recipient; the app answers at r\_<id>.qurl.site, a name absent from Certificate Transparency logs [our test](https://layerv.ai/research/qurl-behaviour)             |
| Who can reach it                    | Public unless you add a Cloudflare Access application [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/) | Public: anyone with the URL [ngrok.com](https://ngrok.com/docs/share-localhost/quickstart)                                                                | Public: anyone on the internet [tailscale.com](https://tailscale.com/kb/1223/funnel)                                                                                | No one until a link is opened; then the opener’s public IP for that session, including other devices behind that IP [layerv.ai](https://layerv.ai/docs/qurls.md)                                |
| Warning page shown to visitors      | Not documented [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/)                                        | Yes, on free-plan browser traffic (ERR\_NGROK\_6024) [ngrok.com](https://ngrok.com/docs/errors/err%5Fngrok%5F6024)                                        | Not documented [tailscale.com](https://tailscale.com/kb/1223/funnel)                                                                                                | None [our test](https://layerv.ai/research/qurl-behaviour)                                                                                                                                      |
| Visitor access control              | Cloudflare Access policies; service tokens for machines [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/)                   | Traffic Policy: OAuth, OIDC, basic auth, IP restrictions (free plan: 3 OAuth/OIDC users a month) [ngrok.com](https://ngrok.com/docs/share-localhost/auth) | None on Funnel traffic; Funnel requests carry no Tailscale identity headers [tailscale.com](https://tailscale.com/kb/1312/serve)                                    | Single-use access link by default; link and session lifetimes. IP allow and deny lists and other rules can gate links through the API, not the CLI [layerv.ai](https://layerv.ai/docs/qurls.md) |
| Link expiry                         | No per-link expiry; Access session settings apply [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/access-controls/access-settings/session-management/)                         | No built-in expiry; free endpoints have no timeout and stay up while the agent runs [ngrok.com](https://ngrok.com/docs/pricing-limits/free-plan-limits)   | No; runs until you turn it off [tailscale.com](https://tailscale.com/kb/1311/tailscale-funnel)                                                                      | Yes. qurl share returned a 24-hour link in our no-account test; no-account links are capped at 24 hours [our test](https://layerv.ai/research/qurl-behaviour)                                   |
| Single-use links                    | Not documented [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/)                                        | Not documented [ngrok.com](https://ngrok.com/docs/share-localhost/quickstart)                                                                             | No [tailscale.com](https://tailscale.com/kb/1311/tailscale-funnel)                                                                                                  | Yes, the default for qurl share [our test](https://layerv.ai/research/qurl-behaviour)                                                                                                           |
| Protocols                           | HTTP(S); TCP, SSH, RDP, SMB with cloudflared on the client [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/routing-to-tunnel/protocols/) | HTTP(S); TCP after card verification [ngrok.com](https://ngrok.com/docs/gateway/endpoints/tcp)                                                            | HTTPS proxy, TCP, TLS-terminated TCP; ports 443, 8443, and 10000 only [tailscale.com](https://tailscale.com/kb/1311/tailscale-funnel)                               | HTTP(S), WebSocket, SSE; no raw TCP [our test](https://layerv.ai/research/qurl-behaviour)                                                                                                       |
| Free-tier limits                    | Available on all plans; 1,000 tunnels per account, 25 replicas per tunnel [developers.cloudflare.com](https://developers.cloudflare.com/cloudflare-one/account-limits/)                                     | 3 endpoints, 1 GB/month out, 20,000 HTTP requests/month, 4,000 requests/min [ngrok.com](https://ngrok.com/docs/pricing-limits/free-plan-limits)           | Available on all plans; non-configurable bandwidth limits, not published; beta [tailscale.com](https://tailscale.com/kb/1223/funnel)                                | Without an account: up to 3 active resources, with links that last up to 24 hours [github.com](https://github.com/layervai/qurl-integrations/blob/main/apps/cli/README.md)                      |

## What they have in common, and where qURL differs

Cloudflare Tunnel, ngrok, and Tailscale Funnel all answer the same question: how do I give this app an address other people can reach? Each puts the app on a public name, then leaves it to you to decide who gets through: Cloudflare Access policies, ngrok Traffic Policy, or, for Funnel, the app’s own sign-in.

qURL answers a narrower question: how do I let this one person or agent in, for a while? The app gets no public address. qurl publish registers it, and qurl share prints a link for one recipient that is single-use by default and expires within 24 hours. It suits a client preview, a check on your phone, or an agent that needs a private target. It does not suit webhooks, a public API, or raw TCP, which is where the three tunnels win.

## Frequently Asked Questions

Which of the three is private by default? 

None. A Cloudflare Tunnel hostname is public unless you add a Cloudflare Access application, an ngrok URL is public unless you add a Traffic Policy, and Tailscale Funnel is public to anyone, with no access control on Funnel traffic. Tailscale Serve is private, but viewers need a Tailscale account and client. With qurl 3.4.1 or later, a plain publish makes the app private: it opens only for the publisher’s devices and the people and devices the publisher allowed. A single-use access link is one way to let a recipient in.

Do any of them work without an account? 

No. Cloudflare Tunnel needs a Cloudflare account and a domain on Cloudflare, ngrok needs an account and authtoken, and Funnel needs a tailnet. Cloudflare quick tunnels on trycloudflare.com skip the account, and so does the qURL CLI.

Can I give someone a link that expires or works once? 

Not with these three. ngrok endpoints have no built-in expiry and stay up while the agent runs, Cloudflare Tunnel has no per-link expiry (Access session settings apply), and Funnel runs until you turn it off. None of them documents single-use links. With no flags, qurl share prints a link that can be opened once and expires within 24 hours.

Which one gives me a stable URL? 

All three. Cloudflare Tunnel gives you a stable hostname on your own domain, the ngrok free plan gives each account one stable dev domain on ngrok-free.app or ngrok-free.dev, and Funnel uses machine-name.tailnet-name.ts.net, a name that is published in Certificate Transparency logs. qURL gives each recipient their own access link instead of one shared URL.

What does each one cost to start? 

Cloudflare Tunnel is available on all Cloudflare plans. The ngrok free plan includes 3 endpoints, 1 GB a month of outbound data, and 20,000 HTTP requests a month. Funnel is available on all Tailscale plans with bandwidth limits Tailscale does not publish, and it is in beta. The qURL CLI without an account allows up to 3 active resources, with links that last up to 24 hours.

Who can open a qURL link? 

Whoever holds it, once: with no flags, qurl share prints a single-use link. Opening it admits the network address it was opened from for the session, which lasts 1 hour by default for an app published from the CLI. Other devices on the same public IP address, such as an office or café network, can reach the app until the session ends, so keep your app’s own sign-in for anything sensitive. By default a link admits whoever opens it; access rules set through the API, such as IP allow and deny lists, can restrict that.

## Related Resources

[ngrok alternatives: every way to share localhost →](https://layerv.ai/compare/localhost-tunnels/) [qURL vs ngrok →](https://layerv.ai/compare/qurl-vs-ngrok/) [qURL vs Tailscale Funnel →](https://layerv.ai/compare/qurl-vs-tailscale-funnel/) [qURL vs Cloudflare Quick Tunnels →](https://layerv.ai/compare/qurl-vs-cloudflare-quick-tunnels/) [LayerV vs Cloudflare Access →](https://layerv.ai/compare/layerv-vs-cloudflare-access/) [How we tested qURL →](https://layerv.ai/research/qurl-behaviour/)

## Share one app without a public address

Install the qURL CLI, then publish the app you have running. No sign-up.

[Install the CLI ↗](https://layerv.ai/cli/)

New to qURL? Start at [qurl.link ](https://qurl.link/)



---

*This markdown version is auto-generated from [https://layerv.ai/compare/cloudflare-tunnel-vs-ngrok-vs-tailscale-funnel/](https://layerv.ai/compare/cloudflare-tunnel-vs-ngrok-vs-tailscale-funnel/) for AI agents. Curated agent resources: [llms.txt](https://layerv.ai/llms.txt). For the full interactive experience, visit the HTML version.*

