Skip to content

feat: add Caddy web server provider#4534

Open
masonjames wants to merge 21 commits into
Dokploy:canaryfrom
masonjames:codex/caddy-web-server-v0296-clean-pr
Open

feat: add Caddy web server provider#4534
masonjames wants to merge 21 commits into
Dokploy:canaryfrom
masonjames:codex/caddy-web-server-v0296-clean-pr

Conversation

@masonjames

@masonjames masonjames commented Jun 1, 2026

Copy link
Copy Markdown

Summary

Adds Caddy as an opt-in web-server provider alongside Traefik. Traefik remains the default and is unchanged unless an administrator completes the guarded migration.

  • Provider-neutral web-server settings, health, file views, domains, and Compose/application routing
  • Deterministic Caddy JSON generation for dashboard, application, Compose, preview, certificate, and domain flows
  • Guarded Traefik to Caddy migration with dry-run artifacts, live upstream preflight, apply, rollback, and fail-closed recovery
  • Provider selection, migration, trusted-proxy, request-log, and analytics UI
  • Fail-closed runtime Drizzle migration handling

Related: #1246. Architecture RFC: #4615.

Review map

The largest files are generated Drizzle snapshots and test fixtures. The main review surfaces are:

  • packages/server/src/utils/caddy/config.ts - fragment store, deterministic compilation, config locking, validation, reload, and filtered access logs
  • packages/server/src/utils/caddy/migration/ - preparation, translators, runtime preflight, apply, rollback, and durable artifacts
  • packages/server/src/setup/caddy-setup.ts - standalone and Swarm lifecycle, immutable image support, candidate validation, convergence, and rollback
  • apps/dokploy/server/api/routers/web-server.ts - provider, settings, request-log, health, and migration endpoints
  • packages/server/src/services/settings.ts - provider-aware setup and verified network attachment
  • components/dashboard/settings/web-server/ - opt-in migration and provider controls

Safety model

  • Traefik stays the default; direct provider switching is blocked outside migration and rollback flows.
  • Migration apply requires prepared artifacts, active-upstream reachability, supported route translation, and conflict-free output.
  • Fragment read/modify/write and compile/reload sequences are serialized per server.
  • CADDY_IMAGE accepts a full digest-pinned reference; the default remains caddy:2.11.4.
  • Caddy candidates are pulled, inspected, config-validated, and upstream-preflighted before the running edge is touched.
  • Standalone replacement retains the previous container under a rollback name. Candidate creation, start, config, network, reconnect, or upstream failures restore the prior config and edge.
  • Swarm replacement preserves existing networks, waits for the expected image, uses Docker rollback policy, and restores the prior service spec on failure.
  • Request logs delete X-Api-Key, remove query strings, and redact application/Compose deploy credentials before persistence.
  • The request-log setting reloads Caddy transactionally; validation or reload failure restores the previous config.
  • Unsupported BasicAuth hashes and unsafe/manual route conflicts block migration instead of being silently degraded.

Current canary integration

Merged through 2e867c5be1fa3c136d0d3f738f0c0d39e1d4de6e on 2026-07-12.

  • Upstream environment encryption and web-server backup-key support remain canonical at 0174_great_naoko.
  • The Caddy schema migration was regenerated on top as 0175_nebulous_nightshade.
  • The Caddy DDL remains idempotent so installations that tested the earlier migration number safely treat the renumbered migration as a no-op.
  • The journal now has 176 unique, ordered indexes and tags; its tail is 0174_great_naoko, 0175_nebulous_nightshade.

Validation - 2026-07-12

  • pnpm install --frozen-lockfile
  • pnpm --filter=@dokploy/server typecheck - passed
  • pnpm --filter=dokploy typecheck - passed
  • pnpm --filter=dokploy test --run __test__/caddy - 29 files, 215 tests passed
  • pnpm --filter=dokploy test --run __test__/env/encryption.test.ts - 10 tests passed
  • Biome check on every updated Caddy source/test file - passed
  • Migration journal uniqueness, ordering, and 0174 to 0175 lineage - passed

Production evidence

