In Short
When
FLUXER_CAPTCHA_PROVIDER=turnstile is configured on a self-hosted instance, the bootstrap payload correctly advertises the Turnstile site key, but the Content-Security-Policy served by the app shell only whitelists hCaptcha. As a result, the browser refuses to load
https://challenges.cloudflare.com/turnstile/v0/api.js and no captcha widget is rendered on the registration page.
In effect, Turnstile is selectable in the admin UI but non-functional out of the box.
Environment
- Deployment: self-hosted via Docker Compose (Coolify, but the issue is not Coolify-specific — the CSP is set by the app, not the proxy)
- Image tag:
ghcr.io/fluxerapp/fluxer-app-proxy-self-hosted:v1 - Caddy (
caddy:2.10-alpine) used as the documented reverse proxy - Browser: Firefox / Chromium (current versions)
Root cause (best guess)
The CSP emitted by
app-proxy is hardcoded with hCaptcha origins:
script-src includes https://hcaptcha.com https://*.hcaptcha.comframe-src includes https://hcaptcha.com https://*.hcaptcha.com
but does
not include the Turnstile origins:
https://challenges.cloudflare.com (script + iframe + connect)https://static.cloudflareinsights.com (sometimes used by Turnstile telemetry)
Because the captcha provider is selectable at runtime, the CSP should reflect the active provider — either by emitting a different allowlist depending on
FLUXER_CAPTCHA_PROVIDER, or by including both providers' origins unconditionally.
Suggested fix
When
FLUXER_CAPTCHA_PROVIDER=turnstile, extend the CSP served by
app-proxy (and any other component that emits CSP for the web client) to include at least:
script-src → https://challenges.cloudflare.comframe-src → https://challenges.cloudflare.comconnect-src → https://challenges.cloudflare.com
Alternatively, allow operators to configure additional CSP sources via env vars (e.g.
FLUXER_CSP_EXTRA_SCRIPT_SRC,
FLUXER_CSP_EXTRA_FRAME_SRC) so the same kind of issue can be solved for other future providers without code changes.
Workaround for other self-hosters reading this
Switch the provider to
hCaptcha in the admin console (
FLUXER_CAPTCHA_PROVIDER=hcaptcha). It is already whitelisted in the default CSP and works without further configuration.
Additional notes
- A minor unrelated nit in
deploy/self-hosting/docker-compose.yml: the captcha defaults appear in some forks/edits as :true / :turnstile instead of :-false / :-none. The current upstream is correct, but it might be worth a brief comment near those lines explaining that the operator should set FLUXER_CAPTCHA_PROVIDER via env, since people copy-paste these blocks and easily drop the -. - Happy to provide a redacted HAR / full CSP header if useful.
Logs or screenshots
Browser Console:
"RestTransport.ts:501 Loading the script '
https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback&render=explicit%27 violates the following Content Security Policy directive: "script-src 'self' 'nonce-93b7c18a12fdfe08b50ceb0c7cbf3c24' 'wasm-unsafe-eval' blob:
https://*.fluxer.app/ https://hcaptcha.com/ https://*.hcaptcha.com/ https://example.domain/". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback. The action has been blocked"
4 comments
Comment by @MrRubberDucky
Comment by @fincrawmcq
Comment by @Float-as
Comment by @b-hayes