Revive CPM: modern stack, Caddy API mode, OIDC, Docker & CI
Caddy Proxy Manager
A modern web interface for managing Caddy reverse proxy hosts.
Add, edit and delete proxy hosts from a clean UI — let Caddy handle TLS, HTTP/2, HSTS and automatic certificates for you.
Warning
This project is under active development and not yet considered stable. Use at your own risk and review the configuration before exposing it publicly.
✨ Features
- Host management — create, edit and delete hosts with multiple domains and upstream backends.
- Two ways to drive Caddy, switchable at runtime:
- 📝 Caddyfile mode (default) — renders a per-host Caddyfile snippet and reloads Caddy.
- 🔌 API mode — manages Caddy's JSON config through the admin API, one route per host, no reload required.
- Flexible authentication — local email/password or external OIDC/OAuth (Authelia, Keycloak, Authentik, …) with just-in-time user provisioning.
- Single binary — a modern SPA (Vite · React · TypeScript · Tailwind · shadcn/ui) embedded directly in the Go binary, or served from an external directory.
- Container-ready — multi-stage Docker image that bundles Caddy and starts everything for you.
🚀 Quick start (Docker)
docker run -d --name cpm \
-p 3001:3001 -p 80:80 -p 443:443 \
-v cpm-data:/data \
ghcr.io/pacerino/caddyproxymanager
Then open http://localhost:3001 and sign in with the default credentials:
| Password | |
|---|---|
admin@example.com |
changeme |
Important
Change the defaults via
CPM_ADMIN_EMAIL/CPM_ADMIN_PASSWORDon first run.
The container starts Caddy (with its admin API) and CPM in api mode. Mount your own Caddy config at /data/caddy.json to customise it.
🏗️ How it works
┌──────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ Browser │ ───► │ CPM (Go + embedded │ ───► │ Caddy │
│ (React SPA) │ │ React frontend) │ │ (reverse proxy) │
└──────────────┘ └──────────┬───────────┘ └─────────────────┘
│
Caddyfile mode │ writes host_<id>.conf + reload
API mode │ PUT/PATCH/DELETE via admin API
CPM stores hosts in a local SQLite database and applies each change to Caddy using the selected provider.
⚙️ Configuration
All settings are environment variables prefixed with CPM_.
Caddy
| Variable | Default | Description |
|---|---|---|
CPM_CADDY_MODE |
caddyfile |
Provider to use: caddyfile or api. |
CPM_CADDY_ADMINURL |
http://localhost:2019 |
Caddy admin API base URL (API mode + api reload). |
CPM_CADDY_SERVERNAME |
srv0 |
HTTP server name routes are managed under (API mode). |
CPM_CADDY_LISTEN |
:80,:443 |
Listen addresses for the bootstrapped server (API mode); use e.g. :8080 for local non-root testing. |
CPM_CADDY_RELOADSTRATEGY |
systemd |
Reload strategy (Caddyfile mode): systemd, exec, api or none. |
CPM_CADDY_BINARY |
caddy |
Caddy executable for the exec reload strategy. |
CPM_CADDY_SERVICE |
caddy.service |
systemd unit for the systemd reload strategy. |
CPM_CADDYFILE |
/etc/caddy/Caddyfile |
Main Caddyfile (used by exec/api reload). |
Authentication
| Variable | Default | Description |
|---|---|---|
CPM_AUTH_MODE |
local |
local or oidc. |
CPM_AUTH_OIDC_ISSUER |
— | OIDC issuer URL (e.g. Keycloak/Authelia). |
CPM_AUTH_OIDC_CLIENTID |
— | OIDC client ID. |
CPM_AUTH_OIDC_CLIENTSECRET |
— | OIDC client secret. |
CPM_AUTH_OIDC_REDIRECTURL |
— | Callback URL, e.g. https://cpm.example.com/api/auth/oidc/callback. |
CPM_AUTH_OIDC_SCOPES |
openid,profile,email |
Requested scopes. |
CPM_AUTH_OIDC_ALLOWEDDOMAINS |
— | Optional email-domain allowlist for JIT provisioning. |
General
| Variable | Default | Description |
|---|---|---|
CPM_DATAFOLDER |
/etc/caddy/ |
Data + per-host config folder. |
CPM_LOGFOLDER |
/var/log/caddy |
Per-host log folder. |
CPM_FRONTENDDIR |
— | Serve the frontend from this directory instead of the embedded assets. |
CPM_ADMIN_EMAIL |
admin@example.com |
Seed admin email (first run, local mode). |
CPM_ADMIN_PASSWORD |
changeme |
Seed admin password (first run, local mode). |
🧑💻 Development
Prerequisites: Go 1.24+, Node 22+, and a local Caddy for end-to-end testing.
Run the backend and frontend in two terminals:
# Terminal 1 — backend on :3001
cd backend
CPM_DATAFOLDER=./data CPM_LOGFOLDER=./data CPM_CADDY_RELOADSTRATEGY=none \
go run ./cmd/main.go
# Terminal 2 — frontend dev server on :5173 (proxies /api → :3001)
cd frontend
npm install
npm run dev
Open http://localhost:5173 and log in with admin@example.com / changeme.
Building a single binary
cd frontend && npm run build # emits into backend/embed/assets
cd ../backend && go build ./cmd/main.go
Testing
cd backend && go test ./... # backend
cd frontend && npm run build # frontend type-check + build
CI (.github/workflows/ci.yml) runs the backend tests, builds the frontend, and publishes the Docker image to GHCR on pushes to master and version tags.
🐳 Building the image yourself
docker build -t caddyproxymanager .
The multi-stage build compiles the frontend and backend (a pure-Go build, no C toolchain required) into a small Alpine runtime that bundles Caddy.
❓ FAQ
Should I use Caddyfile mode or API mode?
Use Caddyfile mode (the default) for the simplest setup — CPM writes snippets that Caddy imports, and you keep all of Caddy's conveniences (automatic HTTPS, HSTS, HTTP/2). Use API mode when you want CPM to manage Caddy's live JSON config directly through the admin API, with no reloads.
Can I use external SSO (Authelia, Keycloak, Authentik …)?
Yes. Set CPM_AUTH_MODE=oidc and configure the CPM_AUTH_OIDC_* variables. On first successful login CPM provisions the matching user automatically (JIT). Restrict access with CPM_AUTH_OIDC_ALLOWEDDOMAINS.
Does CPM run Caddy for me?
The Docker image does — its entrypoint launches Caddy with the admin API and then CPM. For bare-metal installs, run Caddy yourself and point CPM at it (CPM_CADDYFILE / CPM_CADDY_ADMINURL) with the appropriate reload strategy.
🗺️ Roadmap
- Log viewer
- Plugin management
- Per-host advanced directives
🙌 Acknowledgements
Inspired by the excellent Nginx Proxy Manager by jc21 — go check it out. CPM brings the same idea to Caddy.
🤝 Contributing
Pull requests and issues are welcome! Please open an issue to discuss larger changes first.