Skip to content

feat(cloudflare): Cloudflare Access (zero-trust) for published domains#4530

Closed
maxsam4 wants to merge 3 commits into
Dokploy:canaryfrom
maxsam4:cf-zero-trust
Closed

feat(cloudflare): Cloudflare Access (zero-trust) for published domains#4530
maxsam4 wants to merge 3 commits into
Dokploy:canaryfrom
maxsam4:cf-zero-trust

Conversation

@maxsam4
Copy link
Copy Markdown

@maxsam4 maxsam4 commented Jun 1, 2026

What is this PR about?

Part 3 of 3 of a native Cloudflare integration (builds on #4529). Optionally places a published domain behind Cloudflare Access (Zero Trust) — a login gate with no auth code in the app itself.

  • Per-domain Access: a self_hosted Access application + allow policy (email / email_domain include rules), with a configurable session duration. Idempotent create/update/delete across the domain lifecycle (incl. cascade deletes). Admin-gated, audit-logged.
  • Org defaults & policy (admin): a default session duration (defaults to 1 week) and default allowed identities; "protect new domains by default"; "require all domains to be protected" (members must end up protected; owners/admins keep an unprotected escape hatch).
  • Safety: a lockout guard (won't enable protection with no default identity), fail-closed integration selection (a transient Cloudflare API error can't silently downgrade a require-protected domain), and an update pre-flight that validates a new target before tearing down the old route. Migration 0172. Tested.

Stacked PR

Stack: #4528 -> #4529 (Tunnel, Closes #4309) -> this PR. GitHub PRs must target canary, so this diff re-includes #4528/#4529 until they merge — please review per-commit and merge last.

Checklist

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file.
  • You have tested this PR in your local instance. Verified locally (server + app typecheck, Biome, full Cloudflare + domain + permissions suites) and end-to-end on a live Docker-Swarm instance: protected a domain (confirmed the Access login redirect), exercised org defaults, protect-by-default and require-protected (member auto-protected, admin override), the lockout guard, and clean teardown.

Issues related (if applicable)

Closes #4515

maxsam4 and others added 3 commits June 1, 2026 12:00
Adds an organization-scoped Cloudflare integration: a settings page to
store a scoped API token + account ID (plus optional default zone/tunnel),
a "Test connection" action, and full CRUD.

All procedures are admin-gated (adminProcedure, not withPermission —
`cloudflare` is an enterprise-only resource whose checkPermission bypass
would otherwise grant members). The API token is redacted from every
response and never logged, the account id is URL-encoded and inputs are
trimmed, and every mutation is written to the audit log (with the
audit-log UI label/filter wired up for the new resource type).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes Dokploy#4309

Lets a domain be published through Cloudflare Tunnel instead of (or
alongside) direct Traefik exposure, in two modes: a Dokploy-managed
"shared" tunnel with an auto-deployed cloudflared connector, or an
existing remotely-managed tunnel.

Provisioning upserts a per-host ingress rule (preserving any unknown
rules and keeping the catch-all last) plus a proxied, Dokploy-tagged
CNAME, and is idempotent with compensating cleanup on partial failure.
The web->websecure redirect is suppressed for published domains, which
terminate TLS at the Cloudflare edge and reach Traefik over plain HTTP.

Cloudflare state is torn down before the domain row is removed on every
path — single delete, application/compose/project cascade, and compose
import — with shared tunnels/connectors reaped only once their last route
is gone. The connector token is mounted as a read-only file (never in
`docker inspect`, never persisted to the DB or logged). Account/zone/
tunnel id path segments are URL-encoded, all publishing is owner/admin-
gated, and the selected integration is verified to belong to the caller's
organization.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds optional Cloudflare Access protection for a Cloudflare-published
domain: a self-hosted Access application with an allow policy built from
email and email-domain include rules, configured from a per-domain editor
in the dashboard.

Provisioning is idempotent with compensating cleanup, admin-gated, and
scoped to the caller's organization; account/app/policy id path segments
are URL-encoded and the session duration is format-validated. Access is
torn down before the domain row is deleted (including the cascade paths),
and is re-pointed when a published domain's host/tunnel/integration
changes so a protected domain stays protected across target changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maxsam4
Copy link
Copy Markdown
Author

maxsam4 commented Jun 1, 2026

Superseded by #4532 — rebased onto the latest canary (migration renumbered to 0172) and trimmed to pass the PR-quality checks. This one was auto-closed by the quality bot before the rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Native Cloudflare Access (Zero Trust) for published domains [Feature] Native Cloudflare Tunnel integration for domain publishing

1 participant