feat: add Caddy web server provider#4534
Conversation
|
Related Knowledge 1 document with suggested updates is ready for review. Dokploy's Space README
|
46a438e to
7baf056
Compare
|
Architecture RFC for this PR (comparison with the label-driven approach, production evidence, and a proposed stacked split so nobody has to review 27.8k lines at once): #4615 — a commit regroup and a review-map description update for this PR are coming shortly to make it tractable. |
…o behavior change)
8a4292f to
0dcc5f9
Compare
…validate Caddy's Server.trusted_proxies_strict JSON field is an int; the compiler emitted a JSON boolean, so `caddy validate` rejected any config with strict trusted proxies enabled. Found in production on 2026-06-10. Emit 1 when strict; keep omitting the field otherwise.
Resolves conflicts with 16 upstream commits, notably: - Renumber caddy migration 0172_parched_ares -> 0173_cool_vargas (upstream 0172_quick_the_professor from concurrent deployments Dokploy#4645 is canonical); regenerated snapshot on top of upstream's, restored idempotent DDL so hosts that applied the old identity no-op cleanly - Adopt dynamic traefik container resolution in access-log cleanup (Dokploy#4646) within the provider-aware handler - Accept admin-tools refactor (Dokploy#4625): traefik file-system modal is deleted; /dashboard/traefik page with ServerFilter is now the entry point and is cloud-enabled, ShowTraefikSystem stays provider-aware with a provider-aware empty state path - Fold buildsConcurrency (server + webServerSettings) alongside caddy provider columns in db schema - Tailwind v4 class renames (shadow-xs, h-140) applied to our provider-aware components, keeping caddy language switch and pointer-events-none read-only overlay fix Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Upstream's concurrent deployments (Dokploy#4645) allow builds to finish simultaneously. The active caddy.json is compiled from the fragments directory, so an unsynchronized read-compile-write could publish a config missing a concurrently written fragment, and the rm-rf-based restoreCaddyRouteFragments rollback could delete another deployment's fragment outright. Add a per-server promise-chain lock; the public compile+reload entry takes it, and the fragment read-modify-write flows (application domains, compose domains, dashboard route) hold it across their full capture-mutate-compile-rollback sequences. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mechanical move of the 20 provider/web-server/caddy-migration procedures plus their input schemas and helpers from settings.ts into web-server.ts, spread back into settingsRouter so client api.settings.* paths and existing tests are unchanged. settings.ts now carries only the in-place provider-awareness edits to upstream procedures, which keeps its diff against canary reviewable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
getActiveWebServerProvider was adminProcedure, but it is consumed by member-visible surfaces: domain forms, application traefik/caddy config views, and the web-server files page (cloud-enabled by the admin-tools refactor Dokploy#4625 and gated only by traefikFiles.read). For non-admin members the query returned FORBIDDEN, so provider resolution failed and those surfaces silently degraded (e.g. traefik-only fields shown on caddy installs, file editor locked). getWebServerSettings, a superset of this data, is already protectedProcedure; ensureServerAccess keeps remote-server lookups scoped to the caller's organization. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Apply the shadow-xs rename from the tailwind v4 migration (Dokploy#4706) to the caddy components it could not have touched, and biome-format the provider-aware empty state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Merged
Validation on the merged branch: both typechecks clean; 758 tests passed / 1 skipped, with only the 4 known environment-dependent |
Summary
Adds Caddy as an opt-in web-server provider alongside Traefik. Traefik remains the default and is untouched unless a user explicitly runs the guarded migration.
Related: #1246 (feature request). RFC with architecture comparison: #4615.
Review map — where the +27.7k actually is
web-server-settings.ts/server.ts)Real-source hotspots, largest first:
packages/server/src/utils/caddy/config.ts(+1,151) — Caddy JSON compilation + per-server config write lockpackages/server/src/utils/caddy/migration/(~4,300 across prepare/apply/rollback/translators/preflight/files/types)apps/dokploy/server/api/routers/web-server.ts(+839) — all provider/web-server/caddy-migration endpoints, extracted fromsettings.ts(thewebServerRouterextraction previously flagged here is done; procedures are spread intosettingsRouter, so clientapi.settings.*paths are unchanged)apps/dokploy/server/api/routers/settings.ts(+88/−26) — only in-place provider-awareness edits to existing procedurespackages/server/src/utils/caddy/{domain,compose,web-server,types}.ts(~600) — route generationpackages/server/src/setup/caddy-setup.ts(+332)services/settings.ts,services/web-server-settings.ts,services/domain.ts,utils/docker/domain.ts, db schema/validationscomponents/dashboard/settings/web-server/*(migration panel, provider selector, trusted proxies, env editor),domains/handle-domain.tsx,show-traefik-*made provider-awareutils/access-log/{utils,handler}.tsSafety model
withCaddyConfigLock), so concurrent deployments (Feat/concurrent deployments in memory queue #4645) cannot publish a config missing a concurrently written route or roll back another deployment's fragmentgetActiveWebServerProviderisprotectedProcedure(org-scoped via server access check): member-visible surfaces (domain forms, the web-server files page) need the provider name to render the right fields — precedent isgetWebServerSettings, which is already protectedMerged with canary — 2026-07-03
Conflicts with the last 16 canary commits are resolved; notable decisions:
0172_quick_the_professor(buildsConcurrency) is canonical; the caddy migration is regenerated on top of it as0173_cool_vargaswith idempotent DDL (guarded enum create,ADD COLUMN IF NOT EXISTS), so hosts that applied it under the previous number re-run it as a no-op/dashboard/traefik+ServerFilteris the entry point (cloud included).ShowTraefikSystemresolves the provider itself and the new empty state shows the provider-correct pathValidation
Fresh run on the merged branch (2026-07-03):
pnpm --filter=@dokploy/server typecheck— clean (tsc --noEmit)pnpm --filter=dokploy typecheck— clean (tsc --noEmit)pnpm --filter dokploy run test— 85/86 test files pass: 758 passed, 1 skipped, 4 failed. All 4 failures are in__test__/deploy/application.real.test.ts("REAL Execution" tests that require the local Docker daemon to be a swarm manager) — environment-dependent and unrelated to this PR; every caddy/db/traefik suite passes