DNS Setup
Configure custom domains and SSL certificates for your NNO platform.
DNS Setup
NNO uses two DNS patterns depending on whether a hostname belongs to a core NNO service or a client platform resource. Understanding which pattern applies tells you how to configure it and what to expect during provisioning.
DNS naming conventions
Pattern A — NNO Core services (<name>.<type>.nno.app)
Used for NNO operator services like the Gateway, IAM, Registry, and Billing. These are declared in wrangler.toml and activated automatically on deploy — no API calls or Registry entries required.
| Environment | Pattern | Example |
|---|---|---|
| Production | <name>.svc.nno.app | gateway.svc.nno.app |
| Staging | <name>.svc.stg.nno.app | gateway.svc.stg.nno.app |
Pattern B — Client platform resources (<name>.<type>.<stack>.<platformId>.nno.app)
Used for per-platform resources like auth Workers and console frontends. These are provisioned programmatically by the Provisioning service and tracked in the Registry.
| Environment | Pattern | Example |
|---|---|---|
| Production | <name>.<type>.<stack>.<pid>.nno.app | auth.svc.default.k3m9p2xw7q.nno.app |
| Staging | <name>.<type>.stg.<stack>.<pid>.nno.app | auth.svc.stg.default.k3m9p2xw7q.nno.app |
The .app suffix is for user-facing frontends (Cloudflare Pages), and .svc is for backend APIs (Workers).
How platform DNS is provisioned automatically
When you create a platform, the Provisioning service runs a BOOTSTRAP_PLATFORM job that calls registerDns() for each resource in the default stack. Both production and staging hostnames are registered together and are idempotent — retries do not create duplicates.
After registration, Cloudflare for SaaS (CF4SaaS) issues a DV SSL certificate via HTTP validation. An ssl-poller cron runs every 15 minutes and updates the record status from pending to active once the certificate is confirmed. Under normal conditions a new hostname is active within 15–30 minutes.
Track DNS and SSL status in the NNO Portal under Platform > Provisioning, or query the Registry dns_records table directly.
Adding a new NNO core service hostname (Pattern A)
If you are adding a new operator service, declare the hostname in wrangler.toml with custom_domain = true:
# Production
[[routes]]
pattern = "notifications.svc.nno.app"
custom_domain = true
# Staging
[[env.stg.routes]]
pattern = "notifications.svc.stg.nno.app"
custom_domain = trueDeploy the Worker and Cloudflare creates the DNS records automatically:
wrangler deploy # production
wrangler deploy --env stg # stagingVerify after 30–60 seconds:
curl -I https://notifications.svc.nno.appAdding a client custom domain
Clients can map their own domain (for example, app.acmecorp.com) to any platform hostname. Trigger the ADD_CUSTOM_DOMAIN provisioning job from the NNO Portal under Platform > Domains > Add Domain, providing the custom hostname and the target DNS record ID.
After the job completes, the client must add a CNAME in their DNS provider:
app.acmecorp.com CNAME auth.svc.default.<platformId>.nno.appSSL verification begins as soon as the CNAME resolves. The ssl-poller picks up the pending record and activates it within 15–30 minutes.
Cookie domain configuration
Auth cookies are set with domain .<platformId>.nno.app (note the leading dot). All apps on your platform share this ancestor domain, so a single sign-in works across the entire platform.
For this to work, every frontend hostname must match the Pattern B structure — <name>.app.<stack>.<platformId>.nno.app. If a frontend is served from an unrelated hostname, the auth cookie will not be sent to it.
Locally, cookies are scoped to localhost and work across all ports without configuration.
CORS configuration
CORS allowed origins are set via the CORS_ORIGINS variable in each service's wrangler.toml. Production accepts a single origin; staging includes Cloudflare Pages preview URLs:
# Production
[vars]
CORS_ORIGINS = "https://console.app.nno.app"
# Staging
[env.stg.vars]
CORS_ORIGINS = "https://console.app.stg.nno.app,https://nno-<pid>-console.pages.dev"When you add a new frontend app, add its origin to every backend service it calls directly.
Troubleshooting
SSL stays pending for more than 30 minutes:
Check that the CNAME is in place with dig CNAME app.acmecorp.com. Query the CF4SaaS API for the cfHostnameId and inspect verification_errors. Fix the CNAME and reset the record to pending to trigger re-verification.
Service returns 522 or 523:
Confirm [[routes]] has custom_domain = true and the deploy succeeded (wrangler deployments list). Wait 30–60 seconds after the first deploy for DNS records to propagate.
CORS error in browser:
Identify the failing service from the network tab, then check CORS_ORIGINS in that service's wrangler.toml. Redeploy after updating.
Next steps
- Managing Environments — staging vs. production URL patterns
- Authentication — cookie domain and auth Worker setup
- API reference — Provisioning service endpoints