Get started - it's free!
Login
© 2025

tsnet

tsnet is a library that lets you embed Tailscale inside a Go program. With tsnet, you can programmatically make direct connections to devices on your Tailscale network (known as a tailnet), just like any other device in your tailnet would. When combined with other features of Tailscale, you can create new and interesting ways to use your tailnet.

Overview

Typically, every IP address in your tailnet has to be strongly associated with a single device. This makes it difficult to run multiple services on a single device, especially if all of those services have different access control rules. tsnet lets you run multiple services on the same device with different IP addresses, access control rules, and even user identities.

tsnet uses a userspace TCP/IP networking stack.

Inside Tailscale, we built and constantly use tools on top of tsnet. tsnet powers our internal URL shortener golink. It powers the support tooling that our support team uses daily to help you resolve problems. Without tsnet, our Tailscale-enabled tools would be far more difficult to create and maintain.

Externally, people have used tsnet to provide metrics, deliver administrative endpoints, and create other functionality. For examples, visit the Go tsnet known importers page.

Include tsnet in your program

Run the following command to add tsnet to your dependencies and make it available for use in your Go program:

go get tailscale.com/tsnet

In your Go program, import tailscale.com/tsnet:

package main

import (
    "flag"
    "fmt"
    "html"
    "log"
    "net/http"
    "strings"

    "tailscale.com/tsnet"
)

Make calls with tsnet.Server

The tsnet.Server object provides the entry point for your program to connect with other devices in your tailnet. Initialize tsnet.Server by specifying an address to listen on and a hostname for the device that will be created.

var (
    addr = flag.String("addr", ":80", "address to listen on")
    hostname = flag.String("hostname", "tshello", "hostname to use in the tailnet")
)

func main() {
    flag.Parse()
    srv := new(tsnet.Server)
	srv.Addr = *addr
    srv.Hostname = *hostname
	if err := srv.Start(); err != nil {
    log.Fatalf("can't start tsnet server: %v", err)
}
    defer srv.Close()

	// Use the tsnet.Server object to interact with your tailnet
	...
}

Device creation and authentication

If you are not using an auth key, the call to the Server.Start function will result in creation and display of a Tailscale authentication URL. Use the URL to log in to Tailscale, same as you would for other devices on your tailnet. If device approval is enabled for the tailnet, a tailnet admin will need to approve the device.

As an alternative to logging in by using a Tailscale authentication URL, you can use an auth key as part of your tsnet.Server initialization. This lets you pre-approve a device.

The authentication process can occur even if Server.Start itself is not directly called in your code, because some Server functions will implicitly call Server.Startif it has not yet been called.

To learn more about the tsnet.Server functions, see tsnet.Server.

For a complete example that uses tsnet, see Hello tsnet.

Last updated Feb 7, 2025