Custom Domains

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

Custom Domains

Every function gets a default URL at https://{function-name}.clusterbase.dev. You can also bring your own domain — register it 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 registered 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 DNS verification.

The Two-Step Flow

The common path is add → set DNS → link:

ccp domain add example.com
# (set the printed A record at your DNS provider, wait for propagation)
ccp domain link example.com --function fn_abc123

Splitting registration from attachment lets you set DNS up front and avoids a window where the platform routes a domain that doesn't yet resolve.

Register a Domain

ccp domain add example.com
# ✓ Domain example.com registered
#
# DNS Add this A record in your DNS provider:
#
#   Type:  A
#   Name:  example.com
#   Value: 34.xx.xx.xx
#
# › Run `ccp domain link example.com --function <id>` to attach this domain to a function or VM service.

add registers the domain against an organization. The org is resolved from cluster.toml, the --org-id flag, or — when ambiguous — an interactive picker:

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

Once registered, every member of the org sees the parked domain in ccp domain ls with status pending. add is print-only — it never prompts for project setup or writes .cluster/config.json, even when invoked outside a linked project directory.

If you run ccp domain add from inside a linked project directory, the hint points at that project automatically:

› Linked project detected (fn_abc123).
  Run `ccp domain link example.com` to attach this domain.

add registers the domain in the API; nothing is routed yet. Re-running add for a domain you already own is a no-op.

Attach a registered 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 linked
› TLS certificate will be issued automatically

If DNS hasn't propagated yet, link exits non-zero with a pending status and rolls back the attachment server-side, so you can simply retry once the A record resolves — no unlink needed in between.

A domain can only be linked to one target at a time. Attempting to link a domain that's already attached returns 409 Conflict; unlink it first.

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

ccp domain unlink example.com
# ✓ Domain example.com unlinked

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 custom domain registered in the resolved organization — parked (unattached) rows included. The org is resolved the same way as add (cluster.toml, --org-id, or interactive picker). No cluster.toml or .cluster/config.json is required:

ccp domain ls
#  • example.com  active
#    →  → function:fn_abc123
#    updated 2026-05-17T17:31:00Z
#
#  • parked.example.com  pending
#    →  unattached
#    updated 2026-05-17T17:42:11Z

Parked rows show with status pending and target unattached until they're linked. Pass --org-id to list a different org.

Remove a Domain

rm deletes the domain registration outright. If the domain is currently linked, it's detached first. Confirmation is required (auto-confirms in headless mode). Works outside any project directory.

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 registration entirely.

Verb Cheatsheet

VerbEffect
addRegister the domain against the resolved org. No routing yet.
linkAttach a registered domain to a function or VM service.
unlinkDetach from the current target; registration + DNS preserved.
rmDelete the domain registration entirely.
lsList every domain in the resolved org, including parked rows.

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 rollback 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 registers the domain in the resolved organization, unattached. The API returns the A record IP for your DNS provider.
  • link validates the target (function or VM service), provisions routing, and attaches the domain. If DNS isn't ready yet, the link is rolled back and a pending status is returned.
  • unlink removes routing and detaches the domain, but the registration and DNS-verified state are preserved.
  • TLS certificates live on the domain (not the attachment), so an unlinklink cycle preserves the cert and avoids a re-issue.

On this page