Tailscale’s website reads:
A secure network that just works
Zero config VPN. Installs on any device in minutes, manages firewall rules for you, and works from anywhere.
gokrazy-based devices are no exception! This guide shows you how to use Tailscale with gokrazy.
Tailscale’s networking will come in handy when accessing your gokrazy server remotely (no static DHCP leases, port-forwarding and DynDNS required!), or even to secure your communication when gokrazy is connected to an unencrypted WiFi network.
tailscale.com
v1.56.1 or later (latest version used automatically unless you have the package already in go.mod)/perm/
needs to be initialized (instructions use github.com/gokrazy/mkfs
to initialize)
to persist authentication over reboots.Add the Tailscale daemon tailscaled
and CLI tailscale
Go packages to your
gokrazy instance:
gok add tailscale.com/cmd/tailscaled
gok add tailscale.com/cmd/tailscale
# Automatically initialize a file system on the /perm partition on first boot:
gok add github.com/gokrazy/mkfs
Then, open your instance’s config.json
in your editor:
gok edit
And configure Package config: Command-line flags for Option A or Option B:
Option A: interactive authentication
{
"Hostname": "ts",
"Packages": [
"github.com/gokrazy/fbstatus",
"github.com/gokrazy/hello",
"github.com/gokrazy/serial-busybox",
"github.com/gokrazy/breakglass",
"tailscale.com/cmd/tailscaled",
"tailscale.com/cmd/tailscale",
"github.com/gokrazy/mkfs"
],
"PackageConfig": {
"tailscale.com/cmd/tailscale": {
"CommandLineFlags": [
"up"
]
}
}
}
Option B: unattended authentication with auth key
Alternatively, navigate to Tailscale console and open Settings / Keys. Generate auth key.
Include the key to tailscale flags:
{
"Hostname": "ts",
"Packages": [
"github.com/gokrazy/fbstatus",
"github.com/gokrazy/hello",
"github.com/gokrazy/serial-busybox",
"github.com/gokrazy/breakglass",
"tailscale.com/cmd/tailscaled",
"tailscale.com/cmd/tailscale",
"github.com/gokrazy/mkfs"
],
"PackageConfig": {
"tailscale.com/cmd/tailscale": {
"CommandLineFlags": [
"up",
"--auth-key=tskey-AAAAAAAAAAAA-AAAAAAAAAAAAAAAAAAAAAA"
]
}
}
}
Then, deploy as usual:
gok update
Skip this step if you are using option B with auth key.
gok
CLI./user/tailscale
and find the login URL.You are now connected to Tailscale and you can access your gokrazy instance over Tailscale.
Tailscale requires re-authentication periodically. You can disable key expiry from Tailscale console for the gokrazy instance to not require login every 3 months.
To allow hosts in your Tailnet to access devices in your network other than your gokrazy appliance, you can set up Tailscale as a subnet router.
{
"Hostname": "ts",
"Packages": [
"github.com/gokrazy/serial-busybox",
"tailscale.com/cmd/tailscaled",
"tailscale.com/cmd/tailscale"
],
"PackageConfig": {
"tailscale.com/cmd/tailscale": {
"CommandLineFlags": [
"up",
"--advertise-routes=192.168.0.0/24"
]
}
}
}
Starting Tailscale version v1.64, IP forwarding is automatically enabled on Gokrazy.
To access the gokrazy appliance using SSH authenticating using Tailscale, you can enable Tailscale SSH.
{
"Hostname": "ts",
"Packages": [
"github.com/gokrazy/serial-busybox",
"tailscale.com/cmd/tailscaled",
"tailscale.com/cmd/tailscale"
],
"PackageConfig": {
"tailscale.com/cmd/tailscale": {
"CommandLineFlags": [
"up",
"--ssh=true"
]
}
}
}
Note that Tailscale SSH needs to be allowed by your Tailnet ACL. You can configure to allow, for example, each user to access their own devices using Tailscale SSH, or define which hosts users can access.
Before Tailscale v1.56.1, Tailscale used Userspace networking mode on gokrazy, meaning you needed to use Tailscale as an HTTP proxy to establish outgoing connections into your tailnet.
With Tailscale v1.56.1 and newer, programs running on gokrazy can connect to other devices in your tailnet without extra steps! 🎉 DNS resolution and TCP connections work out of the box.
Before Tailscale v1.56.1, Tailscale used Userspace networking mode on gokrazy, meaning you needed to use the tsnet package if you wanted to restrict a listener to Tailscale.
With Tailscale v1.56.1 and newer, you can listen on Tailscale addresses and use LocalClient.WhoIs to obtain the remote identity:
package main
import (
"flag"
"fmt"
"log"
"net/http"
"tailscale.com/client/tailscale"
)
func main() {
listen := flag.String("listen", "gokrazy.monkey-turtle.ts.net:8111", "[host]:port listen address")
allowedUser := flag.String("allowed_user", "", "the name of a tailscale user to allow")
flag.Parse()
log.Printf("starting HTTP listener on %s", *listen)
var ts tailscale.LocalClient
httpsrv := &http.Server{
Addr: *listen,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
who, err := ts.WhoIs(r.Context(), r.RemoteAddr)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if who.UserProfile.LoginName != *allowedUser || *allowedUser == "" {
err := fmt.Sprintf("you are logged in as %q (userprofile: %+v), but -allowed_user flag does not match!", who.UserProfile.LoginName, who.UserProfile)
log.Printf("forbidden: %v", err)
http.Error(w, err, http.StatusForbidden)
return
}
fmt.Fprintf(w, "hey there, %q! this message is served via tailscale from gokrazy!", who.UserProfile.LoginName)
}),
}
log.Fatal(httpsrv.ListenAndServe())
}
--allowed_user
flag to verify that tailscale authentication works as expected