github fuomag9/caddy-proxy-manager v1.12.0

6 hours ago

Highlights

Generic forward auth (#188)

Proxy hosts can now use a generic forward-auth provider (Authelia preset or fully custom) alongside the existing Authentik integration and the built-in CPM portal, with the split browser vs API pattern for mixed UI + API services:

  • Browser requests (Accept: text/html, no X-Requested-With) keep the auth server's portal-redirect flow — 302s pass through so users get the normal login experience.
  • API split mode: with api_split enabled, API clients and WebSocket handshakes get a bare 401 instead of an HTML login page mid-stream — a second route converts any 3xx from the auth server into a static 401.
  • Bypass headers (e.g. X-Api-Key) let requests skip forward auth entirely so the upstream can enforce its own API-key auth (the Moonraker/Spoolman case), replacing hand-written customPreHandlersJson subroutes.

Security hardening: identity headers the auth server returns (Remote-User, Remote-Groups, …) are stripped from inbound requests on every route of the host — protected or not — preventing identity spoofing to the upstream (same class of fix as the X-CPM-* stripping). Header names are validated against the RFC 7230 token grammar, placeholders are stripped from endpoints and paths, and enabled-but-invalid configs are rejected at write time so a host can never silently publish unprotected.

Surface: forwardAuth field on proxy hosts, Settings > Forward Auth Defaults (synced to slave instances), /api/v1/settings/forward-auth API group, and the OpenAPI ForwardAuthConfig schema. Tested with 14 functional e2e tests against real Caddy via a mock Authelia container (browser 302 / API 401 / WS 401 / bypass / forged-header stripping) plus real Authelia and real Moonraker integration tests.

L4 hosts can no longer bind reserved ports 80/443/2019 (#295)

An L4 host listening on :443 (or :80) while regular HTTPS proxy hosts exist made CPM generate two independent listeners on the same port. Caddy sets SO_REUSEPORT on every listener, so the second bind succeeded silently — and the kernel then split new connections between the two sockets, failing ~50% of TLS handshakes with tlsv1 alert internal error (reported and confirmed at kernel level in #295). Two independent HTTP and layer4 servers sharing port 443 is not supported by Caddy (the caddy-l4 docs require listener wrappers for that), so CPM now refuses the invalid configuration instead of generating it:

  • L4 listen addresses on ports 80, 443 and 2019 are rejected on create and update — in the UI, the REST API and server actions — with the reserved ports named in the error.
  • Instance sync rejects synced L4 hosts on reserved ports, so a replica can't inherit the broken config.
  • Config generation and the L4 port manager skip legacy rows already on a reserved port and log a warning, so an existing bad row can't poison :443 for every other host until it's fixed.
  • The create/edit dialog documents the reservation; the wiki no longer describes the TLS SNI example as "on port 443" and gained a troubleshooting entry.

If you have an existing L4 host on :443, move it to a different listen port (e.g. :8443) — SNI matching and passthrough behave the same, and "Apply Port Changes" publishes the new mapping.

Caddy monitor: config drift detected by content

The monitor's restart detection compared the live config ID against a literal "empty" marker — but Caddy always serves an ETag, so the marker was unreachable and no configuration re-push ever happened after the l4-port-manager recreated the caddy container, leaving it unconfigured until something else pushed config. Every successful applyCaddyConfig() now records the sha256 of the config Caddy is actually serving, and the monitor re-pushes whenever the live hash differs — catching empty configs, the image's default Caddyfile, and stale autosaves alike.

Maintenance

  • Caddy: bump otlptracegrpc/otlptracehttp to 1.46.0 and the otel/log 0.21.0 line so the tree compiles against otel core 1.46.0 (#284, #285#288).
  • Bump TypeScript 5.9.3 → 7.0.2 (#293), 9 production (#292) and 4 development (#291) dependency updates.
  • e2e: real Authelia and real Moonraker integration tests for the generic forward-auth provider.
  • Repo cleanup: the forward-auth security analysis moved out of the repository (docs/ is now gitignored).

Changes

  • e5e7f00 fix(l4): reject reserved listen ports 80/443/2019 for L4 proxy hosts (#295)
  • 93b05fd deps(deps-dev): bump typescript from 5.9.3 to 7.0.2 (#293)
  • f0bd0f0 deps(deps): bump the production-dependencies group with 9 updates (#292)
  • 3b2a595 deps(deps-dev): bump the development-dependencies group with 4 updates (#291)
  • 286de86 caddy: bump otel exporters to match merged otel 1.46.0 core (#285-#288)
  • 9d75485 chore: remove security analysis from repo and ignore docs/
  • c8a360b test(e2e): add real Authelia and real Moonraker integration tests for generic forward auth
  • 7b6a1d1 feat(forward-auth): add generic forward-auth provider with split browser vs API auth (#188)
  • 255ab49 caddy: bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc (#284)
  • 3dbb3b8 fix(caddy-monitor): detect config drift by content, not an unreachable sentinel

Full Changelog: v1.11.3...v1.12.0

Don't miss a new caddy-proxy-manager release

NewReleases is sending notifications on new releases.