Embed Funnel in your App

Photo of Maisem Ali

We recently released Tailscale Funnel for testing, which lets you expose a locally running web server to the internet.

Funnel can be especially useful when you are hosting services in a homelab, or developing against webhook APIs that need to POST back to your server. The standard way to use Funnel is to install Tailscale, run your server on localhost, and then configure Funnel to share that server.

Today we are adding another way to use Funnel: compile it into your program. When you do this, there is no need to install Tailscale on the host. This allows Funnel to work in serverless environments such as Heroku or fly.io.

The open source Go tsnet package has gained a new method: ListenFunnel. Call one function and you get a net.Listener with a publicly reachable domain name and a valid TLS certificate. Using it looks like this:

s := &tsnet.Server{ Hostname: "fun" }
defer s.Close()
ln, err := s.ListenFunnel("tcp", ":443") // does TLS
if err != nil {
defer ln.Close()
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<html>Hello from Funnel!")
log.Fatal(http.Serve(ln, h))

See the full example on GitHub in tsnet-funnel.go.

After enabling HTTPS and Funnel in the Tailscale admin panel, you can generate an auth key and use it to run this example:

TS_AUTHKEY=<your-key> go run ./tsnet-funnel.go

Your local web server will be available on the internet with your tailnet name at https://fun.<your-fun-name>.ts.net.