Skip to content

Cockpit: per-project Cloudflare exposure — cockpit-expose skill (named tunnel, Access-gated DNS, loop-scoped unit) #143

Description

@robercano-ghbot

Blocked by #142

Context

With the cockpit loop-managed (#142), consumer projects need a self-serve way to expose it from the host machine to the internet, protected by Cloudflare Access. Requirement: independent per project — each consumer repo (reDeploy, reDeFi, …) gets its own named tunnel, credentials, config, and unit, so projects can be onboarded and torn down without touching each other. No shared machine-level ingress file, and nothing user-specific (domain, hostname, port) baked into plugin code.

Reference implementation to generalize: reDeploy's always-on studio tunnel (deploy/always-on/ + docs/ALWAYS-ON-TUNNEL.md in that repo) — named tunnel, per-tunnel config yml passed via --config (avoids the default-config.yaml wrong-tunnel hazard), systemd user unit, Access configured per hostname.

Security constraint (drives the workflow ordering): the cockpit has no authentication and its worker-inspector/SSE routes expose repo and git forensics. Cloudflare Access is the only gate, so DNS must never be routed before the Access application exists.

Proposal

  1. Extend the gates.json cockpit block with expose: { hostname, tunnelName } (default: absent).
  2. New cockpit-expose skill/script that, idempotently:
    • checks cloudflared is installed and ~/.cloudflared/cert.pem exists (else instructs cloudflared tunnel login);
    • creates the per-project named tunnel (default name <project>-cockpit);
    • writes ~/.cloudflared/<project>-cockpit.yml with a single ingress rule hostname → http://localhost:<cockpit.port> plus the required http_status:404 catch-all;
    • gates the DNS step on Access: walks the user through creating the Access self-hosted app in the Zero Trust dashboard and requires confirmation — or creates it via the API when a CLOUDFLARE_API_TOKEN with Access:Apps edit scope is provided — before running cloudflared tunnel route dns --overwrite-dns <tunnel-uuid> <hostname>;
    • wires the per-project cloudflared unit loop-scoped by default (started on arm / stopped on halt alongside the cockpit unit, addressing the tunnel by UUID and explicit --config), with an always-on systemd option;
    • provides a matching teardown path (unit, DNS route, tunnel, config).
  3. Offer the skill from /orchestrator:setup when the user opts into cockpit exposure.

Acceptance criteria

  • Running the skill in a consumer repo with a Cloudflare-managed zone yields a working https://<hostname> cockpit behind Access, up while the loop is armed.
  • DNS is provably never routed before the Access app is confirmed/created.
  • Two projects on one machine expose independently: separate tunnels, configs, units; tearing one down leaves the other running.
  • Re-running the skill is a no-op on an already-exposed project; teardown removes everything it created.
  • Repos without expose config (or without Cloudflare) are completely unaffected.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    backlogFiled, not yet approved by the owner - the loop must NOT pick it upenhancementNew feature or requestmodule:harnessOrchestrator machinery under .claudepriority:highNext in line

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions