Architecture Overview
Caddy configuration follows a hierarchical structure:Root Configuration
Fromcaddy.go:46-95, the top-level Config struct:
The
Config struct contains both JSON-encodable fields (exported with json tags) and internal runtime fields (unexported). Only JSON fields are configurable.Module System
Caddy’s extensibility comes from its module system. Every feature is a module.Module Namespaces
Modules are organized into namespaces:caddy.storage.*- Storage backendscaddy.logging.writers.*- Log writerscaddy.logging.encoders.*- Log encodershttp.handlers.*- HTTP handlershttp.matchers.*- Request matcherstls.issuance.*- Certificate issuerstls.cert_managers.*- Certificate managers
Module Specification
Modules can be specified in two ways:- Inline Key
- Module Map
module field names the module, other fields are module-specific.App Lifecycle
Fromcaddy.go:98-101, apps implement the App interface:
Provisioning and Startup
The lifecycle follows this sequence (caddy.go:403-468):
- Provision Context - Create execution environment
- Load Modules - Instantiate all modules
- Provision Modules - Call
Provision()on each module - Validate - Verify configuration correctness
- Start Apps - Call
Start()on each app in order - Finish Setup - Configure admin endpoints, config loaders
Configuration Layers
Layer 1: Native JSON
The foundational layer - Caddy’s internal representation:Layer 2: Config Adapters
Adapters transform other formats to JSON:caddyconfig/caddyfile/adapter.go:26-64:
Layer 3: Admin API
Dynamic runtime configuration via HTTP API:Storage Architecture
Caddy stores persistent data like TLS certificates:Context and Modules
Fromcontext.go, every module receives a Context:
- Load other modules via
ctx.LoadModule() - Access configuration via
ctx.cfg - Register cleanup via
ctx.OnCancel()
Module Interface
Configuration Flow
HTTP App Structure
The HTTP app is the most complex:Route Matching
Routes are evaluated in order until a terminal route matches:- Match - Request matches all matchers (AND logic)
- Handle - Handlers process the request
- Terminal - Stop route evaluation if true
TLS App Structure
Configuration Reloads
Fromcaddy.go:159-264, config changes are atomic:
- Decode new configuration
- Provision new config (instantiate modules)
- Validate new config
- Start new apps
- Swap to new config
- Stop old apps
- Cleanup old modules
Config reloads are zero-downtime. The old config keeps running until the new config is fully started and validated.
Auto-Save and Resume
Fromcaddy.go:362-384, Caddy can persist configs:
Events System
Fromcaddy.go:1065-1156, Caddy emits events:
started- Emitted when config starts successfullystopping- Emitted when shutdown begins
The events system is experimental and subject to change.
Best Practices
Structure Your Config
- Separate concerns - Use multiple apps appropriately
- Modularize - Break large configs into smaller pieces
- Use adapters - Write in the format that makes sense for your use case
- Validate early - Check configs before deploying
- Monitor changes - Track config changes in version control
Performance Considerations
- Route order matters - Place common routes first
- Use terminal routes - Stop evaluation when match is found
- Minimize matchers - Fewer matchers = faster matching
- Leverage caching - Enable TLS session resumption, HTTP caching
Security Considerations
- Disable admin when not needed - Reduce attack surface
- Use enforce_origin - Prevent CSRF on admin API
- Validate TLS configs - Ensure strong cipher suites
- Protect storage - Secure certificate storage with proper permissions
Debugging Configuration
View Current Config
Trace Config Loading
Validate Before Loading
See Also
- Caddyfile Format - Human-friendly configuration
- JSON Format - Native configuration format
- Admin API - Runtime configuration management
- HTTP Modules - HTTP module documentation