Every service gets a platform hostname automatically on deploy ({service}.tawa.pro,
{service}.sandbox.tawa.pro, {service}.uat.tawa.pro). To put your own domain in front of a
service, use tawa domain. There are three DNS modes, picked by how the domain's DNS is
managed and whether Cloudflare can be used.
--cloudflare | --external | --direct (BYO-DNS) | |
|---|---|---|---|
| Customer DNS record | CF auto-creates CNAME | CNAME → platform host | A record → ingress LB IP |
| TLS terminated at | Cloudflare edge | Cloudflare edge | In-cluster (cert-manager / Let's Encrypt) |
| Apex/root domains | CF flattening | hard (apex CNAME) | native (A record is legal at apex) |
| CDN / WAF / DDoS | yes | yes | no (origin hit directly) |
verify checks for | n/a (auto) | CNAME → target | A → ingress LB IP |
| Needs CF zone / NS on CF | yes | yes (for TLS) | no |
Default to --cloudflare. Use --direct only when the customer cannot move their
nameservers to Cloudflare (e.g. DNS stuck at HostGator/cPanel) but can still set an A record.
# Cloudflare-managed (auto DNS + TLS) — preferred
tawa domain add portal.example.com --cloudflare
# External CNAME (you add the CNAME; TLS still at Cloudflare)
tawa domain add portal.example.com --external
# Direct A record (BYO-DNS, TLS issued in-cluster) — for when Cloudflare is not an option
tawa domain add example.com --direct
tawa domain verify example.com
tawa deploy --prod
tawa domain list
tawa domain status example.com
tawa domain remove example.com
tawa domain add <domain> --direct registers the domain on the service with
dnsProvider: 'direct'. The expectedTarget is the cluster ingress LoadBalancer IP
(INGRESS_TARGET on the builder). The CLI prints the A record to add.www, registered separately) pointing
at that IP. Apex domains work natively — no CNAME flattening needed.tawa domain verify <domain> checks that the A record resolves to the ingress LB IP
(not a CNAME). On success the record is marked dnsVerified.tawa deploy injects the verified direct-mode hosts into the service's builder-managed
ingress, adds a tls block (secretName: {service}-custom-tls) and the annotation
cert-manager.io/cluster-issuer: {CERT_MANAGER_CLUSTER_ISSUER} (default letsencrypt-prod).Cloudflare/external domains are not given an in-cluster TLS block — Cloudflare terminates
their TLS. Only direct domains get cert-manager TLS.
ClusterIssuer named to match
CERT_MANAGER_CLUSTER_ISSUER (default letsencrypt-prod, HTTP-01 solver on ingressClassName: nginx).INGRESS_TARGET on the builder must be set to the ingress LB IP. tawa domain add --direct
fails with DIRECT_MODE_UNAVAILABLE if it is unset or not an IP.tls block.Direct mode registers one record per hostname. For apex + www, add both:
tawa domain add example.com --direct
tawa domain add www.example.com --direct
tawa domain verify example.com && tawa domain verify www.example.com
tawa deploy --prod
Both hosts are added to the same {service}-custom-tls secret, so a single Let's Encrypt cert
covers them.
Last updated: July 15, 2026