Compare

Tailscale vs Cloudflare Tunnel vs Bore: What I Use For My Daemon's Tunnel

Akshay Sarode
Direct answer

For private remote access to a homelab box: Tailscale. For exposing a self-hosted web app to the public: Cloudflare Tunnel. For embedding "give this binary a public URL" inside another binary you ship: bore. They're not really competitors — different problems, picked the right one for each.

Anyone who's run a homelab has fought the "how do I reach this from outside" problem. The popular three answers each solve a different version of the question. People online compare them as if they're substitutes; XDA's writeup gets it right that the answer depends on what you're exposing and to whom.

The three jobs

JobBest fit
"My laptop should reach my homelab from anywhere"Tailscale
"My self-hosted dashboard should have a public HTTPS URL"Cloudflare Tunnel
"My binary should expose a port without an account or signup"bore (or ngrok / cloudflared anonymous mode)

Tailscale

What it is: a peer-to-peer mesh built on WireGuard. Every device has a stable Tailscale IP. Devices connect to each other directly when they can; relay through DERP when they can't (CGNAT, symmetric NAT).

What it's great at: private networking. Your laptop sshes to my-server.tail-scale.ts.net from any network, any time. Latency is excellent because most pairs find a direct path.

What it's not: a public-internet front door. Tailscale Funnel exists but is a partial story — it gives you one HTTPS URL routing to one Tailscale device; not a full reverse-proxy story.

Cost: free for personal use up to 100 devices. Paid plans for teams.

I use it for: ssh, internal services that should never be public, sharing a NAS with my partner.

Cloudflare Tunnel

What it is: an outbound persistent connection from your machine (cloudflared) to Cloudflare's edge. The edge proxies inbound HTTPS to your service. CGNAT-friendly because all connections are outbound.

What it's great at: public web apps. You get a real HTTPS URL on your domain (or a *.trycloudflare.com subdomain). Cloudflare WAF, caching, DDoS in front for free.

What it's not: a private network. Anyone with the URL can hit your service. You can layer Cloudflare Access on top for auth, but that's a separate product.

Cost: free.

I use it for: anything I want shareable via URL — Plex, public web demos, ad-hoc "let my mom watch this stream."

bore

What it is: a tiny Rust reverse-tunnel binary. ~5MB. No account, no auth (you bring your own). One command opens a tunnel between a port on your machine and a port on a relay server.

What it's great at: embedding inside another binary. The relay can be your own — bored is the server. The client is a single static binary you ship.

What it's not: production-grade exposure. No TLS termination, no auth, no traffic shaping out of the box. You build those on top.

Cost: free. (Run your own relay on a $5/mo VPS.)

I use it for: embedding inside celistrad. The daemon ships with the bore client compiled in. When the dashboard can't reach 127.0.0.1:33120, the daemon's bore client opens a tunnel to mail.ujex.dev:7000; nginx terminates Let's Encrypt TLS and reverse-proxies to a per-machine subdomain on *.tunnel.ujex.dev. The whole thing is invisible to the user.

The case where they overlap

For a single-developer homelab where you want both private access (ssh to the box) and a public URL for one specific service, you can run Tailscale + Cloudflare Tunnel side by side. They don't fight. Tailscale handles the device-to-device case; Cloudflare Tunnel handles the public-URL case.

What about ngrok?

ngrok is the original. It does everything — public URLs, custom domains, TCP tunneling. Free tier is severely limited (random URL, low rate limit). The paid plans are fine but expensive for casual use. Hookdeck has been quietly eating ngrok's developer-tooling lunch with a free tier and an MCP server for AI agents.

ngrok and bore solve the same problem; bore solves it as code you can vendor; ngrok solves it as a SaaS you pay for. Pick based on whether you're embedding it.

Why I picked bore for Celistra

Result: zero user setup. The user doesn't sign up for ngrok. They don't run cloudflared. They don't install Tailscale. The daemon ships, runs, and "off-LAN works." That's the goal.

What this means for you

If you're building a tool that needs reachability and you don't want the user to manage tunnel auth: embed bore (or ngrok-paid if you want SaaS) and run your own relay. If you're building for yourself: Tailscale + Cloudflare Tunnel side by side covers both jobs and costs $0. Don't pick one of the three; pick the right one for each problem you actually have.

FAQ

Can I use Tailscale Funnel instead of Cloudflare Tunnel for public URLs?

Yes for simple cases. You get one URL per device, three devices max on the free plan. For more devices or custom domains, Cloudflare Tunnel is still better.

Why not just use SSH reverse port forward?

It works. You need a public-IP server somewhere to forward through, you handle reconnects yourself, no TLS termination. bore + nginx is the productionized version of exactly this pattern.

Is bore safe?

The protocol is simple — TCP tunneled inside TCP. Auth is whatever you put on top. For Celistra we add a bore-side admission token (rotated via Firestore) plus a Firebase ID token check at the daemon. Without those, anyone hitting the public URL gets a 401.

Does bore work behind CGNAT?

Yes — same reason Cloudflare Tunnel does. The connection is outbound from your machine to the relay; the inbound side is the relay's public IP.