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.
- 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.
docker run -d --name cpm \
-p 3001:3001 -p 80:80 -p 443:443 \
-v cpm-data:/data \
ghcr.io/pacerino/caddyproxymanagerThen 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_PASSWORD on 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.
┌──────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ 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.
All settings are environment variables prefixed with CPM_.
| 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). |
| 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. |
| 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). |
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 devOpen http://localhost:5173 and log in with admin@example.com / changeme.
cd frontend && npm run build # emits into backend/embed/assets
cd ../backend && go build ./cmd/main.gocd backend && go test ./... # backend
cd frontend && npm run build # frontend type-check + buildCI (.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.
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.
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.
- Log viewer
- Plugin management
- Per-host advanced directives
Inspired by the excellent Nginx Proxy Manager by jc21 — go check it out. CPM brings the same idea to Caddy.
Pull requests and issues are welcome! Please open an issue to discuss larger changes first.