Tailscale Services
Waypoint can register listeners as Tailscale Services using the service field. ✓ TestLoad_ServiceField internal/config/config_test.go:508 This gives each listener its own stable FQDN (e.g. waypoint-db.tailf3d5b.ts.net) that is load-balanced across all nodes hosting the service. ✓ TestIntegration_ListenService_MultiInstance internal/proxy/proxy_integration_test.go:1582
Configuration
Section titled “Configuration”Add a service field to a listener:
[tailscale]hostname = "waypoint-proxy"
[[listeners]]name = "pg-main"listen = ":5432"mode = "postgres"backend = "10.0.1.10:5432"service = "svc:waypoint-db"For the monitor’s SSH service:
[tailscale]hostname = "waypoint-mgr"
[ssh]enabled = trueservice = "svc:waypoint-ssh"Tailscale admin prerequisites
Section titled “Tailscale admin prerequisites”ListenService() advertises the node as a host for the service, but the service must be pre-configured in the Tailscale admin console. Without these steps the service will not appear or function correctly.
- Create an ACL tag (e.g.
tag:waypoint) and assign it as an owner. - Define the service in the Tailscale admin panel under Services (e.g.
svc:waypoint-dbon TCP port 5432). - Configure auto-approval so the service automatically accepts devices with the host tag.
- Define access grants allowing clients to reach the service.
- Generate an auth key tagged with the host tag and set it as
TS_AUTHKEYor in the config.
If any of these steps are missing, ListenService() may succeed at the API level but the service will not be reachable or visible in the admin panel.
DNS shadowing pitfall
Section titled “DNS shadowing pitfall”The Tailscale hostname and the service name (without svc: prefix) must not match. When they collide — e.g. hostname = "waypoint-db" and service = "svc:waypoint-db" — both resolve to the same FQDN. The machine’s DNS entry shadows the service, making the service invisible in the Tailscale admin panel.
Waypoint validates this at config load time and rejects the configuration with an error. ✓ TestValidate_ServiceHostnameCollision internal/config/config_test.go:558 Distinct hostnames pass the check. ✓ TestValidate_ServiceHostnameNoCollision internal/config/config_test.go:577 To fix it, use a different hostname:
# Bad — hostname shadows the service[tailscale]hostname = "waypoint-db" # resolves to waypoint-db.<tailnet>.ts.net
[[listeners]]service = "svc:waypoint-db" # also resolves to waypoint-db.<tailnet>.ts.net — shadowed!
# Good — distinct hostname[tailscale]hostname = "waypoint-proxy"
[[listeners]]service = "svc:waypoint-db"Constraints
Section titled “Constraints”- Service hosts must be tagged nodes. Untagged nodes receive
ErrUntaggedServiceHost. ✓TestIntegration_ListenService_UntaggedNodeFailsinternal/proxy/proxy_integration_test.go:1565 Tagged nodes register successfully. ✓TestIntegration_ListenService_TaggedNodeinternal/proxy/proxy_integration_test.go:1510 - A host must advertise all ports defined for the service. If the service is defined with ports 5432 and 3306, you need two
ListenServicecalls (two listeners with the sameservicevalue). - Requires Tailscale v1.86.0 or later.