Platform

Custom Domains

Claim, verify, link, and unlink custom domains across functions and VMs with automatic TLS.

View as Markdown

Every function gets a default URL at https://{function-name}.clusterbase.dev. You can also bring your own domain — claim and verify ownership once, then link it to a function or a VM service. TLS is provisioned automatically.

Domains are top-level objects scoped to an organization: a verified domain belongs to the org and is visible to every member, independent of any function or VM. Linking attaches a domain to a target; unlinking detaches it without forgetting the domain or re-running ownership verification.

The Three-Step Flow

The common path is add → set DNS → verifylink:

ccp domain add example.com
# (add the printed TXT ownership record and A routing record at your DNS provider, wait for propagation)
ccp domain verify claim_abc123
ccp domain link example.com --function fn_abc123

Splitting the ownership claim, verification, and attachment lets you prove you control the domain and set DNS up front, avoiding a window where the platform routes a domain that doesn't yet resolve or isn't yours.

Start an Ownership Claim

ccp domain add example.com
# ✓ Ownership claim created for example.com
# Claim:   claim_abc123
# Expires: 2025-01-15T12:00:00Z
#
# DNS Add these records in your DNS provider:
#
#   Type:  TXT
#   Name:  _clusterbase-verify.example.com
#   Value: clusterbase-verify=8f14e45f-ea0f-4c2b-9c1a-3d5b7e2a6f01
#
#   Type:  A
#   Name:  example.com
#   Value: 34.xx.xx.xx
#
# › After the TXT record resolves, run `ccp domain verify claim_abc123 --org-id <org>`

add starts an expiring ownership claim against an organization; the domain is not yet in inventory and does not appear in ccp domain ls until it's verified. The org is resolved from cluster.toml, the --org-id flag, the CCP_ORG_ID env var, or — when ambiguous — an interactive picker:

ccp domain add example.com --org-id org_abc123

add is print-only — it never prompts for project setup or writes .ccp/config.json, even when invoked outside a linked project directory.

Verify a Claim

Once the TXT record from add has propagated, complete the claim:

ccp domain verify claim_abc123 --org-id org_abc123
# ✓ Domain example.com verified
# › It is ready to link to an app or VM.

verify resolves the TXT proof for a claim and, on success, admits the domain into the organization's inventory — this is the point at which it shows up in ccp domain ls. Nothing is routed yet; run link next.

Attach a verified domain to a target. Pass exactly one of --function or --vm:

# Attach to a serverless function
ccp domain link example.com --function fn_abc123

# Attach to a VM service (vm_id:port)
ccp domain link api.example.com --vm vm-xyz:3000

# Inside a linked project directory: target defaults to that function
ccp domain link example.com

On success:

✓ Domain example.com binding accepted at revision rev_2
› Routing and TLS will converge automatically

Every mutation is fenced against the domain's current binding revision, so link always applies on top of the state you last observed. A domain can only be linked to one target at a time — linking an already-attached domain replaces its desired target on the next revision. Pass --org-id if the domain's org can't be resolved from cluster.toml.

Detach a domain from its current target. The domain stays owned and verified, so a later link doesn't repeat ownership verification.

ccp domain unlink example.com
# ✓ Domain example.com withdrawal accepted at revision rev_3

unlink submits a withdrawal of the current binding; routing disappears once the withdrawal converges, not immediately.

Use unlink when you want to move a domain to a different function or VM:

ccp domain unlink example.com
ccp domain link example.com --vm vm-xyz:3000

List Domains

ls lists every verified domain owned by the resolved organization, including domains not yet linked to a target. Domains with a pending (unverified) claim don't appear until verify completes. The org is resolved the same way as add (cluster.toml, --org-id, or interactive picker). No cluster.toml or .ccp/config.json is required:

ccp domain ls
# DOMAIN              REVISION
# example.com         rev_2
# parked.example.com  rev_0

Each row shows the domain and its current binding revision — the same revision used to fence link, unlink, and rm calls. Pass --org-id to list a different org.

Each domain prints on one line, sized to fit the terminal. Pass --json for the domain's id, exact binding_revision, and complete URL with no styling — the format to script against.

Remove a Domain

rm retires the domain's ownership record outright. Confirmation is required (auto-confirms in headless mode). Works outside any project directory. Wait for an existing binding to finish withdrawing before removing — rm does not implicitly unlink first.

ccp domain rm example.com
# Remove domain example.com? (y/N): y
# ✓ Domain example.com removed

Use unlink instead if you only want to detach the domain — rm deletes the ownership record entirely.

Verb Cheatsheet

VerbEffect
addStart an ownership claim against the resolved org.
verifyComplete a claim's TXT proof; admits the domain into inventory.
linkAttach a verified domain to a function or VM service.
unlinkWithdraw from the current target; ownership + verification preserved.
rmRetire the domain's ownership record entirely.
lsList every verified domain in the resolved org.

Compute Services

Compute services don't have a --function flag — point a domain at one via the underlying instance id and the service's port. Get the id from ccp compute status:

ccp compute status
# Compute service my-api
#
#   ID       3fd25c…
#   Status   running
#   Image    ghcr.io/me/api:v3
#   Port     8080
#   Instance vm-7e21…

Then link the domain at <instance>:<port>:

ccp domain link api.example.com --vm vm-7e21:8080

The <port> is the same one you passed to ccp compute deploy --port. Routing, TLS, and revision semantics are identical to function targets — see Compute services for the full lifecycle.

Domain Requirements

  • Must include a TLD (e.g., example.com, not just example)
  • No scheme (https://), path (/), port (:), or spaces
  • Must not start or end with a dot
  • Maximum 253 characters

Aliases

CommandAlias
ccp domain listccp domain ls
ccp domain removeccp domain rm

How It Works

  • add opens an expiring ownership claim against the resolved organization and returns the TXT and A records to add at your DNS provider.
  • verify resolves the TXT proof for a claim and admits the domain into the organization's inventory, unattached.
  • link sets the domain's desired binding to the target (function or VM service); the mutation is fenced against the domain's current binding revision and converges asynchronously.
  • unlink sets the desired binding to withdrawn; routing and the desired target are removed once the withdrawal converges, but the domain's ownership and verification state are preserved.
  • TLS certificates live on the domain (not the attachment), so an unlinklink cycle preserves the cert and avoids a re-issue.
  • Deleting the function behind a linked domain (ccp remove) is rejected while the domain is still attached — unlink (or rm) it first. This prevents a deleted function from orphaning a live route.

On this page