Custom domains

Serve your public site at a domain you own — gracechurch.org instead of grace.psalmly.app. Admin and member portal stay on the Psalmly domain; the custom domain is public-site only.

When you'd use this

  • You already own a domain and want visitors to land at it directly.
  • You're moving from an older church website and want to keep the domain pointing to the same place.
  • You want a vanity URL on outreach materials (yard signs, postcards, the back of a t-shirt) that doesn't include "psalmly.app".

The two-step flow

We verify DNS first, then provision the cert. That avoids burning cert allowance on hostnames a church doesn't actually control.

  1. Add the domain. Admin → Settings → Custom domains → Add domain. Type the hostname (gracechurch.org) — no protocol, no slash. The row appears with status DNS pending and a panel of DNS records to publish.
  2. Publish two DNS records at your DNS host:
    • A TXT record at _psalmly.<hostname> with the verification token shown in the panel. Proves ownership.
    • An A record at the apex (gracechurch.org) pointing to 76.76.21.21, OR a CNAME to cname.vercel-dns.com if your DNS host supports CNAME-at-apex (Cloudflare, Route 53 alias).
  3. Wait — or check now. We re-check DNS periodically. When both records resolve, status flips to DNS verified and we immediately ask Vercel to attach the domain + issue the cert. Status walks through Cert provisioningLive. Don't want to wait for the next automatic pass? Hit Check now on the domain row to re-check that instant.

Typical end-to-end time from "added" to "live" is 10–30 minutes, dominated by DNS propagation. Cloudflare-fronted domains often verify in a couple of minutes; older DNS hosts (GoDaddy, Namecheap web UI) can take an hour or two.

What "live" means

Once the row reads Live:

  • Visiting gracechurch.org/ serves your public home page.
  • Deep links like gracechurch.org/about, gracechurch.org/give, gracechurch.org/events/<id> all work — anything that's on grace.psalmly.app is also on your custom domain.
  • The certificate is auto-renewed by Vercel ahead of expiry. You don't have to do anything.

What does not work on the custom domain — by design:

  • gracechurch.org/admin/... returns 404. The admin app stays on psalmly.app so admin authentication isn't fragmented across arbitrary hostnames.
  • gracechurch.org/member/... (or any other authenticated member portal path) — same.
  • Bare /c/<slug> URLs — the admin/member routes those handle aren't served on a custom domain.

If a visitor lands on one of those URLs on your custom domain, send them to the Psalmly URL instead.

Status states

StatusMeaningWhat to do
DNS pendingRecords not yet detected. We re-check periodically.Publish the records; wait for propagation, or hit Check now to re-check immediately. The panel shows a dig command if you want to verify locally.
DNS verifiedTXT + apex records both resolve. Vercel attach is queued.Nothing — the cert step runs automatically.
Cert provisioningVercel is issuing the cert.Wait — usually completes in seconds, sometimes a minute.
LiveCert issued, routing active.Visit your hostname.
ErrorDNS records dropped or the cert step failed (e.g. a CAA record blocking issuance). The row shows the specific reason.Fix the underlying issue, then hit Check now (or wait for the next automatic check). Error is not a dead end — a successful re-check moves the domain straight back into the pipeline. No need to remove + re-add unless you want a fresh verification token.

Removing a domain

Use the row's overflow menu → Remove. The domain stops serving your site within ~5 minutes (when the route cache expires). The Vercel cert lingers in their system until its own TTL — that's fine, it just won't route to you.

Why isn't it verifying?

Almost always one of:

  1. Records not propagated yet. Give it more time (up to an hour on a slow DNS host), then hit Check now. Run dig +short _psalmly.<hostname> TXT and dig +short <hostname> A — both should return the values from the panel before we can verify.
  2. TXT value typo. DNS UIs sometimes strip / add quotes; the value should be the raw token from the panel, nothing else.
  3. CAA record blocking issuance. Some DNS hosts pre-populate a CAA record that restricts cert issuance to a specific authority. If you see Error with "misconfigured DNS / CAA blocking", either remove the CAA record or add letsencrypt.org to the allowed authorities.
  4. A record pointing at an old host. Make sure the A record value is exactly 76.76.21.21 and there are no extra A records pointing elsewhere.

What's deferred

  • Multiple hostnames per church (e.g. both gracechurch.org and grace-church.org). The schema allows it (one row per hostname); the admin UI lets you add a second row. Both will work, but the canonical / redirect setup between them is on you.
  • Cert / DNS providers other than Vercel. Phase 6 v1 is Vercel only. If you're hosting Psalmly somewhere else, this feature won't work until a small adapter for the new platform's domain API lands.
  • Apex + www handling. If you want both gracechurch.org AND www.gracechurch.org, add them as two separate domain rows. Each needs its own DNS record set.