The Open Source ngrok Alternative for Local HTTPS Dev Tunnels

The Open Source ngrok Alternative for Local HTTPS Dev Tunnels

Tako-kun·

There are two moments when local development suddenly needs a public URL.

The first is practical: a webhook provider, OAuth callback, teammate, or phone on another network needs to reach the app on your laptop. The second is emotional: you realize the clean https://my-app.test/ setup you had five minutes ago is about to become three terminals, a random tunnel URL, and a sticky note about callback URLs.

That second moment is why open-source Tako has tako dev --tunnel: a public HTTPS URL for a running app without a separate tunnel daemon.

tako dev --tunnel

Or, if tako dev is already running, press t.

Tako creates a public URL like:

https://my-app-k7q4z2.tako.website/

The URL is public, HTTPS, and stable for the same app name plus local Tako Identity. When the tunnel connection drops, Tako keeps the URL reserved, shows it as reconnecting, and retries automatically. You do not need a second process, a reserved subdomain, or a config file just to remember where your app is running.

The Local Tunnel Problem

Tools like ngrok, Cloudflare Tunnel, localtunnel, zrok, and bore are useful. They all solve a real networking problem: your laptop is behind NAT, the internet cannot dial it directly, so an outbound connection has to meet a relay somewhere public.

The awkward part is that most tunnel tools sit beside your dev environment instead of inside it. Your app runs on one local port. Your framework has its own allowed-host rules. Your tunnel tool forwards to whatever port you remembered to type. If the public hostname changes, callbacks need updates. If the tunnel process dies, your app may still be fine locally, but everyone else sees a dead URL.

That shape is okay for one-off demos. It gets annoying when public dev URLs become part of your daily loop.

Tako already owns the local dev surface: the dev daemon starts the app, assigns the loopback port, terminates local HTTPS, tracks registered routes, streams logs, and keeps https://my-app.test/ alive. Tunnel mode plugs into that same system instead of asking you to bolt another one on.

Diagram

The public side speaks to tako.website. The local side stays routed through the same dev proxy that already serves your .test URL.

What Makes Tako Different

The big difference is not that Tako has invented tunneling. It is that the tunnel knows about your app.

When you enable tunnel mode, the dev server loads or creates a local Tako Identity, asks the tunnel service for a challenge, signs that challenge, and opens an outbound WebSocket session. The public hostname includes the app name and an id derived from the app plus identity, so the same project on the same machine gets the same public URL when the identity is available.

On macOS, Tako tries to keep that identity in iCloud Keychain and falls back to local storage when synced Keychain access is unavailable. On other platforms, it uses local identity storage. Either way, the URL is tied to a local key, not a random string printed by a throwaway process.

That gives tunnel mode a few nice properties:

ConcernSeparate tunnel CLItako dev --tunnel
Local app targetUsually a port you pass by handThe app registered with the Tako dev daemon
Public URLOften random unless reserved/configuredStable for app name plus Tako Identity
HTTPSPublic HTTPS from the tunnel providerPublic HTTPS plus local HTTPS through Tako
Host routingYou wire Host headers and framework allowlistsTako routes through the existing dev route
Process modelExtra daemon/process beside your appBuilt into the running tako dev session
Reconnect behaviorDepends on the tool and how it is supervisedURL stays reserved while Tako reconnects
Local docs pathTool-specific setupSame tako dev and CLI flow

The result feels smaller. You run the same command you were already running:

tako dev --tunnel

You can still use the local URL:

https://my-app.test/

And now you also have the public one:

https://my-app-k7q4z2.tako.website/

Both point at the same registered app. Both flow through the same route model described in the tako.toml reference. The public URL is just the internet-facing entrance.

A Respectful Comparison

If you need a general-purpose tunnel, the standalone tools are still good tools. Ngrok has a mature hosted platform and domain controls. Cloudflare Tunnel is excellent when you already own the domain and want traffic on Cloudflare’s network. zrok is a serious open-source sharing system built around zero-trust networking. localtunnel is simple for quick Node-flavored sharing. bore is tiny and TCP-shaped.

Tako is narrower on purpose: local HTTPS dev tunnels for apps already running under Tako.

ToolBest fitTradeoff for local app dev
ngrokPolished hosted tunnels, traffic features, managed domainsAnother CLI and account surface outside your dev runtime
Cloudflare TunnelStable custom hostnames on Cloudflare-controlled DNSGreat but setup-heavy for quick branch previews
localtunnelVery quick open-source localhost sharingPublic hostname availability and HTTPS-to-local details are separate concerns
zrokOpen-source sharing with private/public modes and zero-trust rootsMore general than a framework-aware dev command
boreSmall self-hostable TCP tunnelsLower-level than app-aware HTTPS routing
Tako tunnelPublic URL for a tako dev appOnly useful when the app is running through Tako

That last row is the point. We are not trying to replace every tunnel tool. We are trying to remove a whole category of tunnel setup from the path between “my app works locally” and “someone else can open it.”

For webhook testing, this means you can give Stripe, GitHub, Customer.io, or any other callback sender a stable app-derived URL while your local app keeps running behind Tako. For OAuth, it means fewer “which callback URL is live today?” tabs. For teammate review, it means tako dev --tunnel, paste, keep coding.

How It Behaves When Things Get Weird

Tunnel mode is deliberately boring during failure. That is a compliment.

If the tunnel connection drops, the URL does not disappear. Tako keeps tunnel mode enabled, marks the tunnel as reconnecting in the status panel, retries with bounded exponential backoff, and prints log lines when reconnecting starts and when the tunnel reconnects.

If you start another tunnel for the same app and identity, it replaces the previous active session for that URL. If one identity has too many active tunnel URLs at once, the service accepts the new one and closes the oldest active tunnel for that identity. The closed client turns tunnel mode off and tells you why.

If someone visits a tunnel URL while it is inactive or disconnected, they get a Tako-styled error page in the browser. API-ish clients that send Accept: application/json get JSON, and other clients get plain text.

That behavior matters because dev tunnels are usually used right when someone else is waiting. A webhook retry is hitting your endpoint. A teammate is refreshing a bug repro. An OAuth provider is redirecting back to you. The URL should be the stable thing, even if the laptop briefly changes Wi-Fi networks.

Try It

Install Tako, run your app through tako dev, and turn on the tunnel:

brew install takoserver/tap/tako
cd your-project
tako dev --tunnel

Inside an existing interactive session, press t to toggle the tunnel. Run tako dev list to see registered apps and the current tunnel URL for any app with tunnel mode enabled.

For local-device testing on the same Wi-Fi, use LAN mode instead. For a custom domain on Cloudflare, the manual Cloudflare Tunnel setup still works. For the common “I need a public HTTPS URL for this local Tako app right now” case, tunnel mode is the shorter path.

No port forwarding. No second tunnel daemon. No random URL musical chairs. Just your app, already running under Tako, with a public HTTPS door when you need one.