`.local` unreachable over HTTPS for months — stale AAAA record pointing at an address the TLS listener does not serve; renaming the server fixes it

Title: .local unreachable over HTTPS for months — stale AAAA record pointing at an address the TLS listener does not serve; renaming the server fixes it


Summary

For a long time my server could not be reached at its .local address in any browser, while the LAN IPv4 address worked fine. The cause turned out to be a mismatch between the IPv6 address published for the .local name and the IPv6 address the TLS listener actually serves. The host answered ICMPv6 on the published address, so everything looked reachable — but every TLS connection was accepted and then immediately closed without a certificate being sent.

Renaming the server re-registered the address set and fixed the problem completely, IPv6 included. Posting this in case it helps others, and because the failure mode is close to invisible from the UI.

Setup

  • StartOS 0.4.0.1 (upgraded from 0.3.5.1; the problem predates the upgrade and was unaffected by it)
  • Original server name Oldest Sneezeoldest-sneeze.local; renamed to Lotter Knotenlotter-knoten.local
  • Wired connection on eno1, dual stack behind an AVM Fritz!Box
  • LAN IPv4 192.168.178.93; IPv6 prefix redacted below as 2a02:xxxx:xxxx:xxxx
  • Client: macOS, reproduced in both Safari and Chrome
  • Root CA downloaded and trusted throughout

Timeline

HTTPS access via the .local name worked for a while after initial setup, then stopped and never came back. The 0.4.0 upgrade changed nothing either way. In hindsight this fits the diagnosis exactly: at setup, published address and served address matched; at some later point the server’s IPv6 address changed and the registration did not follow.

Notably, the network prefix is identical in the old and the new address — only the interface identifier differs. So this was not an ISP prefix rotation, but a change in the host’s own address selection (the old one is an EUI-64 address derived from the MAC, the new one is a randomly generated address).

Symptoms

  • http://oldest-sneeze.local → worked, loaded the “Trust your Root CA” page
  • https://oldest-sneeze.local → Chrome: ERR_CONNECTION_CLOSED; Safari: “cannot open the page”
  • https://192.168.178.93 → worked
  • ping and ping6 against oldest-sneeze.local both succeeded

The last point is what made this hard to diagnose: the published IPv6 address responds to pings, so name resolution and reachability both appear healthy.

Evidence — before the rename

Same command, only the address family differs.

IPv4 — full handshake, valid chain:

$ openssl s_client -4 -connect oldest-sneeze.local:443 -servername oldest-sneeze.local \
    -sigalgs "ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256" </dev/null 2>&1 | head -12
Connecting to 192.168.178.93
depth=2 CN=oldest-sneeze Local Root CA, O=Start9, OU=StartOS
verify return:1
depth=1 CN=StartOS Local Intermediate CA, O=Start9, OU=StartOS
verify return:1
depth=0 CN=oldest-sneeze.local, O=Start9, OU=StartOS
verify return:1
CONNECTED(00000005)

IPv6 — connection accepted, then closed, no certificate:

$ openssl s_client -6 -connect oldest-sneeze.local:443 -servername oldest-sneeze.local </dev/null 2>&1 | head -12
Connecting to 2a02:xxxx:xxxx:xxxx:abf:b8ff:feee:cc13
80A157F401000000:error:0A000126:SSL routines::unexpected eof while reading:ssl/record/rec_layer_s3.c:703:
CONNECTED(00000005)
---
no peer certificate available
---
No client certificate CA names sent
Negotiated TLS1.3 group: <NULL>
---
SSL handshake has read 0 bytes and written 1557 bytes

Because mDNS publishes both an A and an AAAA record, and browsers prefer IPv6, every browser landed on the address that fails.

The fallback certificate served without SNI listed no IPv6 address at all:

$ openssl s_client -connect 192.168.178.93:443 </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN=localhost, O=Start9, OU=StartOS
X509v3 Subject Alternative Name:
    IP Address:<public IPv4>, IP Address:192.168.178.93

Corresponding server log entries while a browser was connecting:

DEBUG start_core::net::tls: no certificate for SNI Some("oldest-sneeze.local")
DEBUG start_core::net::tls: no certificate for SNI None

Evidence — after the rename

Renaming the server (System → Server Name) resolved it. The same IPv6 test now completes:

$ openssl s_client -6 -connect lotter-knoten.local:443 -servername lotter-knoten.local </dev/null 2>&1 | head -8
Connecting to 2a02:xxxx:xxxx:xxxx:3f1c:8c94:e03c:12bb
depth=2 CN=oldest-sneeze Local Root CA, O=Start9, OU=StartOS
verify return:1
depth=1 CN=StartOS Local Intermediate CA, O=Start9, OU=StartOS
verify return:1
depth=0 CN=lotter-knoten.local, O=Start9, OU=StartOS
verify return:1
CONNECTED(00000005)

The published IPv6 address is now a different one, and this one is served. Both browsers work immediately.

(Side note: the Root CA retains its original CN from initial setup after a rename, which is expected but briefly confusing when you re-download it.)

Diagnosis

The server holds several IPv6 addresses simultaneously. mDNS published one of them in the AAAA record for the .local name, while the TLS listener served a different one. Connections to the published address reached the host — hence the successful pings — but were dropped at the TLS layer. Renaming the server rebuilt the registration and brought the two back into alignment.

Questions / suggestions

  1. Should the mDNS registration follow the server’s current address set when an interface address changes, rather than persisting an address that is no longer served?
  2. Is there a supported way to force re-registration without renaming the server? Renaming works but changes the .local address, which is disruptive if it is in use elsewhere.
  3. If the server registers a temporary or privacy IPv6 address, is there anything that keeps the registration in sync when that address rotates? Otherwise the same breakage seems likely to recur.
  4. Would it be feasible to surface a warning in the UI when the published address for the .local name is not among the addresses the TLS listener serves? That single check would have saved a lot of guesswork here.

This is likely to affect any dual-stack user whose server’s IPv6 address has changed since initial setup, and it presents as the very generic “.local doesn’t work for me” — which is probably why it is easy to dismiss as an mDNS or certificate-trust issue. Happy to provide further logs or run additional tests.

https://oldest-sneeze.local → Chrome: ERR_CONNECTION_CLOSED; Safari: “cannot open the page”

As for this^ issue, you might need to explicitly tell macOS to allow your browser to make connections to .local names: Control access to your local network on Mac - Apple Support

System Settings > Privacy & Security > Local Network

Also, Brave Browser, has special needs:

System Settings > Privacy & Security > Local Network > “Brave Browser Helper” also enabled along with “Brave Browser”

So that may apply to chrome too.

Thank you. For Google Chrome, the option is enabled. For Safari, the option is not listed. As far as I know, Safari uses system services and does not need extra approval.

I had the problem with both Safari and Chrome. I hadn’t tried Brave.