-
Notifications
You must be signed in to change notification settings - Fork 15
Development and Releases
cmd/caddyui/ entry point, env config, start-up, migrate-db command
internal/
auth/ sessions, password hashing, TOTP
caddy/ admin API client, Caddyfile adapter/parser, importer, config rendering
db/ SQLite/MariaDB init, schema migrations, data migration
dns/ DNS providers, one file each, registered through a descriptor
models/ data types and queries
server/ HTTP handlers, routes, sync, notifiers, health poller, background workers
web/
templates/ Go html/template pages (embedded)
static/ CSS, icons, PWA manifest and service worker (embedded)
packaging/systemd/ sample unit for the binary install
Dockerfile scratch-based CaddyUI image, non-root uid 10001
Dockerfile.caddy Caddy with every supported DNS provider and the CrowdSec bouncer
CaddyUI keeps its state in SQLite or MariaDB and talks to Caddy only through the HTTP admin API: no SSH, no editing of Caddy's files. Everything the browser needs is embedded in the binary, so there are no runtime downloads.
Go 1.26 or newer.
git clone https://github.com/X4Applegate/caddyui.git
cd caddyui
git checkout "$(git tag --sort=-v:refname | head -n1)"
version="$(git describe --tags --always --dirty)"
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.Version=${version}" -o caddyui ./cmd/caddyuiRun it against a local Caddy:
mkdir -p ./data
CADDYUI_DB="$PWD/data/caddyui.db" \
CADDYUI_LISTEN=127.0.0.1:8080 \
CADDY_ADMIN_URL=http://127.0.0.1:2019 \
CADDYUI_INGEST_LISTEN=127.0.0.1:9019 \
./caddyuiInstall as a service with the sample unit:
id -u caddyui >/dev/null 2>&1 || sudo useradd --system --home /var/lib/caddyui --shell /usr/sbin/nologin caddyui
sudo install -d -o caddyui -g caddyui -m 0750 /var/lib/caddyui
sudo install -m 0755 caddyui /usr/local/bin/caddyui
sudo install -m 0644 packaging/systemd/caddyui.service /etc/systemd/system/caddyui.service
sudo systemctl daemon-reload
sudo systemctl enable --now caddyuiDocker image:
docker build --build-arg VERSION=v2.45.2 -t caddyui:v2.45.2 .The VERSION build argument stamps main.Version, which the sidebar shows and the update check compares against Docker Hub. The repository compose file builds locally with CADDYUI_VERSION=vX.Y.Z docker compose up -d --build; without it the UI shows dev.
gofmt -l . # CI fails on unformatted files
go vet ./...
go test ./...Opt-in integration tests run against a real Caddy or MariaDB when these are set:
CADDYUI_TEST_CADDY_ADMIN=http://127.0.0.1:2019 go test ./internal/caddy/... ./internal/server/...
CADDYUI_TEST_MARIADB_DSN='caddyui:pw@tcp(127.0.0.1:3306)/caddyui_test' go test ./internal/db/... ./internal/models/...A throwaway Caddy for the first one: docker run --rm -p 127.0.0.1:2019:2019 -e CADDY_ADMIN=0.0.0.0:2019 caddy:2-alpine.
Every pull request runs:
- Go build and test on SQLite, plus the MariaDB integration job against a service container.
- gofmt check.
- CodeQL static analysis (its path-injection findings are why typed file paths go through the vetting helpers).
-
Claude code review — an automatic review comment on every non-draft, non-Dependabot pull request, using the maintainer's Claude subscription through a repository secret. Mention
@claudein an issue or PR comment to ask questions or request follow-up changes. Both jobs skip themselves in forks without the secret.
release-binaries.yml runs on tags and attaches the linux/amd64 and linux/arm64 tarballs with the systemd unit and installer to the GitHub release.
Read CONTRIBUTING.md. In short: open an issue or discussion first for anything larger than a fix, keep pull requests focused, add a CHANGELOG entry under a new version heading, make sure gofmt is clean and go build ./... and go test ./... pass, and expect the Claude review comment to be read as seriously as a human one. Bug reports are triaged by the maintainer with Claude's assistance; no credentials or database contents are ever shared with it.
Adding a DNS provider: implement the provider interface in internal/dns/, register a descriptor with its credential fields, add the Caddy module to Dockerfile.caddy, map the credentials to the module's JSON in the server's provider config switch, and add a docs section. The Gandi provider (v2.45.0) with its fake-API test is the template.
- Merge the pull request (squash). CI must be green.
- Bump nothing in code: the version comes from the tag. Create an annotated tag
vX.Y.Zonmainwith the CHANGELOG subject as message and push it. - The release workflow publishes the binaries. The Docker image is built from the tag with
--build-arg VERSION=vX.Y.Zand pushed to Docker Hub asapplegater/caddyui:vX.Y.Z,:latestand:stable, all pointing at the same digest. - The Operations dashboard of running installs announces the new version.
Versioning follows semver: a patch for fixes, a minor for features, and the CHANGELOG entry per version is the release note.
CaddyUI Source Available License 1.0: free for personal use, non-profits, education, small businesses and internal use in any organisation; a commercial licence is required to offer CaddyUI as a hosted or managed service.
CaddyUI · Changelog · Docker Hub · Report an issue — never expose Caddy's admin port 2019 to the internet.
Getting started
Routing
Operations
Integrations
Help