Custom Domain
CP users can attach their own domain name to a deployed service. Once configured, the domain serves the service over HTTPS with an automatically provisioned Let's Encrypt certificate.
How It Works
user domain (e.g. dashboard.example.com)
│ CNAME (DNS only)
▼
cpctl.app
│
▼
edge (Let's Encrypt cert provisioned per hostname, auto-renewed)
│
▼
Kubernetes cluster
Traefik Ingress (routes by Host header)
│
▼
Service pod (e.g. cp-dashboard)User Setup
Add a single DNS record at your domain registrar or DNS provider:
| Name | Type | Target | Proxy |
|---|---|---|---|
dashboard | CNAME | cpctl.app | DNS only (grey cloud) |
No Cloudflare account required. Works with any DNS provider. The record must be DNS only — do not enable proxying.
API
Attach a domain
http
POST /v1/services/:service/domains
Authorization: Bearer <cp-api-token>
Content-Type: application/json
{
"hostname": "dashboard.koraccel.kr"
}What happens: The platform verifies the CNAME, provisions a Let's Encrypt certificate for the hostname, and configures the edge servers to serve the domain over HTTPS. This takes about a minute.
Response:
json
{
"hostname": "dashboard.koraccel.kr",
"status": "active",
"service": "cp-dashboard",
"created_at": "2026-07-04T10:52:36.153Z"
}Skip DNS check (for testing):
json
{ "hostname": "dashboard.koraccel.kr", "skip_dns": true }List domains
http
GET /v1/services/:service/domains
Authorization: Bearer <cp-api-token>json
{
"domains": [
{ "hostname": "cp-dashboard.computeportal.io", "status": "active", "created_at": null },
{ "hostname": "dashboard.koraccel.kr", "status": "active", "created_at": null }
]
}Remove a domain
http
DELETE /v1/services/:service/domains/:hostname
Authorization: Bearer <cp-api-token>Returns 204 No Content. The default <service>.cpctl.app domain cannot be removed.
What happens on the server:
- Removes the hostname from the Traefik Ingress routing rules
- Removes the TLS certificate entry for the hostname
Certificates are not explicitly revoked on removal — they expire naturally after 90 days.
CLI
bash
cpctl domain add <service> <domain> # attach a domain
cpctl domain list <service> # list attached domains
cpctl domain status <service> <domain> # check DNS and TLS status
cpctl domain remove <service> <domain> # detach a domaindomain add
Before running this, add a CNAME record at your DNS provider:
| Name | Type | Target | Proxy |
|---|---|---|---|
dashboard | CNAME | cpctl.app | DNS only (grey cloud) |
Then attach the domain:
bash
cpctl domain add my-service dashboard.example.com✓ Domain dashboard.example.com attached to my-service
domain dashboard.example.com
service my-service
status active
tls provisioningTLS is provisioned automatically via Let's Encrypt within a minute or two.
If DNS hasn't propagated yet, use --skip-dns to bypass the CNAME check:
bash
cpctl domain add my-service dashboard.example.com --skip-dnsdomain list
bash
cpctl domain list my-serviceDOMAIN STATUS TLS CREATED
my-service.cpctl.app active active 2026-08-21T04:52:23.000Z
dashboard.example.com active provisioning 2026-08-21T04:52:23.000Zdomain status
bash
cpctl domain status my-service dashboard.example.comdomain dashboard.example.com
status active
tls yes
dns_configured yes
cname_target cpctl.app
created_at 2026-07-01T10:00:00Zdomain remove
bash
cpctl domain remove my-service dashboard.example.comThe default <service>.cpctl.app domain cannot be removed.
MCP Tools
| Tool | Description |
|---|---|
cp_domain_add | Attach a custom hostname to a service |
cp_domain_list | List all hostnames attached to a service |
cp_domain_remove | Detach a custom hostname from a service |
Infrastructure
| Component | Value |
|---|---|
| CNAME target | cpctl.app |
| TLS | Let's Encrypt, issued per hostname, provisioned automatically |
| Routing | Traefik Ingress, Host-header rules |
