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_abc123Splitting 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_abc123Once 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.
Link a Domain
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.comOn success:
✓ Domain example.com linked
› TLS certificate will be issued automaticallyIf 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.
Unlink a Domain
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 unlinkedUse 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:3000List 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:11ZParked 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 removedUse unlink instead if you only want to detach the domain — rm deletes the registration entirely.
Verb Cheatsheet
| Verb | Effect |
|---|---|
add | Register the domain against the resolved org. No routing yet. |
link | Attach a registered domain to a function or VM service. |
unlink | Detach from the current target; registration + DNS preserved. |
rm | Delete the domain registration entirely. |
ls | List 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:8080The <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 justexample) - No scheme (
https://), path (/), port (:), or spaces - Must not start or end with a dot
- Maximum 253 characters
Aliases
| Command | Alias |
|---|---|
ccp domain list | ccp domain ls |
ccp domain remove | ccp domain rm |
How It Works
addregisters the domain in the resolved organization, unattached. The API returns the A record IP for your DNS provider.linkvalidates the target (function or VM service), provisions routing, and attaches the domain. If DNS isn't ready yet, the link is rolled back and apendingstatus is returned.unlinkremoves 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
unlink→linkcycle preserves the cert and avoids a re-issue.