This episode dissects Caddy's architecture: the HTTP server core, the module system, the admin API, and the storage layer. You'll also learn the request flow, Caddyfile structure, the concepts of site address, directive, matcher, and handler, plus the four configuration methods.

You now know why Caddy exists. Episode 2 takes you one level deeper: understanding the architecture and core concepts that underpin all configuration. Once you understand that a directive is an action and a matcher is a criterion, reading someone else's Caddyfile will feel like reading a language you already know.
Caddy is built as a collection of modules running on top of a small core. This architecture makes Caddy easy to extend — almost every feature, from TLS to reverse proxy, is a module that can be replaced or added. This understanding is also what lets you use the caddy list-modules feature with confidence.
Episode 2 covers the architecture components, Caddyfile structure, the request flow, and the four configuration methods available. You don't need to memorize every term — what matters is understanding the mindset.
Caddy's architecture consists of several layers:
Every module has a type and a name. When you run caddy list-modules, that long list is every module compiled into your binary.
Caddy stores certificates and keys in storage, by default at $XDG_DATA_HOME/caddy on Linux. This storage concept matters because:
We'll dig into storage in depth in episodes 7 and 10.
The Caddyfile is made up of global options at the top and site blocks below them. A site block opens with the site address and contains directives inside:
example.com {
root * /var/www
encode gzip
file_server
}example.com determines which domain is served.root, encode, file_server are actions executed in order.email and admin are written outside site blocks.Directives can be constrained with matchers — criteria that decide which requests get processed. There are two forms:
@api { path /api/* } or header Content-Type application/json.@ prefix, then reused across several directives.A snippet is a named block that can be inserted into many sites — analogous to a macro or include:
(common) {
encode gzip zstd
header {
X-Frame-Options DENY
}
}
site-a.example.com {
import common
root * /var/www/a
file_server
}Snippets are marked with parentheses in their name and invoked with the import directive. This keeps repeated configuration DRY.
When a request arrives, Caddy runs a structured flow:
Directive order matters: for example, redir should be written before file_server so the redirect catches the request first. We'll discuss ordering and placement in episodes 4 and 13.
localhost:8080.A single directive can map to one or more handlers, and a single handler can be used by many directives.
Caddy accepts configuration through four paths:
:2019 endpoint for loading and changing configuration at runtime.The caddy adapt command shows the JSON produced from a Caddyfile:
caddy adapt --config CaddyfileAnd JSON can be loaded directly through the admin API:
curl -X POST -H 'Content-Type: application/json' \
-d @config.json http://localhost:2019/loadcurl -X POST ... -d @config.json is how you load dynamic configuration. We'll dissect this admin API thoroughly in episode 23.
Episode 2 introduced Caddy's conceptual foundation: a modular architecture with an HTTP core, TLS management, a reverse proxy engine, the admin API, and a storage layer; the Caddyfile structure with site blocks, directives, matchers, named matchers, and snippets; the request flow from listener to response; and the four configuration methods.
Key takeaways:
In the next episode, episode 3, we'll install Caddy completely — from official package managers, binary downloads, Docker, to building from source — and run a first run to make sure everything works before diving into Caddyfile material.