Victor Crespo
12/25/2025, 9:00 PMPREFECT_API_URL variable to point to the URL handled by a Flask server running on Linux. At first, the worker runs and executes the flows, but when I try to restrict access to this link so that only authorized people can use it, the worker is no longer able to connect. I am using Nginx and also have Cloudflare Zero Trust. How can I protect the URL so that only authorized people can access the Prefect UI without the worker losing its connection to the API?Marvin
12/25/2025, 9:01 PMMarvin
12/25/2025, 9:06 PMexport PREFECT_API_URL="<https://prefect.example.com/api>"
export PREFECT_CLIENT_CUSTOM_HEADERS='{"CF-Access-Client-Id":"<your_id>","CF-Access-Client-Secret":"<your_secret>"}'
- Keep Nginx as a plain reverse proxy for /api (no auth prompt there); let Cloudflare Access enforce API access with the service token.
- Why it works
- Workers include the Cloudflare Access headers on every request via PREFECT_CLIENT_CUSTOM_HEADERS
- Humans must SSO to see the UI; workers do not need to log in interactively
- References
- Custom client headers setting in Prefect: prefect/settings/models/client.py
- How the client applies custom headers: prefect/client/base.py
Option B: Split UI and API hostnames, protect only the UI with SSO
- What to do
- Expose two hostnames:
- ui.example.com → behind Cloudflare Access SSO
- api.example.com → available to workers (restrict via Cloudflare Access service token, IP allowlist, or Basic auth below)
- Tell the Prefect UI where the API lives:
# On the server
export PREFECT_UI_API_URL="<https://api.example.com/api>"
- If the UI and API are on different origins, enable CORS for your UI origin on the server:
export PREFECT_SERVER_CORS_ALLOWED_ORIGINS="<https://ui.example.com>"
- Why it works
- Humans use a protected UI origin; workers target the API origin directly
- References
- UI → API discovery endpoint: /ui-settings implementation
- CORS middleware and env vars: CORS setup
Alternative: Use Prefect’s built-in Basic Auth for the API
- If you’d rather have the API itself require credentials (instead of Cloudflare service tokens), enable Basic auth on the Prefect server and give the credentials to workers:
- On the server:
export PREFECT_SERVER_API_AUTH_STRING="username:strong-password"
- On workers:
export PREFECT_API_URL="<https://prefect.example.com/api>"
export PREFECT_API_AUTH_STRING="username:strong-password"
- The UI will prompt the browser for Basic credentials as needed.
- References
- Server-side Basic auth: server auth middleware
- Client-side support for Basic auth setting: prefect/settings/models/api.py
Nginx tips
- If you’re using Nginx auth in front of everything today, either:
- Remove Nginx auth for /api and let Cloudflare Access or Prefect Basic auth handle it; or
- Keep Nginx auth on /api and configure workers to send the appropriate Authorization header. With Prefect, prefer PREFECT_API_AUTH_STRING over custom headers for Basic.
- Make sure health/readiness endpoints can still be reached if you use probes. Prefect server exposes:
- /api/health
- /api/readyMarvin
12/25/2025, 9:06 PMexport PREFECT_API_SSL_CERT_FILE=/path/to/ca-bundle.crt
- If you’re fronted by Cloudflare with public certs, workers usually do not need custom trust.
- Prefect does not natively support mTLS client certificates via settings; prefer Cloudflare Access service tokens or Basic auth instead.
Which approach should you use?
- Easiest with Cloudflare: Option A (same domain, Cloudflare Access SSO for UI + service tokens for /api) using PREFECT_CLIENT_CUSTOM_HEADERS.
- Most isolation: Option B (split UI/API hostnames) with CORS and UI API URL configured.
If you can share:
- Your current domain layout (one hostname vs separate UI/API)
- Whether you prefer Cloudflare Access tokens or Basic auth for the API
- Any Nginx auth you want to keep
…I can suggest exact Nginx/Cloudflare policy snippets tailored to your setup.