feat(settings): derive the HTTPS URL from the Target Domain, show + override in UI (#355)

The HTTPS URL AfterTouch advertises (and points speakers at for the
DNS-redirect, OAuth, install-ca and cert-trust flows) was a separate,
internally-tracked value: sourced only from --https-server-url /
HTTPS_SERVER_URL / the settings file, defaulting to the machine hostname,
and never shown or editable in the web UI. So it could silently diverge
from the Target Domain (e.g. a different host, or a port-less value that
fell back to 443 while the listener was on 8443 — the root of #355), with
no way to see or fix it in the UI.

Make it derive + show + override:

- DeriveHTTPSURL resolves the effective HTTPS URL: an explicit override
  wins; otherwise it follows the Target Domain (same host, https, on the
  configured HTTPS port); an already-https Target Domain is honoured
  verbatim (its port is not second-guessed); empty falls back to the
  hostname default. So changing the Target Domain updates the HTTPS URL
  automatically for the common single-host case.
- The persisted https_server_url is now the *override* (empty = derive).
  Existing installs carry their old value here, so it is preserved as an
  override — no silent change on upgrade; clearing it opts into derive.
- The server keeps httpsServerURL as the effective value, so all
  consumers (cert SANs, migration, export, health) are unchanged; it is
  recomputed whenever the Target Domain or override changes.
- Settings API returns https_server_url (effective) plus
  https_server_url_override; the Settings page shows the effective URL
  with a derived/override note and an "advanced" override field.

Verified live on a clean data dir: derive from an http Target Domain,
auto-follow when the Target Domain changes, explicit override, an https
Target Domain kept verbatim, and override persistence across restart.
Unit tests cover DeriveHTTPSURL including the already-https cases.

refs #355

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tobias Gesellchen
2026-07-04 17:45:41 +02:00
co-authored by Claude Opus 4.8
parent 433a779998
commit b1b3472297
7 changed files with 208 additions and 36 deletions
+22 -10
View File
@@ -518,8 +518,8 @@ func main() {
server := handlers.NewServer(ds, sm, config.serverURL, config.redact, config.logBody, config.record)
sm.GetDNSRunning = server.GetDNSRunning
server.SetLogBuffer(logBuf)
server.SetHTTPServerURL(config.httpsServerURL)
server.SetHTTPSListenAddr(config.httpsAddr)
server.SetHTTPSSettings(config.httpsOverride, config.httpsPort, config.httpsDefaultURL)
server.SetExpectedHosts(config.domains)
server.SetVersionInfo(version, commit, date, repoURL)
server.SetDiscoverySettings(config.discoveryInterval, config.discoveryEnabled)
@@ -683,7 +683,10 @@ type serviceConfig struct {
dataDir string
hostname string
serverURL string
httpsServerURL string
httpsServerURL string // effective (derived or overridden)
httpsOverride string // explicit override; "" = derive from serverURL
httpsPort string
httpsDefaultURL string // hostname-based fallback
httpsAddr string
redact bool
logBody bool
@@ -756,10 +759,13 @@ func loadConfig(c *cli.Context) serviceConfig {
httpsAddr = ":" + httpsPort
}
httpsServerURL := c.String("https-server-url")
if httpsServerURL == "" {
httpsServerURL = "https://" + hostname + ":" + httpsPort
}
// The HTTPS URL is an override (from the flag/env); when empty it is
// derived from serverURL + https port so one setting (Target Domain)
// drives both. httpsDefaultURL is the hostname-based fallback used
// before a Target Domain is configured.
httpsOverride := c.String("https-server-url")
httpsDefaultURL := "https://" + hostname + ":" + httpsPort
httpsServerURL := handlers.DeriveHTTPSURL(serverURL, httpsOverride, httpsPort, httpsDefaultURL)
tlsExtraHosts := c.StringSlice("tls-extra-host")
domains := getDomains(serverURL, httpsServerURL, hostname, tlsExtraHosts)
@@ -817,6 +823,9 @@ func loadConfig(c *cli.Context) serviceConfig {
hostname: hostname,
serverURL: serverURL,
httpsServerURL: httpsServerURL,
httpsOverride: httpsOverride,
httpsPort: httpsPort,
httpsDefaultURL: httpsDefaultURL,
httpsAddr: httpsAddr,
redact: redact,
logBody: logBody,
@@ -954,9 +963,12 @@ func applyPersistedSettings(ds *datastore.DataStore, config *serviceConfig) data
config.serverURL = handlers.NormalizeServerURL(persisted.ServerURL)
}
if persisted.HTTPServerURL != "" {
config.httpsServerURL = persisted.HTTPServerURL
}
// persisted.HTTPServerURL is the HTTPS override (empty = derive).
// Existing installs carry their old effective value here, so it is
// preserved as an override; recompute the effective URL either way,
// since serverURL may have come from the persisted settings above.
config.httpsOverride = persisted.HTTPServerURL
config.httpsServerURL = handlers.DeriveHTTPSURL(config.serverURL, config.httpsOverride, config.httpsPort, config.httpsDefaultURL)
config.discoveryEnabled = persisted.DiscoveryEnabled
if persisted.DiscoveryInterval != "" {
@@ -1076,7 +1088,7 @@ func applyPersistedMusicServiceCredentials(config *serviceConfig, persisted data
func createDefaultSettings(ds *datastore.DataStore, config serviceConfig) datastore.Settings {
settings := datastore.Settings{
ServerURL: config.serverURL,
HTTPServerURL: config.httpsServerURL,
HTTPServerURL: config.httpsOverride,
RedactLogs: config.redact,
LogBodies: config.logBody,
RecordInteractions: config.record,