From 68760a89776c30a0a3a8573ba37d415e713651fa Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Mon, 18 May 2026 23:04:44 +0200 Subject: [PATCH] feat(service): add --tls-extra-host for additional TLS cert SAN entries The leaf cert generator already routes IP-shaped entries into the IPAddresses SAN, and getDomains already feeds it the hostnames parsed from --server-url and --https-server-url. Add an explicit --tls-extra-host flag (repeatable, env TLS_EXTRA_HOST) for the remaining cases: multi-homed hosts, reverse-proxy frontends, or browsing the admin UI via a LAN IP that isn't part of the configured server URLs. Resolves the ERR_CERT_COMMON_NAME_INVALID Chrome refuses when the URL bar hostname (e.g. the host's LAN IP) isn't in any cert SAN, even when the local CA is trusted. --- cmd/soundtouch-service/main.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/cmd/soundtouch-service/main.go b/cmd/soundtouch-service/main.go index a97852f..2cbf3e3 100644 --- a/cmd/soundtouch-service/main.go +++ b/cmd/soundtouch-service/main.go @@ -342,6 +342,11 @@ func main() { Usage: "Paths for internal requests (comma-separated or multiple flags)", EnvVars: []string{"INTERNAL_PATHS"}, }, + &cli.StringSliceFlag{ + Name: "tls-extra-host", + Usage: "Additional DNS name or IP to include in the server TLS certificate SAN list (repeatable)", + EnvVars: []string{"TLS_EXTRA_HOST"}, + }, &cli.BoolFlag{ Name: "migration-enabled", Usage: "Enable device directory migration from serial to MAC-based structure", @@ -382,7 +387,7 @@ func main() { hostname = "localhost" } - config.domains = getDomains(config.serverURL, config.httpsServerURL, hostname) + config.domains = getDomains(config.serverURL, config.httpsServerURL, hostname, config.tlsExtraHosts) cm := initCertificateManager(config.dataDir, config.hostname) sm := setup.NewManager(config.serverURL, ds, cm) @@ -534,6 +539,7 @@ type serviceConfig struct { dnsUpstream string dnsBind string internalPaths []string + tlsExtraHosts []string discoveryEnabled bool discoveryInterval time.Duration domains []string @@ -590,7 +596,8 @@ func loadConfig(c *cli.Context) serviceConfig { httpsServerURL = "https://" + hostname + ":" + httpsPort } - domains := getDomains(serverURL, httpsServerURL, hostname) + tlsExtraHosts := c.StringSlice("tls-extra-host") + domains := getDomains(serverURL, httpsServerURL, hostname, tlsExtraHosts) redact := c.Bool("redact-logs") logBody := c.Bool("log-bodies") @@ -644,6 +651,7 @@ func loadConfig(c *cli.Context) serviceConfig { dnsUpstream: dnsUpstream, dnsBind: dnsBind, internalPaths: internalPaths, + tlsExtraHosts: tlsExtraHosts, discoveryEnabled: discoveryEnabled, discoveryInterval: discoveryInterval, domains: domains, @@ -666,7 +674,7 @@ func loadConfig(c *cli.Context) serviceConfig { } } -func getDomains(serverURL, httpsServerURL, hostname string) []string { +func getDomains(serverURL, httpsServerURL, hostname string, extraHosts []string) []string { domainsMap := map[string]bool{ // RFC-compliant wildcards for API patterns "*.api.bose.io": true, @@ -699,6 +707,15 @@ func getDomains(serverURL, httpsServerURL, hostname string) []string { domainsMap[strings.ToLower(u.Hostname())] = true } + // Explicit overrides / additions for multi-homed hosts, reverse proxies, + // or browsing the admin UI via a LAN IP that isn't part of serverURL. + for _, h := range extraHosts { + h = strings.ToLower(strings.TrimSpace(h)) + if h != "" { + domainsMap[h] = true + } + } + domains := make([]string, 0, len(domainsMap)) for d := range domainsMap { domains = append(domains, d)