Simplify SSL Certificates Handling for Tailscale's serve Command by Replacing Dot with Dash in Machine.GetFQDN #543

Closed
opened 2025-12-29 02:19:43 +01:00 by adam · 3 comments
Owner

Originally created by @marcellmars on GitHub (Aug 18, 2023).

Why

The Tailscale serve command starts a server that only respond to its specific FQDN (e.g. not its IP address), and that's set up in headscale's codebase as Machine.GivenName + dot + Machine.User.Name. Because of that dot between Machine.GivenName and Machine.User.Name, you'd need an extra wildcard SSL certificate for each User.Name (to cover all of her nodes) if you want to make it accessible to everyone online.

But if we used a dash instead of the dot, it would simplify things. It would just count as one subdomain, so a single wildcard SSL certificate could cover all users in the tailnet.

To test if I am right I came up with a simple patch for this. It makes the server return Machine.GivenName + - + Machine.User.Name. If you get a wildcard SSL certificate from Caddy and set up a reverse proxy to the node running tailscale serve http:1234 / text:"hello world!", it works perfectly. Anyone online would see "hello world!" at the same URL used in the tailnet, and the wildcard SSL certificate would have it covered.

Description

Here's the simple patch which does it:

modified   hscontrol/types/machine.go
@@ -269,7 +269,7 @@ func (machine *Machine) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string)
 	var hostname string
 	if dnsConfig != nil && dnsConfig.Proxied { // MagicDNS
 		hostname = fmt.Sprintf(
-			"%s.%s.%s",
+			"%s-%s.%s",
 			machine.GivenName,
 			machine.User.Name,
 			baseDomain,

With this setup, a single generic Caddy snippet can handle all users. Without it, you'd have to add every new user to Caddy individually. That would be way more work to keep up with.

I wonder if there's any interest in having something like this as part of the configuration directive. I am happy to discuss it more and eventually make a PR.

Originally created by @marcellmars on GitHub (Aug 18, 2023). ## Why The Tailscale `serve` command starts a server that only respond to its specific FQDN (e.g. not its IP address), and that's set up in headscale's codebase as `Machine.GivenName` + `dot` + `Machine.User.Name`. Because of that dot between `Machine.GivenName` and `Machine.User.Name`, you'd need an extra wildcard SSL certificate for each `User.Name` (to cover all of her nodes) if you want to make it accessible to everyone online. But if we used a dash instead of the dot, it would simplify things. It would just count as one subdomain, so a single wildcard SSL certificate could cover all users in the tailnet. To test if I am right I came up with a simple patch for this. It makes the server return `Machine.GivenName` + `-` + `Machine.User.Name`. If you get a wildcard SSL certificate from Caddy and set up a reverse proxy to the node running `tailscale serve http:1234 / text:"hello world!"`, it works perfectly. Anyone online would see "hello world!" at the same URL used in the tailnet, and the wildcard SSL certificate would have it covered. ## Description Here's the simple patch which does it: ```diff modified hscontrol/types/machine.go @@ -269,7 +269,7 @@ func (machine *Machine) GetFQDN(dnsConfig *tailcfg.DNSConfig, baseDomain string) var hostname string if dnsConfig != nil && dnsConfig.Proxied { // MagicDNS hostname = fmt.Sprintf( - "%s.%s.%s", + "%s-%s.%s", machine.GivenName, machine.User.Name, baseDomain, ``` With this setup, a single generic Caddy snippet can handle all users. Without it, you'd have to add every new user to Caddy individually. That would be way more work to keep up with. I wonder if there's any interest in having something like this as part of the configuration directive. I am happy to discuss it more and eventually make a PR.
adam added the enhancementstale labels 2025-12-29 02:19:43 +01:00
adam closed this issue 2025-12-29 02:19:43 +01:00
Author
Owner

@ChibangLW commented on GitHub (Aug 21, 2023):

Not necessary based on the same motivation but would also result in the same functionality for you (for tagged devices at least): #1405

From my understanding the given name should be unique by appending a suffix if two machines do have the same given name.

@ChibangLW commented on GitHub (Aug 21, 2023): Not necessary based on the same motivation but would also result in the same functionality for you (for tagged devices at least): #1405 From my understanding the given name should be unique by appending a suffix if two machines do have the same given name.
Author
Owner

@github-actions[bot] commented on GitHub (Dec 11, 2023):

This issue is stale because it has been open for 90 days with no activity.

@github-actions[bot] commented on GitHub (Dec 11, 2023): This issue is stale because it has been open for 90 days with no activity.
Author
Owner

@github-actions[bot] commented on GitHub (Dec 19, 2023):

This issue was closed because it has been inactive for 14 days since being marked as stale.

@github-actions[bot] commented on GitHub (Dec 19, 2023): This issue was closed because it has been inactive for 14 days since being marked as stale.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#543