Reference
View as MarkdownDomains API
Service domains.
10 operations. Every call needs a session cookie or an Authorization: Bearer nct_… token unless marked Public. Conventions, errors and scopes
/domains/{domainId}Update a domain's routing rule (staged until deployed)
Requires If-Match: "<generation>" of the owning service; a stale value returns 412 generation_conflict. Hostname changes need projects:write; every other field (path prefix, strip/add prefix, redirect, TLS mode, pinned certificate, options) also needs proxy:write and an agent with proxy v2 (422 agent_too_old). 422 codes: invalid_path_prefix, invalid_redirect, redirect_loop, invalid_tls_mode, certificate_mismatch, invalid_options, basic_auth_needs_users. 409 domain_conflict when host+path is taken.
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string | |
If-Match | header | string | The owning service's ETag (generation) from its last GET. Required. |
Request body · application/json · required
- addPrefixstringPrepend this path before forwarding to the service
- certificateIdstringAn uploaded certificate of the service's server whose names cover the hostname; empty clears the pin
- dnsResolverstringDNS-01 provider (a lego provider code) that obtains the certificate; the server must have a resolver for it. Empty = HTTP-01 or a covering wildcard certificate
- hostnamestring
- kindenum: serve | redirectserve routes to the service; redirect answers with a redirect to redirectTo
- RouteOptions
- pathPrefixstringServe only this path (and below), e.g. /api. Empty = the whole host
- preservePathbooleanA redirect keeps the request path and query (default true)
- redirectCodeenum: 301 | 302 | 307 | 308
- redirectTostringTarget hostname of a redirect (not a URL)
- stripPrefixbooleanRemove the path prefix before forwarding to the service
- tlsModeenum: auto | custom | noneauto = ACME or the default certificate, custom = an uploaded certificate, none = plain HTTP only
- wwwRedirectbooleantrue creates (false removes) a whole-host 301 redirect from the www/apex counterpart of this hostname (www.<host>, or the host without www.) to this domain. Both hostnames are routed and get certificates; each needs its own DNS record. Needs a whole-host serve domain (422 invalid_www_redirect)
Response 200 · OK · application/json
- addPrefixstringrequired
- authUsersstring[] | nullrequired
- DomainCertrequired
- certificateIdstringrequired
- componentstringrequired
- DomainDNSrequired
- dnsCheckedAtstring (date-time) | nullrequired
- dnsOkboolean | nullrequired
- dnsResolverstringrequiredThe lego code of the DNS-01 provider that obtains the certificate; empty = HTTP-01 or a covering wildcard certificate
- generatedbooleanrequired
- hostnamestringrequired
- idstringrequired
- kindenum: serve | redirectrequired
- RouteOptionsrequired
- pathPrefixstringrequired
- preservePathbooleanrequired
- redirectCodeenum: 301 | 302 | 307 | 308required
- redirectTostringrequired
- statusstringrequired
- statusMessagestringrequired
- stripPrefixbooleanrequired
- targetPortinteger (int64)required
- tlsModeenum: auto | custom | nonerequired
- wwwPartnerstringrequiredThe counterpart hostname a www redirect would use (www.<host>, or the host without www.); empty when the domain cannot have one
- wwwRedirectbooleanrequiredA whole-host redirect from wwwPartner to this domain exists (both hostnames are routed and get certificates)
- wwwRedirectForstringrequiredFor the redirect domain of a www redirect: the hostname it redirects to; empty otherwise
401Unauthorized403Forbidden404Not Found409Conflictdomain_conflict412Precondition Failedgeneration_conflict422Unprocessable Entityagent_too_old428Precondition Required500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}Remove a domain (staged until deployed)
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string |
Response 204 · No Content
No body.
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}/auth-usersReplace a domain's basic-auth users
Replaces the whole user set (needs proxy:write). A user that already exists may omit the password to keep it. Passwords are bcrypt-hashed (cost 10) and stored sealed; only user names are ever returned. Enable the option with PATCH /domains/{id} options.basicAuth. Users apply live with the next route push.
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string |
Request body · application/json · required
- passwordstringOmit to keep the password of an existing user
- usernamestringrequired
Response 200 · OK · application/json
- usernamesstring[] | nullrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}/auth-users/{username}Remove one basic-auth user
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string | |
usernamerequired | path | string |
Response 204 · No Content
No body.
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}/dnsLive Cloudflare DNS status of a domain
Reads the records of the hostname from Cloudflare and classifies them: managed (a record NebulaCtrl created points to the server or tunnel), present (a record NebulaCtrl did not create already points there), wrong_target, missing or not_in_zone. Changes nothing.
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string |
Response 200 · OK · application/json
- checkedAtstring (date-time) | nullrequired
- configuredbooleanrequiredThe team has a Cloudflare connection
- conflictstringrequiredWhy adopting is impossible (for example a CNAME next to an A record)
- RecordViewrequired
- effectiveProxiedbooleanrequired
- errorstringrequiredThe last failed sync, empty when the last sync worked
- managebooleanrequiredNebulaCtrl keeps this domain's records in sync
- messagestringrequired
- needsAdoptbooleanrequired
- OriginLockViewrequired
- proxiedbooleanrequiredThe proxy setting of the domain (orange cloud)
- RecordView[] | nullrequiredA, AAAA and CNAME records of the hostname
- sslModeenum: | off | flexible | full | strictrequiredThe zone's SSL/TLS mode; empty when unknown
- statusenum: | managed | present | wrong_target | missing | not_in_zonerequired
- tunnelbooleanrequiredThe server is behind a Cloudflare Tunnel: the record is a proxied CNAME to it
- warningsstring[] | nullrequired
- zoneIdstringrequired
- zoneNamestringrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error502Bad Gateway
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}/dnsChange a domain's Cloudflare settings
Sets the per-domain proxy toggle and whether NebulaCtrl manages the domain's records, then syncs. A failed sync is reported as error in the status and retried in the background.
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string |
Request body · application/json · required
- managebooleanLet NebulaCtrl keep the domain's DNS records in sync
- originLockbooleanLock the origin to Cloudflare while the domain is proxied (default true). False opts out: anyone who finds the server's IP can bypass Cloudflare. Audited.
- proxiedbooleanProxy through Cloudflare (orange cloud). Tunnel records are always proxied.
Response 200 · OK · application/json
- checkedAtstring (date-time) | nullrequired
- configuredbooleanrequiredThe team has a Cloudflare connection
- conflictstringrequiredWhy adopting is impossible (for example a CNAME next to an A record)
- RecordViewrequired
- effectiveProxiedbooleanrequired
- errorstringrequiredThe last failed sync, empty when the last sync worked
- managebooleanrequiredNebulaCtrl keeps this domain's records in sync
- messagestringrequired
- needsAdoptbooleanrequired
- OriginLockViewrequired
- proxiedbooleanrequiredThe proxy setting of the domain (orange cloud)
- RecordView[] | nullrequiredA, AAAA and CNAME records of the hostname
- sslModeenum: | off | flexible | full | strictrequiredThe zone's SSL/TLS mode; empty when unknown
- statusenum: | managed | present | wrong_target | missing | not_in_zonerequired
- tunnelbooleanrequiredThe server is behind a Cloudflare Tunnel: the record is a proxied CNAME to it
- warningsstring[] | nullrequired
- zoneIdstringrequired
- zoneNamestringrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/domains/{domainId}/dns/fixFix a domain's DNS record
Creates or corrects the record so the hostname points at the server (or tunnel). A record NebulaCtrl did not create is never modified unless adopt is true (409 adoption_required; 409 dns_conflict when adopting is impossible, for example a CNAME next to an A record). 422 not_configured / not_in_zone; 502 when Cloudflare fails.
| Parameter | In | Type | Description |
|---|---|---|---|
domainIdrequired | path | string |
Request body · application/json · required
- adoptbooleanTake over the existing record NebulaCtrl did not create: it is marked as managed and pointed at the server
Response 200 · OK · application/json
- checkedAtstring (date-time) | nullrequired
- configuredbooleanrequiredThe team has a Cloudflare connection
- conflictstringrequiredWhy adopting is impossible (for example a CNAME next to an A record)
- RecordViewrequired
- effectiveProxiedbooleanrequired
- errorstringrequiredThe last failed sync, empty when the last sync worked
- managebooleanrequiredNebulaCtrl keeps this domain's records in sync
- messagestringrequired
- needsAdoptbooleanrequired
- OriginLockViewrequired
- proxiedbooleanrequiredThe proxy setting of the domain (orange cloud)
- RecordView[] | nullrequiredA, AAAA and CNAME records of the hostname
- sslModeenum: | off | flexible | full | strictrequiredThe zone's SSL/TLS mode; empty when unknown
- statusenum: | managed | present | wrong_target | missing | not_in_zonerequired
- tunnelbooleanrequiredThe server is behind a Cloudflare Tunnel: the record is a proxied CNAME to it
- warningsstring[] | nullrequired
- zoneIdstringrequired
- zoneNamestringrequired
401Unauthorized403Forbidden404Not Found409Conflictadoption_requireddns_conflict422Unprocessable Entitynot_configured500Internal Server Error502Bad Gateway
Errors are RFC 9457 application/problem+json with a stable code field.
/services/{serviceId}/domainsList a service's domains
| Parameter | In | Type | Description |
|---|---|---|---|
serviceIdrequired | path | string |
Response 200 · OK · application/json
- DomainView[] | nullrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/services/{serviceId}/domainsAdd a domain (staged until deployed)
Hostnames are RFC 1123, lowercase and globally unique (409 domain_conflict). Fails with 422 proxy_unavailable while the server's proxy is not running. statusMessage carries DNS guidance and dnsOk the result of the periodic DNS check. Compose stacks need component (422 component_required, unknown_component) and, unless the component declares exactly one port, targetPort (422 target_port_required).
| Parameter | In | Type | Description |
|---|---|---|---|
serviceIdrequired | path | string |
Request body · application/json · required
- addPrefixstringPrepend this path before forwarding to the service
- certificateIdstringAn uploaded certificate of the service's server whose names cover the hostname; empty clears the pin
- componentstringCompose stacks only (required for them): the component (compose service) the domain routes to
- dnsResolverstringDNS-01 provider (a lego provider code) that obtains the certificate; the server must have a resolver for it. Empty = HTTP-01 or a covering wildcard certificate
- hostnamestringrequired
- kindenum: serve | redirectserve routes to the service; redirect answers with a redirect to redirectTo
- RouteOptions
- pathPrefixstringServe only this path (and below), e.g. /api. Empty = the whole host
- preservePathbooleanA redirect keeps the request path and query (default true)
- redirectCodeenum: 301 | 302 | 307 | 308
- redirectTostringTarget hostname of a redirect (not a URL)
- stripPrefixbooleanRemove the path prefix before forwarding to the service
- targetPortinteger (int64)Defaults to, and must equal, the service port. Compose stacks: the container port of the component; optional when the component declares exactly one port
- tlsModeenum: auto | custom | noneauto = ACME or the default certificate, custom = an uploaded certificate, none = plain HTTP only
- wwwRedirectbooleantrue creates (false removes) a whole-host 301 redirect from the www/apex counterpart of this hostname (www.<host>, or the host without www.) to this domain. Both hostnames are routed and get certificates; each needs its own DNS record. Needs a whole-host serve domain (422 invalid_www_redirect)
Response 201 · Created · application/json
- addPrefixstringrequired
- authUsersstring[] | nullrequired
- DomainCertrequired
- certificateIdstringrequired
- componentstringrequired
- DomainDNSrequired
- dnsCheckedAtstring (date-time) | nullrequired
- dnsOkboolean | nullrequired
- dnsResolverstringrequiredThe lego code of the DNS-01 provider that obtains the certificate; empty = HTTP-01 or a covering wildcard certificate
- generatedbooleanrequired
- hostnamestringrequired
- idstringrequired
- kindenum: serve | redirectrequired
- RouteOptionsrequired
- pathPrefixstringrequired
- preservePathbooleanrequired
- redirectCodeenum: 301 | 302 | 307 | 308required
- redirectTostringrequired
- statusstringrequired
- statusMessagestringrequired
- stripPrefixbooleanrequired
- targetPortinteger (int64)required
- tlsModeenum: auto | custom | nonerequired
- wwwPartnerstringrequiredThe counterpart hostname a www redirect would use (www.<host>, or the host without www.); empty when the domain cannot have one
- wwwRedirectbooleanrequiredA whole-host redirect from wwwPartner to this domain exists (both hostnames are routed and get certificates)
- wwwRedirectForstringrequiredFor the redirect domain of a www redirect: the hostname it redirects to; empty otherwise
401Unauthorized403Forbidden404Not Found409Conflictdomain_conflict422Unprocessable Entityproxy_unavailablecomponent_requiredtarget_port_required500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/services/{serviceId}/domains/generateGenerate a domain
Creates <service>-<env>-<project>.<base> where base is the server's base domain, else <public-ip>.sslip.io. 422 no_base_domain when neither exists. Compose stacks need component; the hostname is <service>-<component>-<env>-<project>.<base>.
| Parameter | In | Type | Description |
|---|---|---|---|
serviceIdrequired | path | string | |
component | query | string | Compose stacks only (required for them): the component the generated domain routes to |
Response 201 · Created · application/json
- addPrefixstringrequired
- authUsersstring[] | nullrequired
- DomainCertrequired
- certificateIdstringrequired
- componentstringrequired
- DomainDNSrequired
- dnsCheckedAtstring (date-time) | nullrequired
- dnsOkboolean | nullrequired
- dnsResolverstringrequiredThe lego code of the DNS-01 provider that obtains the certificate; empty = HTTP-01 or a covering wildcard certificate
- generatedbooleanrequired
- hostnamestringrequired
- idstringrequired
- kindenum: serve | redirectrequired
- RouteOptionsrequired
- pathPrefixstringrequired
- preservePathbooleanrequired
- redirectCodeenum: 301 | 302 | 307 | 308required
- redirectTostringrequired
- statusstringrequired
- statusMessagestringrequired
- stripPrefixbooleanrequired
- targetPortinteger (int64)required
- tlsModeenum: auto | custom | nonerequired
- wwwPartnerstringrequiredThe counterpart hostname a www redirect would use (www.<host>, or the host without www.); empty when the domain cannot have one
- wwwRedirectbooleanrequiredA whole-host redirect from wwwPartner to this domain exists (both hostnames are routed and get certificates)
- wwwRedirectForstringrequiredFor the redirect domain of a www redirect: the hostname it redirects to; empty otherwise
401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entityno_base_domain500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.