Koo Docs
View as Markdown

Custom domains

Every web service you expose gets a default HTTPS URL from its first deployment. You can also point your own domain at it — delivered over HTTPS with a certificate Koo issues and renews for you.

Your app's default URL

When you expose a web service, Koo's hosting layer assigns it a public URL automatically. There is nothing to configure: HTTPS is included, with the certificate managed for you.

Each app exposes one primary web service at its default URL. Other services in the app — including Postgres and Redis — stay internal and are never publicly routable. See Apps and services for how services fit together.

You can find the URL on the service in the console, or read it from the liveUrl field on the Service object. Public app pages link to it as your app's live destination.

Add a custom domain

A custom domain is a hostname you attach to an exposed web service. The service keeps its default URL — a custom domain adds a hostname, it doesn't replace one.

Domains are declarative on the service, and the hostname is its own identity: you manage the full set of hostnames, and there are no domain IDs to track. The service must already be deployed and exposed to route a custom domain to it.

In the console. Open the service's drawer, go to Networking → Public domains, and add the hostname — for example app.example.com. If the service isn't exposed yet, expose it first under Settings → Public networking and deploy.

Over the API. Write the full desired set of hostnames to the service through a service update, as a domains array of strings:

json
{  "domains": ["app.example.com", "www.example.com"]}

The array is the complete desired state: a hostname you leave out is removed. Read each hostname back on the service's read-only domains array, where every entry is enriched with the DNS records to set and its live status.

Set the DNS records

As soon as you add a hostname, Koo returns the exact DNS records to create — an ownership record and a routing record. The console shows each record's name and value with copy buttons; over the API they come back on the service's domains[].dnsRecords. Don't guess the values — set exactly what Koo returns, at your DNS provider.

PurposeTypeWhat to set
OwnershipTXTThe name and value Koo shows for the hostname
RoutingCNAMEThe target Koo shows for the hostname

Routing is always a CNAME, for both subdomains and apex domains. Because the DNS standard doesn't allow a CNAME at the zone root, point an apex domain (like example.com) at Koo's target using your DNS provider's CNAME flattening — often labelled ALIAS or ANAME. You never configure NS delegation, and Koo never asks you to.

Verification, routing, and TLS

Once the records are set, Koo takes it from there — you don't trigger anything. A domain walks a simple lifecycle, readable from its status on the service:

  • pending — added, but the records aren't proven yet.
  • verifying — the records are accepted, and DNS and the certificate are being set up.
  • active — traffic routes to your service and HTTPS is live. Koo issues the certificate automatically on port 443 and renews it for you; you never upload or renew a certificate.
  • error — something is off. When the cause is known — a record that doesn't resolve, say — it shows under the status, and as statusReason on the API.

While a domain is pending or error, Koo re-checks it automatically about once a minute, so you just set the records and wait — there is no verify button to press. A domain is never marked active until DNS and the certificate are both real, so the status you see is the truth.

Remove a domain

Remove a hostname in the console, or leave it out of the service's domains array on the next update. Traffic on that hostname stops routing right away; the service's default URL and any other custom domains keep working. To restore it, add it again and re-set the DNS records.

Plan requirements

Custom domains are a paid-plan feature. The Free plan doesn't include them, and each paid plan includes a set number — see the plan comparison in Free tier & pricing.

When you reach your plan's custom-domain limit, the console blocks adding another and points you to the plan that raises it, and the API returns a quota error naming the tier to upgrade to. Plan changes are handled in Billing.