diff --git a/app.go b/app.go index 9f8ec4b..09478a6 100644 --- a/app.go +++ b/app.go @@ -44,6 +44,9 @@ type App struct { // Tags to apply to all nodes when registered. Tags []string `json:"tags,omitempty" caddy:"namespace=tailscale.tags"` + // Port specifies the default UDP port for tsnet. When unset (0), tsnet will pick a random available port. + Port uint16 `json:"port,omitempty" caddy:"namespace=tailscale.port"` + // Nodes is a map of per-node configuration which overrides global options. Nodes map[string]Node `json:"nodes,omitempty" caddy:"namespace=tailscale"` @@ -150,6 +153,16 @@ func parseAppConfig(d *caddyfile.Dispenser, _ any) (any, error) { } case "tags": app.Tags = d.RemainingArgs() + case "port": + if d.NextArg() { + v, err := strconv.ParseUint(d.Val(), 10, 16) + if err != nil { + return nil, d.WrapErr(err) + } + app.Port = uint16(v) + } else { + app.Port = 0 + } default: node, err := parseNodeConfig(d) if app.Nodes == nil { diff --git a/module.go b/module.go index a9b42d0..615850f 100644 --- a/module.go +++ b/module.go @@ -66,6 +66,11 @@ func getTCPListener(c context.Context, network string, host string, portRange st network = "tcp" } + // If host is empty (bind tailscale/), use default node name from binary name + if host == "" { + host = getDefaultNodeName() + } + // Get node reference for this listener (increments node reference count) node, err := getNode(ctx, host) if err != nil { @@ -117,6 +122,11 @@ func getTLSListener(c context.Context, network string, host string, portRange st network = "tcp" } + // If host is empty (bind tailscale/), use default node name from binary name + if host == "" { + host = getDefaultNodeName() + } + // Get node reference for this listener (increments node reference count) node, err := getNode(ctx, host) if err != nil { @@ -173,6 +183,11 @@ func getUDPListener(c context.Context, network string, host string, portRange st network = "udp" } + // If host is empty (bind tailscale/), use default node name from binary name + if host == "" { + host = getDefaultNodeName() + } + // Get node reference for this listener (increments node reference count) node, err := getNode(ctx, host) if err != nil { @@ -252,6 +267,12 @@ var nodes = caddy.NewUsagePool() // This ensures listeners are properly closed when removed from configuration. var tailscaleListeners = caddy.NewUsagePool() +// getDefaultNodeName returns the default node name when none is specified. +// It uses the binary name (without path) as the default. +func getDefaultNodeName() string { + return filepath.Base(os.Args[0]) +} + // getNode returns a tailscale node for Caddy apps to interface with. // // The specified name will be used to lookup the node configuration from the tailscale caddy app, @@ -366,7 +387,7 @@ func getPort(name string, app *App) uint16 { return node.Port } - return 0 + return app.Port } func getStateDir(name string, app *App) (string, error) {