universe docs source
browse docs
docs /extensions /tailscale

Tailscale

The Tailscale extension implements TemplateVariableProvider and exposes a node's mesh-network addresses as template variables. Instances pick up stable per-node addresses at deploy time without depending on public IPs.

Nodes spread across data centers or behind NAT rarely have stable, routable addresses for each other. Tailscale gives every node a fixed address on a private tailnet. This extension reads those addresses on the local node and exposes them as %TAILSCALE_*% template variables, so an instance’s config files can reference the mesh address of the node they run on without any hard-coded IPs.

Injected variables

The extension provides these variables during template variable replacement:

VariableExampleMeaning
%TAILSCALE_IP%100.64.1.1IPv4 address on the tailnet.
%TAILSCALE_IP6%fd7a:115c:a1e0::1IPv6 address on the tailnet.
%TAILSCALE_HOSTNAME%my-serverMachine hostname as seen in Tailscale.
%TAILSCALE_MAGIC_DNS%my-server.tail12345.ts.netFull MagicDNS FQDN for the node.
%TAILSCALE_ADDRESS%100.64.1.1Alias for %TAILSCALE_IP%.

Reference them in any file listed under a configuration’s fileModifications:

server-ip=%TAILSCALE_IP%
advertised-host=%TAILSCALE_MAGIC_DNS%

Configuration

Place extension-tailscale.jar in ./extensions/ and create ./extensions/tailscale/config.json:

{
	"binaryPath": "tailscale",
	"timeoutMs": 5000,
	"warnIfUnavailable": true,
	"socketPath": "/var/run/tailscale/tailscaled.sock"
}
FieldDefaultPurpose
binaryPath"tailscale"Path to the Tailscale binary.
timeoutMs5000CLI response timeout in milliseconds.
warnIfUnavailabletrueLog a startup warning when Tailscale cannot be reached.
socketPathnullDaemon socket path, useful inside Docker.

How it resolves addresses

On load, the extension runs tailscale status --json, parses the response, and caches the result for 30 seconds before refreshing. Each deploy reads from that cache, so resolution adds no per-instance CLI cost during a burst of deployments.

Running inside Docker

When Universe runs in a container, mount both the binary and the daemon socket so the extension can query the host’s Tailscale state:

volumes:
  - /usr/bin/tailscale:/usr/bin/tailscale:ro
  - /var/run/tailscale:/var/run/tailscale

Confirm connectivity from inside the container:

docker exec <container> tailscale status
i
note

If Tailscale is unavailable, every %TAILSCALE_*% variable resolves to an empty string and hostAddress falls back to its literal value. Deploys are not blocked by a missing tailnet.