Versus

Self-Hosting from Home: Cloudflare Tunnel vs. Tailscale Funnel vs. ngrok

Cloudflare Tunnel, Tailscale Funnel and ngrok compared for serving a site from home: domains, free-tier limits, security and which one to pick.

·
9 min read
·
AI-assisted

AI tooling disclosure

Generative AI materially contributed to this article.

Human review confirmed by the author.

Self-Hosting from Home: Cloudflare Tunnel vs. Tailscale Funnel vs. ngrok

The short version

You can serve a site from a spare machine at home without opening a single router port, by using a tunnel that your machine opens to a provider. They differ in whose domain you use, what the free tier allows, and what each one was built for.

  • Cloudflare Tunnel is the pick for a site you want to keep running under your own domain.

  • Tailscale Funnel is the fastest to set up if you already use Tailscale: one command gives you a public HTTPS address with no domain to buy, but it has tight limits on ports and bandwidth, and it is still in beta.

  • ngrok is built for development and demos. It has the best request inspector of the three, but its free plan has small monthly quotas.

The rest of this post explains how each works, where each one breaks, and how to choose. Limits and pricing change often, so the figures here are as of October 2026 and link to their sources at the end.

How all three work

All three swap a port-forwarding problem for an outbound-connection problem. A small agent on your machine opens a connection to the provider, and the provider sends each visitor's request down it and returns the response the same way, so your router never accepts a connection from outside. Cloudflare notes that this works without a publicly routable IP address, which helps when your internet provider shares one address across many customers.

flowchart LR
    V["Visitor<br/>with a browser"] -- request --> P["Provider's edge<br/>Cloudflare, Tailscale relay or ngrok"]
    P <==>|"one connection, opened outbound<br/>from your machine"| A
    subgraph Home["Your home network: no inbound port open"]
        A["Tunnel agent<br/>cloudflared, Tailscale or the ngrok agent"] --> App["Your app<br/>listens on localhost only"]
    end

Cloudflare Tunnel: your domain, always on

Cloudflare Tunnel is the one to use for a site that should stay up, because it puts a hostname on your own domain in front of your home server and keeps it there. A program called cloudflared opens outbound connections from your machine to the nearest Cloudflare data center, and Cloudflare's docs note that you can then block all inbound traffic at your firewall.

The catch comes first: to publish an application through a tunnel, you must add a domain to Cloudflare. If you do not own one yet, a quick tunnel works for testing:

cloudflared tunnel --url http://localhost:8080

That prints a random trycloudflare.com address and needs no account or domain, but the address changes every time. Cloudflare says quick tunnels are for testing, have no uptime guarantee, allow 200 in-flight requests per tunnel (more get a 429), and do not support Server-Sent Events.

Setting up a permanent tunnel

There are two ways to do it:

  1. In the dashboard. Go to Networking, then Tunnels, and create a tunnel. Copy the install command it generates for your operating system and run it on the server. Then add a published application route: choose a subdomain and domain, and set the service URL, such as http://localhost:8000.

  2. With a config file. Keep the rules in config.yml and run the tunnel from it:

tunnel: <Tunnel-UUID>
credentials-file: /root/.cloudflared/<Tunnel-UUID>.json

ingress:
  - hostname: example.com
    service: http://localhost:8000
  - service: http_status:404

The final http_status:404 rule is a required catch-all. Two commands help while you write the file: cloudflared tunnel ingress validate checks the rules, and cloudflared tunnel ingress rule https://example.com shows which rule a URL matches.

To create and run the same tunnel from the command line, these four commands are enough:

cloudflared tunnel login
cloudflared tunnel create home
cloudflared tunnel route dns home app.example.com
cloudflared tunnel run home

If your config file is elsewhere or has a custom name, put --config /path/your-config-file.yml before run.

What you get

  • No charge for the tunnel. Cloudflare announced in 2021 that any organization can use the outbound-only connection at no cost. Check current terms before you depend on it.

  • More than websites. Tunnel can also connect SSH servers, remote desktops and other protocols.

  • Failover. You can run as many cloudflared connectors as you like in one tunnel, so a second machine at home can take over.

  • A login in front. Cloudflare Access applications are deny-by-default, so you add an Allow policy for the people you trust. The Security section covers the order to set it up in.

