Custom domains & TLS

Every app has an automatically assigned apex hostname:

<app-slug>-<org-slug>.<PAAS_WILDCARD_BASE>

For org acme, app web, with PAAS_WILDCARD_BASE=apps.example.com, that's web-acme.apps.example.com. The apex is HTTP-only by default — it's served by nginx but no TLS cert is ever issued for it (Let's Encrypt won't issue for arbitrary subdomains of someone else's wildcard without DNS-01).

Custom domains get auto-TLS via Let's Encrypt HTTP-01.

Adding a custom domain

  1. DNS: point a CNAME (or apex ALIAS/A) at your Paas host:

    www.example.com   IN CNAME   paas.example.com.
    
  2. Dashboard: app → Domains → Add → www.example.com. The row appears with TlsStatus: Pending.

  3. Wait. The CertManager polls every 60s. It writes the ACME HTTP-01 challenge token, asks Let's Encrypt to validate, fetches the cert, and tells the ProxyController to flip the vhost into HTTPS mode.

  4. The status moves Pending → Issuing → Active. The nginx.conf for that vhost gains TLS listeners and a 301 from HTTP. Refresh the dashboard to see the issuance time and renewal date.

Troubleshooting

The Domains table surfaces lastError when issuance fails. Common causes:

Error contains What it means
dns problem Your DNS hasn't propagated, or doesn't point here.
Connection refused The Paas host isn't reachable on port 80 from the public internet.
Authorization invalid Same — Let's Encrypt couldn't reach /.well-known/acme-challenge/.
urn:ietf:params:acme:error:rateLimited You re-tried too aggressively. Switch to PAAS_ACME_STAGING=true while debugging.

Tail the cert-manager logs to see exactly what ACME said:

docker compose logs -f cert-manager

Renewals

Certs renew automatically when they're within 30 days of expiry (CertManager__RenewBeforeDays). The CertWorker flips the row to RenewalDue, which is treated identically to Pending on the next tick.

Removing a domain

Dashboard → Domains → Remove. The vhost file is deleted; the cert is left in /etc/nginx/certs/ but no longer referenced (you can clean it up manually if you care).

Why HTTP-01 and not DNS-01?

HTTP-01 needs nothing but port 80 reachability — no API tokens for your DNS provider. DNS-01 would let us issue wildcard certs (so the apex could be HTTPS too) but requires you to plug a DNS provider plugin in. That's on the roadmap; for v1, custom domains are the path to HTTPS.