Two follow-ups to the WebTransport/ALPN-mux landing:
Deployment templates publish UDP alongside TCP for the relay so the
single ALPN-multiplexed socket can serve raw QUIC and WebTransport
clients on the same port as the existing WebSocket transport.
- docker-compose.yml.tmpl: adds the matching `/udp` mapping; the relay
was already binding both stacks, the host port just wasn't published.
- docker-compose.yml.tmpl.traefik: WebTransport is the awkward case —
Traefik can't proxy WT sessions, so the relay container now publishes
UDP/443 directly and obtains its own Let's Encrypt cert (separate
volume), while the TCP /relay route stays behind Traefik unchanged so
WS-only clients keep working.
Management server learned to advertise per-relay transport hints:
- Config gains an optional `Endpoints []{URL, Transports}` block on the
Relay section, mirrored to clients as RelayConfig.endpoints.
- `Addresses` is still emitted as RelayConfig.urls so older agents keep
working unchanged.
- A single BuildRelayConfigProto helper is the only place that builds
the proto, called from both toNetbirdConfig and the token push paths.
The GeoDNS case is operator-asserted, not probed: a single URL fans out
to several physical relays, and the Transports list must already be the
intersection of what every backend supports. Documented on the config
struct — if any backend behind a hostname can't speak h3, the operator
drops "wt" from that hostname's list and no client tries it there.
Auto-update logic moved out of the UI into a dedicated updatemanager.Manager service that runs in the connection layer. The
UI no longer polls or checks for updates independently.
The update manager supports three modes driven by the management server's auto-update policy:
No policy set by mgm: checks GitHub for the latest version and notifies the user (previous behavior, now centralized)
mgm enforces update: the "About" menu triggers installation directly instead of just downloading the file — user still initiates the action
mgm forces update: installation proceeds automatically without user interaction
updateManager lifecycle is now owned by daemon, giving the daemon server direct control via a new TriggerUpdate RPC
Introduces EngineServices struct to group external service dependencies passed to NewEngine, reducing its argument count from 11 to 4
* **New Features**
* SSH server JWT validation now accepts multiple audiences with backward-compatible handling of the previous single-audience setting and a guard ensuring at least one audience is configured.
* **Tests**
* Test suites updated and new tests added to cover multiple-audience scenarios and compatibility with existing behavior.
* **Other**
* Startup logging enhanced to report configured audiences for JWT auth.