The Caddy path is running on a two-node Swarm with Caddy 2.11.4. The current production candidate passed signed immutable-image verification, schema preflight, guarded promotion, container health, all 17 cataloged public routes, and the authenticated 15/15 platform health profile. Privacy canaries confirmed that API keys, query strings, and deploy credentials do not persist in request logs.

The production failures that informed the final hardening are covered by failure-injection tests: pull failure leaves the current edge untouched; creation/start/reconnect/network/config/upstream failures restore it; Swarm update failure restores the prior service specification.

@masonjames masonjames requested a review from Siumauricio as a code owner June 1, 2026 23:07
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jun 1, 2026
@masonjames masonjames marked this pull request as draft June 1, 2026 23:08
@masonjames masonjames marked this pull request as ready for review June 1, 2026 23:10
@dosubot

dosubot Bot commented Jun 1, 2026

Copy link
Copy Markdown

Related Knowledge

1 document with suggested updates is ready for review.

Dokploy's Space

README /dokploy/blob/canary/README.md — ⏳ Awaiting Merge

How did I do? Any feedback?  Join Discord

@masonjames masonjames force-pushed the codex/caddy-web-server-v0296-clean-pr branch from 46a438e to 7baf056 Compare June 2, 2026 10:40
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Jun 2, 2026
@masonjames masonjames mentioned this pull request Jun 2, 2026
@masonjames

Copy link
Copy Markdown
Author

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.

@masonjames masonjames force-pushed the codex/caddy-web-server-v0296-clean-pr branch from 8a4292f to 0dcc5f9 Compare June 10, 2026 23:17
masonjames and others added 7 commits June 10, 2026 19:31
…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>
@masonjames

Copy link
Copy Markdown
Author

Merged canary (through 91abc93) and resolved all conflicts — the PR is mergeable again. Notable updates beyond the merge itself:

  • Migration renumbered to 0173_cool_vargas: canary's 0172_quick_the_professor (Feat/concurrent deployments in memory queue #4645) keeps its number; ours is regenerated on top of its snapshot with idempotent DDL
  • Per-server Caddy config write lock: with concurrent deployments (Feat/concurrent deployments in memory queue #4645), the fragment read-compile-write and the snapshot-based rollback could race; all such sequences now hold withCaddyConfigLock (covered by new tests)
  • webServerRouter extraction done: the 20 provider/migration endpoints moved to server/api/routers/web-server.ts and are spread into settingsRouter, so api.settings.* paths are unchanged — settings.ts now diffs at +88/−26 against canary
  • Adopted refactor: unify server admin tools into dashboard pages with server selector #4625: file-system modal removed in favor of the cloud-enabled /dashboard/traefik page; the component resolves the active provider itself
  • getActiveWebServerProvider is now protectedProcedure (org-scoped) since member-visible surfaces consume it

Validation on the merged branch: both typechecks clean; 758 tests passed / 1 skipped, with only the 4 known environment-dependent application.real.test.ts failures (require a swarm-manager Docker daemon). PR description refreshed with the updated review map.

masonjames and others added 6 commits July 7, 2026 08:54
# Conflicts:
#	apps/dokploy/drizzle/meta/0173_snapshot.json
#	apps/dokploy/drizzle/meta/_journal.json
…12-refresh

# Conflicts:
#	apps/dokploy/drizzle/meta/0174_snapshot.json
#	apps/dokploy/drizzle/meta/_journal.json
@masonjames

Copy link
Copy Markdown
Author

Updated this branch against current canary (2e867c5be) and refreshed the PR description.

New in the latest push:

  • resolved the migration collision without rewriting history: upstream encryption remains 0174_great_naoko; Caddy is regenerated as idempotent 0175_nebulous_nightshade;
  • added digest-pinned CADDY_IMAGE support and pull/inspect/config/upstream validation before replacement;
  • retained and automatically restored the previous standalone edge on candidate failure;
  • added Swarm convergence checks, rollback policy, network preservation, and prior-spec restoration;
  • redacted deploy credentials, X-Api-Key, and query strings from persisted Caddy request logs;
  • made the request-log toggle perform a transactional Caddy reload.

Fresh validation: both typechecks pass; the complete Caddy suite passes (29 files, 215 tests); the merged encryption suite passes (10 tests); Biome passes on the updated source/test files; migration indexes/tags are unique and ordered.

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:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant