feat: TLS (HTTPS) for tunnel public ports with cert hot-reload (1.28.0)#74
Merged
Conversation
Add opt-in TLS termination on tunnel public ports. A tunnel opened with `secure: true` (CLI `--secure`) has the Hub terminate TLS on the public port; the Hub->exposer->target hops stay plaintext. Each accepted connection is upgraded via `SecureSocket.secureServer`, leaving the existing bind/port-range allocation and bridge untouched. The Hub certificate is configured with `hub start --tunnel-tls-dir <dir>` (a directory holding fullchain.pem + privkey.pem, LetsEncrypt layout) matching `--tunnel-public-host`. A new `TunnelTlsSource` re-checks the files every 12h and reloads the TLS context automatically when they change, so renewals are picked up without a restart; a renewal caught mid-write is skipped, keeping the previous cert in service. Requesting `--secure` when no cert is configured fails with `secure_unavailable`. Tunnels remain plain TCP by default; `--tunnel-tls-dir` is also carried through `service install`/`reconfigure`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The unit test sourced a second certificate from certs/server.{crt,key},
but /certs/ is gitignored (only test/support/certs/localhost.* is
committed), so the test failed in a clean checkout with "missing test
certificate". Rework it to use only the committed localhost pair: the
"renewal" case rewrites fullchain.pem with a leading comment so the bytes
differ while staying a valid, parseable PEM.
Also document --secure in the interactive :tunnel command usage/help.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump to the latest major releases (checkout v7.0.0, codecov-action v7.0.0). dart-lang/setup-dart stays at v1 (latest release is v1.7.2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds opt-in TLS termination on tunnel public ports so external clients can speak HTTPS to a tunnel (e.g.
https://sites.menuici.com:20010). TLS terminates at the Hub's public port; the Hub→exposer→target hops stay plaintext, unchanged. Tunnels remain plain TCP by default.How it works
omnyshell tunnel open <node> <port> --secure(also the interactive:tunnel --secure, orClientRuntime.openTunnel(secure: true)). Each accepted connection is upgraded viaSecureSocket.secureServer, so the existing bind / port-range allocation and the byte-bridge are untouched.omnyshell hub start --tunnel-tls-dir <dir>— a directory holdingfullchain.pem+privkey.pem(LetsEncrypt layout) that should match--tunnel-public-host.TunnelTlsSourcere-checks the files every 12h and rebuilds the TLS context automatically when they change, so renewals are picked up without a Hub restart. A renewal caught mid-write (invalid/partial files) is skipped, keeping the previous certificate in service.--secureagainst a Hub with no certificate configured is rejected withsecure_unavailable.--tunnel-tls-diris carried throughservice install/reconfigure.Key changes
secureflag onTunnelOpenRequest/TunnelOpened/TunnelInfo(defaults false → backward compatible).HubBroker: validatessecurerequests and upgrades accepted connections;tunnelSecurityContextis now mutable for reloads.OmnyShellHub/HubConfig:tunnelTlsDirectory+tunnelTlsReloadIntervalmanage aTunnelTlsSourceacross start/stop.--secure(tunnel open) and--tunnel-tls-dir(hub start); CLI printshttps://andtunnel listshows the scheme.Testing
dart format/dart analyze: clean.dart test: 448 passed.secure_unavailablenegative test;TunnelTlsSourceunit tests (load, no-op, renewal reload, invalid-mid-write keeps old context).Note
Certificate files must be readable on the Hub host (TLS terminates there). The cert's SAN is not validated against
--tunnel-public-host— the admin supplies a cert for that host.🤖 Generated with Claude Code