Domain Wizard
Phase С.2 of the GA roadmap: paste a Cloudflare API token, and 30 seconds later your apps live at *.example.com with a green padlock. The wizard collapses “DNS provider → A records → ACME → Caddy reload” into a single screen.
Walkthrough
- Open Settings → Networking → Domain wizard (or browse to
/setup/domain). - Provider — Cloudflare is the first shipped adapter. Route53 / Google Cloud DNS / ACME-DNS land in С.2.b.
- Token — paste your Cloudflare API token. (In Cloudflare: My Profile → API Tokens → Create Token → Edit zone DNS scoped to the relevant zones.)
- Zone & target — pick your zone (
example.com). The NAT card shows the public IP and NAT type (Open / FullCone / Restricted / Symmetric) detected via STUN againststun.cloudflare.com:3478. Ifnat_type=open, single CTA “Use my public IP”. Otherwise two paths: “Use Quazzar tunnel (Pro+)” or “Configure port forwarding”. - Confirm — preview of the records that’ll be written and the ACME wait.
- Run — SSE-backed step list (
verify_token → create_records → configure_caddy → wait_acme → done). - Done — green check + “Open https://example.com ” CTA.
Re-running
Idempotent — re-running for the same zone:
- Skips DNS writes if the records already point at the right IP.
- Skips the Caddy reconfigure if Caddy is already serving the domain.
- Just re-runs the health check.
Useful when your public IP changes (DDNS auto-refresh is a follow-up).
How it works
internal/dnsprovider/ — Provider interface + registry
cloudflare/ — first adapter (raw net/http; ~250 LOC)
internal/netprobe/stun.go — RFC 5780 STUN probe (pion/stun/v2)
internal/domainwizard/ — Service orchestrator (Probe / Start / Get / Subscribe)
internal/proxy/routemgr/ — existing route manager; the wizard hands routes off hereThe wizard never runs ACME itself — Caddy already does, via the existing routemgr integration. We just create the A record and poll the new hostname for a 200 as the success signal.
Grey-IP path
When nat_type != "open" the wizard offers two options:
- Quazzar public tunnel (Pro+) — provisions a tunnel slot via
internal/tunnel(frpc + CP-side relay). The A record points at the tunnel’s exit IP. - Port forwarding — auto-detected NAT type, a one-click UPnP attempt, plus a printable cheat sheet for common router models (best-effort; most users still need to follow generic instructions).
Plans
| Tier | Public IP | Tunnel | BYO DNS |
|---|---|---|---|
| Free (Community) | ✅ | ❌ | ✅ |
| Pro | ✅ | ✅ (1 tunnel) | ✅ |
| Team | ✅ | ✅ (5 tunnels) | ✅ |
| Enterprise | ✅ | ✅ unlimited | ✅ |
License gates: domain_wizard (always on for everyone), public_tunnel (Pro+, count-capped). Both surfaced in /api/license/orbit-features.
API
POST /api/domainwizard/probe { provider, token }
→ { zones, public_ip, nat_type }
POST /api/domainwizard/start { provider, token, zone, target_ip, mode }
→ 202 { run_id }
GET /api/domainwizard/runs/:id → snapshot or SSE stream
POST /api/domainwizard/runs/:id/cancel → 204mode is "public_ip" | "tunnel" | "manual_ip"; the wizard sets it based on what you pick on the NAT card.
Admin-only — touches Caddy + DNS records. Audit-logged via the existing internal/audit channel.
Future providers
С.2.b drop adds Route53 + Google Cloud DNS + ACME-DNS adapters using the same Provider interface. Each new adapter is ~250 lines on average. The wizard UI auto-discovers registered adapters via dnsprovider.Available().