Where it falls short

Tailscale Funnel: the fastest start, with the tightest rules

If you already run Tailscale, Funnel is the quickest way to make one service public: one command gives you an HTTPS address, with nothing to install beyond Tailscale. Tailscale describes it as routing traffic from the public internet to a service on a device in your tailnet, through an encrypted TCP proxy on Funnel relay servers that cannot decrypt the traffic.

Setting it up

You need Tailscale v1.38.3 or later, MagicDNS, HTTPS certificates enabled for the tailnet, and the funnel node attribute in your policy file (by default it goes to autogroup:member). The first time you run tailscale funnel, it opens a web page where you approve Funnel, and Tailscale then creates the certificates and adds the attribute for you.

# Expose the app on local port 3000 and keep it running after reboots
tailscale funnel --bg 3000

# See what is currently public
tailscale funnel status

# Turn everything off
tailscale funnel reset

The --bg flag matters. Without it, Funnel stops when you reboot or restart Tailscale and you have to start it again by hand. With it, Funnel resumes on its own.

What you get

  • No domain to buy. Your address is a name under your tailnet's ts.net domain, and nothing else is needed.

  • A private mode on the same tool. tailscale serve shares a service only with devices in your tailnet, while Funnel makes it public. A port cannot be both at once: the most recent serve or funnel command on it decides.

  • Every plan. Funnel is available on all Tailscale plans.

Where it falls short

  • Three ports only. Funnel can listen only on 443, 8443 and 10000.

  • TLS only. Funnel works only over TLS-encrypted connections, so it is not a way to expose a plain TCP service.

  • Beta. Tailscale still labels Funnel as beta, so behavior and limits may change.

  • Bandwidth limits you cannot tune. Traffic is subject to non-configurable bandwidth limits, and the docs give no figures. Test it with your real traffic before you rely on it, especially if you serve large files.

  • Your names only. Funnel can use only names in your tailnet's domain, so your own domain is not an option.

ngrok: built for development, usable for hosting

ngrok is the tool here that is best at inspecting and shaping traffic, and its free plan is sized for testing rather than for running a site. Getting started takes one command:

ngrok http 8080

Every account gets a free dev domain. Per ngrok's docs, "its URL is automatically generated and cannot be changed," and it is a stable, auto-assigned hostname. Choosing your own name with the --url flag is a paid-plan feature.

What the plans give you

Free

Hobbyist ($10 a month)

Domains

1 auto-assigned dev domain

10 ngrok-branded domains

Data transfer out

1 GB a month

5 GB a month, then $0.10 per GB

HTTP requests

20,000 a month

100,000 a month, then $1 per 100,000

Interstitial warning page

Shown to browsers

Removed

Online endpoints

3

3

Traffic Inspector history

24 hours

72 hours

Bringing your own custom domain starts at the Pay-as-you-go plan, which is $20 a month plus usage. The free-plan figures come from ngrok's limits page.

The interstitial page

On the free plan, ngrok shows a warning page before HTML traffic from a browser, to deter phishing. A visitor who clicks through gets a cookie that hides the page for that domain for 7 days. It does not affect API or programmatic clients, and you can skip it by sending an ngrok-skip-browser-warning header with any value.

Running it from a config file

Open the config with ngrok config edit, which creates ngrok.yml when you add your authtoken. A minimal v3 file looks like this:

version: 3

agent:
  authtoken: YOUR_AUTHTOKEN

endpoints:
  - name: home
    url: your-assigned-name.ngrok-free.app
    upstream:
      url: 8080

Then ngrok start home runs it in the foreground.

To keep it running without a terminal open, install the agent as an operating system service:

ngrok service install --config=/etc/ngrok/ngrok.yml
ngrok service start

The service behaves as if you had run ngrok start --all, so your config file has to define the endpoints. The docs do not say whether the service starts at boot, so reboot the machine once and check.

Where it earns its place

  • Seeing every request. The Traffic Inspector shows requests and responses, which is why ngrok is so good for webhook work.

  • Rules in front of your app. Traffic Policy lets you add checks such as OAuth or webhook verification before a request reaches you. The free plan allows 5 rules per policy and 3 monthly active users on OAuth and OIDC logins.

