Skip to content

A new custom domain silently breaks its newsletter signup until the Turnstile hostname is added #1586

Description

@feruzm

Attaching a custom domain to a managed blog now has a second required step that nothing enforces, and skipping it breaks that tenant's newsletter signup in a way we cannot see.

Why

Since #1579 the managed-blog signup form renders a Cloudflare Turnstile widget, and the relay refuses an anonymous subscribe without a valid token. A Turnstile sitekey is bound to a hostname list.

Subdomains are covered automatically — a hostname entry covers that hostname and all of its subdomains — so every *.blogs.ecency.com tenant works off the existing ecency.com entry and needs nothing. A custom domain on its own apex does not.

blog.hivexplorer.com was added manually on 2026-08-20; the widget now carries ["blog.hivexplorer.com", "ecency.com"]. The next custom domain will not be, unless someone remembers.

The failure mode is the problem

The widget fails to solve, the submit button never enables, and the reader sees a form that quietly does nothing — on someone else's blog. No error reaches us. sync-custom-domains.py issues the certificate and writes the vhost every 5 minutes without touching Turnstile, so the blog itself looks entirely healthy.

What is in place

apps/self-hosted/hosting/origin/README.md documents the step next to the nginx one, including that the update is a PUT of the whole widget object — the domains array must be read and appended to, or every previously registered tenant is silently dropped. The token needs Turnstile: Edit; with read-only the API answers 10405/10000 without naming the missing permission.

Options

  1. Extend sync-custom-domains.py to reconcile the Turnstile domain list the same way it reconciles vhosts — it already reads verified custom domains from the hosting DB, so it has the list.
  2. Have the hosting API append the hostname when a custom domain is verified.
  3. Leave it manual and add a check that alerts when a served custom domain is absent from the widget.

(1) fits the existing shape best: the sync already owns "make the origin match the DB", and this is the same reconciliation against a different API. It needs a Cloudflare token with Turnstile: Edit on the origin box, which is the main new consideration.

Until then this is a documented manual step, which is exactly the kind that gets missed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions