feat(tunnel): multi-hostname support, headless cert reuse, and tunnel delete#670
Open
bussyjd wants to merge 1 commit into
Open
feat(tunnel): multi-hostname support, headless cert reuse, and tunnel delete#670bussyjd wants to merge 1 commit into
bussyjd wants to merge 1 commit into
Conversation
… delete
Align the tunnel CLI with the new least-privilege Cloudflare auth (connector
token / dashboard-managed; no account-wide API token) and round out the tunnel
lifecycle: setup -> hostname add/remove -> delete.
tunnel hostname {add,list,remove}: serve N public hostnames on one tunnel.
Local-managed (cert) routes the DNS CNAME, re-renders the connector ingress over
all hostnames, and reloads the connector; dashboard-managed tracks state, updates
the storefront route, and prints the dashboard step. Adding a second hostname
never disrupts the first. tunnelState gains an ordered Hostnames slice
(primary = Hostnames[0]) with legacy single-hostname migration; CreateStorefront
publishes over the full set; buildLocalManagedConfigYAML emits one ingress rule
per hostname.
tunnel login --reuse-cert: skip the browser and reuse an existing
~/.cloudflared/cert.pem to provision additional clusters headlessly. Errors when
no usable cert is present, so the headless contract is explicit; the default
still does a fresh browser login.
tunnel delete (alias teardown): full teardown completing the lifecycle. Deletes
the Cloudflare tunnel where Obol holds the credential (local cert-scoped
'cloudflared tunnel delete'), cleans in-cluster connector resources + storefront
+ state, reverts the connector to a default quick tunnel, and prints the
dashboard/DNS steps it cannot do without a broad token. --force + confirm-on-TTY,
matching 'agent delete'; 'stop' usage clarified as pause-vs-delete.
No account-wide Cloudflare API token is used anywhere in the feature; DNS records
and dashboard-managed tunnels are left to the operator with explicit instructions.
Tests: 25 tunnel unit tests (state migration, listing, multi-hostname/dedup
render, add/remove/delete guards). Local-managed multi-hostname validated live
(two domains served simultaneously through the x402 gate, removed without
disrupting the first).
Claude-Session: https://claude.ai/code/session_01YUTW7NfxjUoVtyKgR6nPQC
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
Rounds out the tunnel CLI on top of the new least-privilege Cloudflare auth (connector token / dashboard-managed; no account-wide API token), completing the lifecycle
setup → hostname add/remove → delete. No account-wide Cloudflare API token is used anywhere in this change.What's in it
tunnel hostname {add,list,remove}— N public hostnames per tunnel"Deploy one domain, then another." Offer HTTPRoutes are host-agnostic, so every hostname serves the same x402-gated surface and adding a second never takes down the first.
cloudflared(cert-scoped), re-renders the connector ingress over all hostnames, and reloads the connector (a ConfigMap-only change doesn't roll the pods, so the connector would otherwise keep its old ingress).tunnelStategains an orderedHostnamesslice (primary =Hostnames[0]) with legacy single-hostname migration;CreateStorefrontpublishes over the full set;buildLocalManagedConfigYAMLemits one ingress rule per hostname.tunnel login --reuse-cert— headless provisioningSkip the browser and reuse an existing
~/.cloudflared/cert.pemto stand up additional clusters on the same Cloudflare account without a browser. Errors when no usable cert is present (explicit headless contract); the default still does a fresh browser login.tunnel delete(aliasteardown) — full teardownThe destructive counterpart to
tunnel stop(which only pauses). Deletes the Cloudflare tunnel where Obol holds the credential (local cert-scopedcloudflared tunnel delete), cleans in-cluster connector resources + storefront + state, reverts the connector to a default quick tunnel, and prints the dashboard/DNS steps it can't do without a broad token.--force+ confirm-on-TTY (matchesagent delete);stop's usage clarified as pause-vs-delete.Relation to #668
Orthogonal substrate: this makes N hostnames live (all offers on all hosts); #668 is the inverse (bind one offer to a dedicated host).
buildHTTPRouteis untouched, so #668 stays a clean follow-up.Testing
go build ./...,go vet, and the suite are green.*.v1337.orghostname alongside a live tunnel → both served200/402simultaneously → removed it → the first was never disrupted.tunnel deleteis unit-tested + build-verified but not run end-to-end live: the only available cluster fronts a production tunnel, and the real teardown would destroy it. Wiring confirmed viatunnel delete --help.Notes
https://claude.ai/code/session_01YUTW7NfxjUoVtyKgR6nPQC