Where it falls short

  • Small quotas. A page with a few images can use up the monthly data allowance quickly, and the request allowance is small for anything public.

  • A warning page for browsers. The free-plan interstitial described above is a real annoyance on a website your friends open in a browser, and only a paid plan removes it.

Side by side

The three differ most in who owns the address and how much traffic they allow.

Cloudflare Tunnel

Tailscale Funnel

ngrok (Free plan)

Your address

Your own domain; quick tunnels get a random trycloudflare.com name

A name under your tailnet's ts.net domain

An auto-assigned dev domain that cannot be changed

Domain you must own

Yes, added to Cloudflare, for a permanent tunnel

No

No

What it carries

HTTP sites, plus SSH, remote desktop and other protocols

TLS-encrypted connections on ports 443, 8443 and 10000

HTTP endpoints; raw TLS endpoints need a paid plan

Traffic limits

100 MB per upload on Free and Pro zones; no monthly quota stated

Bandwidth limits you cannot change, with no figures published

1 GB out and 20,000 HTTP requests a month

Maturity

Quick tunnels have no uptime guarantee; permanent tunnels are the production path

Beta

Free plan shows a warning page to browsers

Security: the tunnel is your new front door

A tunnel removes your router as a barrier, so anything you publish is reachable from the whole internet and needs its own login before you point a hostname at it.

  • Put a login in front first. With Cloudflare, create the Access application before the tunnel route, because a route without one is open to anyone, and turn on Protect with Access so cloudflared rejects requests that bypass Access. With ngrok, add OAuth through Traffic Policy. Tailscale's Funnel page describes no login layer, so the app has to handle authentication itself, or you can use tailscale serve to keep the service private to your tailnet.

  • Bind the app to localhost. If the app listens only on 127.0.0.1, other devices on your home network cannot reach it directly, and the tunnel agent is the only way in.

  • Keep the machine small. Use a dedicated machine, a VM or a container, run the app as a non-root user, turn on automatic security updates, and keep nothing sensitive beside it.

  • Assume the provider can read HTTP traffic, except on Funnel. Cloudflare Access and ngrok's Traffic Policy and inspector work on the contents of HTTP requests, which means that traffic is visible to them. Tailscale says Funnel relays cannot decrypt what they carry. Either way, keep secrets out of URLs and logs.

  • Know your off switch. tailscale funnel reset clears Funnel, ngrok service stop stops the ngrok service, and stopping the cloudflared process closes the tunnel. Try it once before you need it.

Which one should you pick?

Start with what the thing is for, then ask about your domain, and only then check whether Funnel's rules fit.

flowchart TD
    Q1{"Is it a demo, a webhook test<br/>or something you are still building?"}
    Q1 -- yes --> R1["ngrok<br/>Request inspector and replay, free dev domain"]
    Q1 -- no --> Q2{"Do you want visitors to see<br/>your own domain in the address?"}
    Q2 -- yes --> R2["Cloudflare Tunnel<br/>Your domain, Access login in front, no charge for the tunnel"]
    Q2 -- no --> Q3{"Do you already use Tailscale and need<br/>only TLS on 443, 8443 or 10000?"}
    Q3 -- yes --> R3["Tailscale Funnel<br/>One command, no domain to buy, beta, with limits you cannot tune"]
    Q3 -- no --> R4["Buy a domain, use Cloudflare Tunnel<br/>or move to a paid ngrok plan"]

The order matters because the free plans fail in different places. ngrok's quotas and warning page get in the way of a public site first, Cloudflare's domain requirement gets in the way if you do not own a domain, and Funnel's ports and bandwidth limits get in the way of anything heavy. If two answers fit, choose the one whose limit you can live with.

Sources

All pages were opened in October 2026.

Cloudflare

Tailscale

ngrok

Comments(0)

Join the discussion by logging into your account.

No comments yet. Be the first to comment!

Shobit Singh

Passionate developer sharing knowledge about modern web technologies and best practices.

Subscribe to Shobit Singh's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.