caddyserver/caddy
Getting started
This page covers building Caddy from source, running it, and writing a first Caddyfile. The canonical user-facing docs live at caddyserver.com/docs — the goal here is to get you running locally so you can hack on the codebase.
Prerequisites
- Go 1.25.0 or newer. The repo's
go.modpinsgo 1.25.0. CI runs against Go 1.26 (.github/workflows/ci.yml). golangci-lintfor linting (.golangci.ymlconfigures the rules; CI usesgolangci-lint run --timeout 10m).xcaddyis optional but required to embed plugins or to build with proper version metadata. Seehttps://github.com/caddyserver/xcaddy.
Build the binary
git clone https://github.com/caddyserver/caddy.git
cd caddy/cmd/caddy
go buildThat produces a caddy binary in cmd/caddy/. The CI pipeline uses the same path with extra flags:
cd cmd/caddy
CGO_ENABLED=0 go build -trimpath -ldflags="-w -s" -vIf you want plugin support and accurate version strings, use xcaddy build instead. Internally xcaddy writes a tiny main.go that imports plugins and runs go build.
Bind to low ports (Linux)
If you run Caddy as a non-root user on Linux and bind to ports 80/443, you need the cap_net_bind_service capability:
sudo setcap cap_net_bind_service=+ep ./caddyFor go run workflows, the repo includes a helper at cmd/caddy/setcap.sh:
go run -exec ./setcap.sh main.goRun a hello-world site
Save this as Caddyfile:
:8080
respond "hello, world"Then run:
./caddy run --config Caddyfile
curl -i http://localhost:8080/You should see hello, world. Behind the scenes, caddy run (cmd/commands.go) loads the file, runs it through the caddyfile adapter (caddyconfig/httpcaddyfile/), POSTs the resulting JSON to the local admin endpoint via caddy.Load, and starts the http app.
Inspect the generated JSON
./caddy adapt --config Caddyfile --prettycaddy adapt invokes the named adapter and prints the JSON document Caddy would actually run. This is the single best learning tool: every Caddyfile concept reduces to JSON.
Reload without restarting
./caddy reload --config Caddyfilecaddy reload re-reads the config file and posts it to the admin API (/load). Caddy provisions the new config, swaps it in under a mutex, and rolls back if anything fails (Load in caddy.go).
You can do the same thing manually:
curl -X POST -H "Content-Type: application/json" \
--data-binary @config.json \
http://localhost:2019/loadRun the test suite
The repo's quality gates are:
# Unit tests with the race detector (matches CI)
go test -race -short ./...
# Integration tests
go test ./caddytest/integration/...
# Lint
golangci-lint run --timeout 10mThe integration harness lives in caddytest/caddytest.go. Tests pull non-default ports (9080, 9443, 2999) so they do not conflict with a real Caddy you may have running.
Where to look next
- Architecture — the request lifecycle and module model
- Glossary — vocabulary
- Development workflow — branching, PR style, AI-assisted code policy
- Testing — table-driven tests, the
caddytest.Testerhelper - Caddyfile — directives, ordering, and how it converts to JSON
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.