docs(readme): add a clear Cloudflare Turnstile setup section
CI / check (push) Successful in 39s
CI / tests-imaging-browsers (push) Successful in 1m38s
CI / tests-integration (push) Successful in 2m18s
CI / tests-unit (push) Successful in 2m31s
CI / tests-ui (push) Failing after 4m2s
CI / preflight (push) Skipped
CI / deploy (push) Skipped

Explain where the captcha is configured, how the admin panel and env
vars resolve (with a precedence table), step-by-step Turnstile setup,
that the site key is public while the secret must never be committed,
and how to verify. Also link it from Optional Integrations.
This commit is contained in:
openhands committed 2026-10-15 16:05:49 +02:00
1 parent d64d864175
commit 918134df69
1 file changed
+79
+79
View File
@@ -851,6 +851,78 @@ Open **DevOps → Anti-DDoS protection**
---
## Captcha (Cloudflare Turnstile)
The **register**, **login**, **forgot-password** and **resend-verification**
forms can be protected by a captcha. **Cloudflare Turnstile** is the supported
provider and is free; reCAPTCHA and hCaptcha are also wired up. If you only
read one thing, read the precedence table below.
### Where the captcha is configured (and who wins)
There are two places, and the **admin panel always wins**:
1. **Admin panel** — *Admin → CMS Settings → Captcha* (stored in the database).
2. **Environment variables** — used **only** as a fallback when the admin panel
has no value.
Resolution order, highest first:
| Admin panel `captcha_provider` | Env `CAPTCHA_PROVIDER` | What happens |
| --- | --- | --- |
| `turnstile` | anything | **Turnstile** (panel wins) |
| `none` (set explicitly) | `turnstile` | **Off** — an explicit panel value wins |
| *empty / never set* | `turnstile` | **Turnstile** (env fallback) |
| *empty / never set* | *empty / never set* | **Off** |
In short: **enable it in the admin panel and the env vars are ignored; leave the
panel empty and the env vars take over.** An explicit `none` in the panel turns
the captcha **off** even when `CAPTCHA_PROVIDER=turnstile` is set.
### Option A — configure with environment variables (per deploy)
1. Create a Turnstile widget in the
[Cloudflare dashboard](https://dash.cloudflare.com/?to=/:account/turnstile):
**Add widget**, name it, and add the hostnames your hotel is served on
(e.g. `epicnabbo.nl`, `www.epicnabbo.nl`). *Managed* mode is fine. Copy the
**Site Key** and the **Secret Key**.
2. Put them in your real `.env` (never commit this file):
```dotenv
CAPTCHA_PROVIDER=turnstile
TURNSTILE_SITE_KEY=<your site key> # public — safe to expose
TURNSTILE_SECRET_KEY=<your secret key> # SECRET — server-side only
```
- The **site key** is **public**: it is rendered into the page for the
browser.
- The **secret key** is **secret**: only the server uses it to call
Cloudflare's `siteverify` endpoint. **Never commit it** — keep it in the
host `.env`, or a **masked CI/CD variable** if you deploy from CI.
3. Restart the container so the new env is picked up.
### Option B — configure in the admin panel
**Admin → CMS Settings → Captcha**: pick the provider and paste the site key and
secret. This overrides the env vars and takes effect **without a restart**.
### Verify
- Open `/register`. When active, the Turnstile widget appears above the submit
button.
- The e2e suite can assert the widget contract:
`E2E_EXPECT_CAPTCHA=turnstile pnpm test:e2e` (spec: `e2e/register.spec.ts`).
### Notes
- **Fail-closed**: if the provider is Turnstile but no secret key is available,
verification fails and the form is blocked — it never silently lets bots in.
- The Content-Security-Policy already allows `https://challenges.cloudflare.com`
(`src/lib/csp.ts`), so no header changes are needed.
- Turnstile does **not** require the Cloudflare proxy (orange cloud); it works
independently of the anti-DDoS layer above.
---
## Production Deployment (blue/green)
@@ -1181,6 +1253,13 @@ pnpm jobs:worker # or: npm run jobs:worker / yarn jobs:worker
Optional OpenAI-powered moderation for comments and guestbook posts. Set `OPENAI_API_KEY`.
### Captcha — Cloudflare Turnstile
Protect the register, login, forgot-password and resend-verification forms.
Set `CAPTCHA_PROVIDER=turnstile` plus the Turnstile keys in `.env`, or configure
it in **Admin → CMS Settings**. Full setup, precedence and verification:
[Captcha (Cloudflare Turnstile)](#captcha-cloudflare-turnstile).
### Byparr (Cloudflare Bypass)
Some clone sources are protected by Cloudflare. Byparr (a FlareSolverr successor) solves these challenges automatically.