# Caddy Proxy Manager
**A modern web interface for managing [Caddy](https://caddyserver.com/) 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.
[](https://github.com/Pacerino/CaddyProxyManager/actions/workflows/ci.yml)




---
> [!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)
```bash
docker run -d --name cpm \
-p 3001:3001 -p 80:80 -p 443:443 \
-v cpm-data:/data \
ghcr.io/pacerino/caddyproxymanager
```
Then open and sign in with the default credentials:
| Email | 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.
## ποΈ How it works
```
ββββββββββββββββ ββββββββββββββββββββββββ βββββββββββββββββββ
β Browser β ββββΊ β CPM (Go + embedded β ββββΊ β Caddy β
β (React SPA) β β React frontend) β β (reverse proxy) β
ββββββββββββββββ ββββββββββββ¬ββββββββββββ βββββββββββββββββββ
β
Caddyfile mode β writes host_.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](https://caddyserver.com/docs/install) for end-to-end testing.
Run the backend and frontend in two terminals:
```bash
# 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 and log in with `admin@example.com` / `changeme`.
### Building a single binary
```bash
cd frontend && npm run build # emits into backend/embed/assets
cd ../backend && go build ./cmd/main.go
```
### Testing
```bash
cd backend && go test ./... # backend
cd frontend && npm run build # frontend type-check + build
```
CI ([`.github/workflows/ci.yml`](.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
```bash
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](https://github.com/NginxProxyManager/nginx-proxy-manager) by [jc21](https://github.com/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.
## π License
[MIT](LICENSE)