tstun

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2026 License: MIT Imports: 13 Imported by: 0

README

tstun

A Caddy module that routes reverse_proxy traffic through a Tailscale network using tsnet (userspace).

No Tailscale daemon required — the node runs embedded inside Caddy.

How it works

Client → Caddy (tstun) → Tailnet → target-node:port

tstun registers two Caddy modules:

Module ID Purpose
App tsnet Manages a single tsnet.Server lifecycle (global)
Transport http.reverse_proxy.transport.tsnet Overrides DialContext to route through Tailnet

Caddyfile

{
    tsnet {
        auth_key {env.TS_AUTH_KEY}    # optional after first auth
        hostname "my-proxy"           # node name on Tailnet
        state_dir "./tsnet_state"     # persist keys across restarts
    }
}

app.example.com {
    reverse_proxy my-server:8080 {
        transport tsnet
    }
}

# multiple sites work fine
api.example.com {
    reverse_proxy api-node:3000 {
        transport tsnet
    }
}

The upstream address (my-server:8080) is a Tailscale MagicDNS hostname or Tailnet IP.

Build

Requires Go 1.26+.

go build -o tstun ./cmd/tstun

Or with Docker:

docker build -t tstun .

Run

./tstun run --config Caddyfile
First run

On first run, tsnet needs to authenticate. Either:

  1. Set TS_AUTH_KEY environment variable (recommended for automation):
    export TS_AUTH_KEY="tskey-auth-xxxxx"
    
  2. Or check logs for a Tailscale login URL

After authentication, state is saved to state_dir. The auth_key can then be removed.

Environment variables
Variable Description
TS_AUTH_KEY Tailscale auth key for automated login
TSNET_FORCE_LOGIN=1 Force re-authentication even if state exists

Docker

docker run -d \
  -v ./Caddyfile:/etc/tstun/Caddyfile \
  -v tstun_state:/data/tsnet_state \
  -p 80:80 -p 443:443 \
  tstun

See docker-compose.yml for a complete example.

Notes

  • All reverse_proxy blocks share the same Tailnet node (single auth_key)
  • Standard Caddy reverse_proxy options (header_up, lb_policy, health checks, etc.) work as usual
  • The transport tsnet directive takes no arguments — all config is in the global tsnet block

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {
	// AuthKey is the tailscale authentication key.
	AuthKey string `json:"auth_key,omitempty"`
	// Hostname is the name of this node on the tailnet.
	Hostname string `json:"hostname,omitempty"`
	// StateDir is the directory where tsnet stores its state.
	StateDir string `json:"state_dir,omitempty"`
	// contains filtered or unexported fields
}

App configures the global Tailscale tsnet node for Caddy.

func (App) CaddyModule

func (App) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (*App) Cleanup

func (a *App) Cleanup() error

Cleanup implements caddy.CleanerUpper. It ensures the tsnet server is closed if provisioning of other modules fails after this module has already started its server.

func (*App) DialContext

func (a *App) DialContext(ctx context.Context, network, addr string) (net.Conn, error)

DialContext returns the DialContext function from the tsnet server.

func (*App) Provision

func (a *App) Provision(ctx caddy.Context) error

Provision sets up the tsnet server.

func (*App) Start

func (a *App) Start() error

Start implements caddy.App.

func (*App) Stop

func (a *App) Stop() error

Stop implements caddy.App.

func (*App) Validate

func (a *App) Validate() error

Validate implements caddy.Validator. It checks that required configuration fields are set.

type Transport

type Transport struct {
	// Embed the standard HTTPTransport so we inherit all its config
	// and JSON parsing behavior for standard transport options.
	*reverseproxy.HTTPTransport
}

Transport implements a custom HTTP transport for Caddy's reverse_proxy that dials out using the global tsnet App.

func (Transport) CaddyModule

func (Transport) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (*Transport) Provision

func (t *Transport) Provision(ctx caddy.Context) error

Provision sets up the transport. It gets a reference to the global tstun App and overrides the underlying http.Transport's DialContext.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

func (*Transport) UnmarshalCaddyfile

func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

UnmarshalCaddyfile sets up the transport from Caddyfile.

Directories

Path Synopsis
cmd
tstun command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL