caddyserver/caddy
HTTP
The http app is Caddy's HTTP/1.1, HTTP/2, and HTTP/3 server. Module ID http, defined in modules/caddyhttp/app.go.
Purpose
Run one or more HTTP Server instances, each with its own listeners, TLS connection policies, route list, and middleware chain. Wire those servers into Caddy's automatic-HTTPS pipeline so any host name appearing in a host matcher gets a managed certificate by default.
Directory layout
| Path | Role |
|---|---|
modules/caddyhttp/app.go |
The App type (registered as module http), Start, Stop, server provisioning |
modules/caddyhttp/server.go |
The Server type and its ServeHTTP method (~41 KB) |
modules/caddyhttp/routes.go |
Route, RouteList, route compilation into a middleware chain |
modules/caddyhttp/matchers.go |
Built-in matchers: host, path, method, header, etc. (~54 KB) |
modules/caddyhttp/celmatcher.go |
CEL expression-based matchers (expression {…}) |
modules/caddyhttp/autohttps.go |
Inferring which hostnames need certificates and pushing them to the tls app |
modules/caddyhttp/replacer.go |
HTTP-specific placeholders ({http.request.uri.path}, etc.) |
modules/caddyhttp/responsewriter.go |
Custom http.ResponseWriter wrapper |
modules/caddyhttp/metrics.go |
Prometheus metrics for HTTP server |
modules/caddyhttp/standard/imports.go |
Side-effect imports of bundled handlers, matchers, encoders |
modules/caddyhttp/<subdir>/ |
Bundled handlers (file_server, reverse_proxy, headers, encode, …) |
Key abstractions
| Type | Where | Description |
|---|---|---|
App |
app.go |
Top-level module; holds servers, idle/read timeouts, HTTP/HTTPS port defaults |
Server |
server.go |
One bound listener-group + routes + connection policies |
Route |
routes.go |
A list of matchers + a list of handlers + (optional) terminal flag |
RouteList |
routes.go |
Slice of Route; compiles to a middleware chain |
Handler |
caddyhttp.go |
ServeHTTP(w, r) error — error-returning HTTP handler |
MiddlewareHandler |
caddyhttp.go |
Handler that takes the next handler as a parameter |
RequestMatcher / RequestMatcherWithError |
caddyhttp.go |
Predicate over *http.Request; the …WithError form is the modern interface, the original is deprecated |
Subroute |
subroute.go |
Handler that recursively embeds another RouteList |
StaticResponse |
staticresp.go |
The respond directive's underlying handler |
StaticError |
staticerror.go |
The error directive's handler |
How it works
graph TD
Conn[TCP/QUIC conn]
Conn --> Listener
Listener -->|accept| Server
Server -->|matchers + middleware| Routes[RouteList<br/>routes.go]
Routes --> H1[Handler 1]
H1 --> H2[Handler 2]
H2 --> Hn[…]
Hn --> Resp[response]
Provision[Provision] -->|build chain| Routes
Provision -->|register hostnames| AutoHTTPS[autohttps.go]
AutoHTTPS -->|policies| TLS[tls app]Server provisioning
App.Provision (in app.go) iterates the configured servers and:
- Resolves each
listenaddress throughcaddy.ParseNetworkAddress/caddy.Listen(listeners.go), opening sockets shared across the process viaSO_REUSEPORTon supported platforms (listen_unix.go). - Builds the route list, calling each route's
Provision. Matchers and handler modules load throughctx.LoadModule(context.go) — that's howhttp.handlers.file_serveretc. become liveHandlerinstances. - Compiles the route list into a single middleware chain via
routes.go: BuildSubroute. Each route's matchers wrap its handlers; non-terminal routes fall through to the next. - Calls
autohttps.go: automaticHTTPSPhase1/2to discover hostnames that need TLS.
Request lifecycle
Server.ServeHTTP (in server.go) does roughly:
- Wraps the response writer so handlers can return errors (
responsewriter.go). - Sets up the
caddy.Replacerfor placeholder substitution. - Invokes the compiled middleware chain.
- Handles errors via the registered error handler chain (errors, like routes, can have their own matchers).
- Emits an access log entry through
modules/caddyhttp/logging.goif enabled.
Subroutes
http.handlers.subroute (subroute.go) embeds another RouteList. This is how the Caddyfile's site blocks become handler trees: each site is a subroute whose host matchers gate entry, and inside the subroute the directives become routes.
CEL matchers
celmatcher.go adds an expression matcher backed by google/cel-go. A CEL expression like header("X-Role") == "admin" && path.startsWith("/api/") compiles to a CEL program at provision time and runs per request.
Auto-HTTPS
See Automatic HTTPS for the full flow. In short: at provision time, autohttps.go walks every server's routes, harvests hostnames from host matchers, sorts them into "managed", "manual", and "skip" buckets, and pushes the managed names into tls.automation.policies. At start time, the tls app obtains certificates for those names.
Integration points
tlsapp: the http app callscaddytls.AppLoaded(ctx)to look up the running TLS app, so it can register hostnames and read connection policies (autohttps.go).eventsapp: a few moments emit events (e.g. config reload), accessible viacaddy.Events(ctx).caddy.Listenerinfrastructure (listeners.go): all sockets come from the core listener layer, including listener-wrapper modules incaddy.listeners.*(PROXY-protocol parser, HTTP→HTTPS redirect listener).- Replacer (
replacer.go+modules/caddyhttp/replacer.go): every handler can read placeholders for request fields, env vars, and TLS metadata. - Metrics (
metrics.go): Prometheus counters for in-flight, completed, and errored requests, exposed via the admin endpoint at/metrics.
Bundled handlers
These are the standard handler modules registered when modules/caddyhttp/standard/imports.go is imported (which happens automatically in the default build):
| ID | Source | Purpose |
|---|---|---|
http.handlers.file_server |
fileserver/staticfiles.go |
Static files + directory listings |
http.handlers.reverse_proxy |
reverseproxy/reverseproxy.go |
Reverse proxy with health checks, retries, load balancing |
http.handlers.headers |
headers/headers.go |
Add/remove/replace headers |
http.handlers.encode |
encode/encode.go |
Response compression (gzip, zstd, brotli) |
http.handlers.rewrite |
rewrite/rewrite.go |
URI rewriting |
http.handlers.templates |
templates/templates.go |
Server-side templating with sprig functions |
http.handlers.subroute |
subroute.go |
Nested route lists |
http.handlers.static_response |
staticresp.go |
The respond directive |
http.handlers.error |
staticerror.go |
The error directive |
http.handlers.authentication |
caddyauth/caddyauth.go |
Request authentication (basic auth + others) |
http.handlers.tracing |
tracing/module.go |
OpenTelemetry tracing |
http.handlers.push |
push/handler.go |
HTTP/2 server push |
http.handlers.intercept |
intercept/intercept.go |
Replace upstream responses based on response matchers |
http.handlers.request_body |
requestbody/requestbody.go |
Limit / buffer request bodies |
http.handlers.map |
map/map.go |
Pattern-based variable mapping |
http.handlers.metrics |
metrics.go |
Prometheus metrics handler |
http.handlers.copy_response, http.handlers.copy_response_headers |
reverseproxy/copyresponse.go |
Used by intercept |
http.handlers.log_append |
logging/logappend.go |
Add fields to access-log line |
For a focused look at the most heavily used handlers, see Reverse proxy and File server.
Bundled matchers
| ID | Source |
|---|---|
http.matchers.host, path, path_regexp, method, query, protocol, not, vars, vars_regexp |
matchers.go |
http.matchers.header, header_regexp |
matchers.go |
http.matchers.remote_ip, client_ip |
ip_matchers.go |
http.matchers.tls |
matchers.go |
http.matchers.file |
fileserver/matcher.go |
http.matchers.expression |
celmatcher.go |
Entry points for modification
- To add a handler, create a package under
modules/caddyhttp/<name>/, register the module in itsinit(), and add the import tomodules/caddyhttp/standard/imports.goif it should be bundled. - To change request lifecycle behavior (timeouts, response writer wrapping), edit
server.goand accompany it with tests inserver_test.go. - To affect Caddyfile UX for a directive, work in
caddyconfig/httpcaddyfile/(especiallydirectives.gofor ordering andhttptype.gofor adapter glue).
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.