Custom Domains

Replace your bettersuite.io subdomains with your own hostnames, and how the DNS + well-known proxy verification actually works.

Last updated May 19, 2026

Every tenant gets a family of system subdomains under bettersuite.io automatically. On Professional and Enterprise plans you can layer your own domains on top of them. This article walks through what's mapped, what verification actually checks, and the nginx snippet you have to deploy alongside the CNAME.

What gets provisioned by default

When your tenant is created, BetterSuite generates one system subdomain per app from your slug plus a per-app suffix:

App (enum value)System URL pattern (slug = acme)
TAXI_PASSENGERacme-rides.bettersuite.io
TAXI_DRIVERacme-drive.bettersuite.io
SHOP_CUSTOMERacme-shop.bettersuite.io
SHOP_VENDORacme-vendor.bettersuite.io
PARKING_APPacme-parking.bettersuite.io
SERVICE_CUSTOMERacme-service.bettersuite.io
SERVICE_PROVIDERacme-provider.bettersuite.io
ADMIN_CONSOLEacme-admin.bettersuite.io

Only the apps for verticals you enabled get provisioned, plus ADMIN_CONSOLE always. System subdomains are pre-verified and can't be removed from the dashboard — they're the fallback if a custom domain regresses.

What a custom domain replaces

A custom domain is added per app. The page is at Owner Dashboard → Custom Domains and is owner-only — non-owner admins can't add or remove domains even if they have other manage-* permissions. The page also gates the Add custom domain button behind a Professional or Enterprise plan; below that you'll see an upgrade banner.

Each app card shows the system subdomain on top and either a custom-domain block underneath or an "Add custom domain" button.

The two-step verification

When you submit a custom domain, the backend does two checks before flipping dns_verified to true. Both must pass.

1. DNS resolution

The backend runs a lookup_host against your domain on port 443. If the hostname doesn't resolve at all, the mutation fails immediately with:

DNS verification failed for <domain>. Please add a CNAME record pointing to <system-subdomain> and try again.

So you need the CNAME live before clicking Verify & Add. Add a record at your DNS provider:

TypeNameValue
CNAMErides (or whatever subdomain you want)acme-rides.bettersuite.io — the system subdomain for the same app

2. The well-known proxy probe

DNS alone isn't enough. BetterSuite then probes three paths over HTTPS on your custom domain, in parallel, with a 5-second timeout each:

  • /.well-known/apple-app-site-association — for iOS Universal Links and passkeys.
  • /.well-known/assetlinks.json — for Android App Links and passkeys.
  • /.well-known/webauthn — for related-origin passkey sharing.

Each probe must return a 2xx with a Content-Type starting with application/json, and the body has to start with { or [. If any of the three fail, the domain gets persisted but stays dns_verified = false, and the dashboard shows it as Pending with a re-verify button.

You make these endpoints work by proxying them through to api.bettersuite.io with X-Forwarded-Host set to your custom domain. The backend renders the exact nginx snippet you need and returns it in the same response — paste it into your server { listen 443 ssl; server_name rides.acme.com; ... } block:

location ^~ /.well-known/ {
    proxy_pass https://api.bettersuite.io;
    proxy_set_header Host api.bettersuite.io;
    proxy_set_header X-Forwarded-Host rides.acme.com;
    proxy_set_header X-Forwarded-Proto https;
    proxy_ssl_server_name on;
    proxy_http_version 1.1;
    proxy_read_timeout 5s;
}

Without that snippet, iOS/Android won't bind passkeys to your custom domain — they fetch those well-known files directly from the OS and refuse anything that isn't a 2xx JSON.

Workflow end to end

  1. Add the CNAME at your DNS provider, pointing to the system subdomain for the same app.
  2. Deploy the well-known proxy snippet on the reverse proxy that fronts your custom domain. (You'll need the snippet from the dashboard — the backend tailors it to your domain on first add.)
  3. Open Owner Dashboard → Custom Domains and click Add custom domain on the app card.
  4. Enter the hostname (e.g. rides.acme.com) and click Verify & Add.
  5. If it shows Pending, click the refresh icon next to the Pending badge. The mutation re-runs DNS and the well-known probe and flips to Verified once both pass.

The same flow runs every time you re-verify. If your nginx config regresses later, the next verification will roll the domain back to Pending automatically.

Removing a custom domain

The trash icon next to a custom domain triggers a step-up password prompt before deletion — removing a domain in production redirects live traffic, and a hijacked session shouldn't be able to do that without re-entering the password. System domains can't be deleted; they're managed automatically.

Removed domains are written to the audit log (/dashboard/audit-log) as custom_domain_removed, with the domain string in the payload, so you can answer "who took rides.acme.com offline?" later.

Common issues

  • Pending won't flip even though DNS resolves — your well-known proxy isn't deployed (or isn't returning JSON). Open the dashboard, click the refresh icon, and read the failure list — it tells you which of the three endpoints failed and how (wrong status, wrong content-type, body doesn't look like JSON).
  • CAA records blocking issuance — system subdomains terminate TLS on BetterSuite's edge, and your custom domain inherits that path via the CNAME. If your apex has a restrictive CAA record, lift it for the subdomain you're delegating.
  • Cloudflare proxied (orange cloud) — proxied CNAMEs work, but only if Cloudflare passes through the well-known paths. If verification fails on the proxy probe specifically, switch the record to DNS only while you debug.
  • System-suffix collision — you can't register a custom domain ending in .bettersuite.io; the mutation rejects it explicitly.

What's next

  • Branding — pair your custom hostname with your own logos and theme.
  • Team & Roles — control which admins can manage domains.
  • Plans & Billing — custom domains require Professional or Enterprise.

Build the foundation once. Expand without limits.

BetterSuite is built for teams who see on-demand as a business — not a feature.