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 Sneeze→oldest-sneeze.local; renamed toLotter Knoten→lotter-knoten.local - Wired connection on
eno1, dual stack behind an AVM Fritz!Box - LAN IPv4
192.168.178.93; IPv6 prefix redacted below as2a02: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” pagehttps://oldest-sneeze.local→ Chrome:ERR_CONNECTION_CLOSED; Safari: “cannot open the page”https://192.168.178.93→ workedpingandping6againstoldest-sneeze.localboth 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
- 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?
- Is there a supported way to force re-registration without renaming the server? Renaming works but changes the
.localaddress, which is disruptive if it is in use elsewhere. - 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.
- Would it be feasible to surface a warning in the UI when the published address for the
.localname 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.