caddyserver/caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

71,685 stars Go 8 components

Serves HTTP/HTTPS sites with automatic TLS certificates and zero-downtime config reloads

Configuration enters through CLI commands or files, gets parsed and converted to JSON by adapters, validated against module schemas, then applied to the running instance. HTTP requests flow through middleware chains defined by the configuration, while the admin API allows runtime configuration changes without restart. Certificate management happens automatically in background, with certificates stored and renewed as needed.

Under the hood, the system uses 3 feedback loops, 4 data pools, 5 control points to manage its runtime behavior.

A 8-component backend api. 309 files analyzed. Data flows through 6 distinct pipeline stages.

How Data Flows Through the System

Configuration enters through CLI commands or files, gets parsed and converted to JSON by adapters, validated against module schemas, then applied to the running instance. HTTP requests flow through middleware chains defined by the configuration, while the admin API allows runtime configuration changes without restart. Certificate management happens automatically in background, with certificates stored and renewed as needed.

  1. Parse configuration input — CLI commands read Caddyfile or JSON from disk, Caddyfile text gets tokenized by lexer into Token streams, then parsed into ServerBlock tree structures with import resolution
  2. Convert to unified JSON — Adapter.Adapt() transforms ServerBlock structures into standardized JSON Config format, resolving imports, substituting variables, and organizing by application type [ServerBlock → Config]
  3. Load configuration into instance — Instance.Load() validates JSON config against registered module schemas, provisions modules with their configurations, and builds dependency graphs [Config → Module]
  4. Start services and admin API — Instance.Start() initializes provisioned modules (HTTP servers, TLS managers), starts AdminServer on configured port, begins certificate management tasks [Module] (config: AdminConfig.Listen, AdminConfig.Disabled)
  5. Handle HTTP requests — Incoming requests flow through HTTP middleware chains defined in configuration, with Context providing module access, logging, and placeholder replacement
  6. Process configuration changes — Admin API receives new configurations via POST /config endpoints, validates changes, performs graceful reload by starting new modules alongside old ones, then switching atomically [Config]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

Config caddy.go
struct with Apps map[string]json.RawMessage (module configurations), Admin *AdminConfig (API settings), Logging *LoggingConfig, Storage json.RawMessage (storage backend config)
Created from JSON/Caddyfile input, validated against module schemas, applied to running instance with graceful reload
ServerBlock caddyconfig/caddyfile/parse.go
struct with Keys []string (hostnames/addresses), Segments []Segment (directive blocks), IsSnippet bool
Parsed from Caddyfile text, processed through import resolution and variable substitution, converted to JSON Config
Module modules.go
interface with CaddyModule() ModuleInfo method, plus optional Provisioner, Validator, CleanerUpper interfaces for lifecycle hooks
Registered at init time, instantiated during config loading, provisioned with dependencies, validated, then used in request handling
Token caddyconfig/caddyfile/lexer.go
struct with Text string (token content), File string, Line int (source location), Quoted bool, IsSilent bool
Generated by lexer from Caddyfile text, consumed by parser to build ServerBlock tree structure
AdminConfig admin.go
struct with Disabled bool, Listen string (API address), EnforceOrigin bool, Origins []string (CORS), Config *ConfigSettings
Configured from main Config, used to start HTTP admin API server for runtime management

Hidden Assumptions

Things this code relies on but never validates. These are the things that cause silent failures when the system changes.

critical Environment unguarded

The global module registry contains all required modules when Load() is called, with no validation that modules referenced in the JSON config actually exist in the registry

If this fails: If a config references an unregistered module (e.g., 'http.handlers.custom_auth'), Load() fails with a cryptic error instead of suggesting available modules or indicating a missing import

caddy.go:Instance.Load
critical Temporal weakly guarded

Configuration changes via the admin API are atomic - either fully applied or fully rolled back, but the code doesn't handle partial failures during graceful reload where some modules start successfully but others fail

If this fails: A bad config could leave the server in an inconsistent state with half-old, half-new configuration if reload fails partway through module provisioning

admin.go:AdminServer.handleConfig
critical Resource weakly guarded

Import resolution assumes unlimited recursion depth and doesn't track memory usage during recursive file imports, trusting that filesystem limits prevent infinite loops

If this fails: Carefully crafted Caddyfile imports could exhaust memory or stack space before hitting the cycle detection, causing OOM crashes instead of clean error messages

caddyconfig/caddyfile/parse.go:Parse
warning Domain unguarded

Sets certmagic.DefaultACME.Agreed = true globally, assuming all users consent to Let's Encrypt terms without any explicit agreement mechanism or documentation requirement

If this fails: Users unknowingly agree to CA terms of service they may not have read, potentially creating legal liability, especially in corporate environments with compliance requirements

cmd/main.go:init
warning Environment unguarded

The admin API bind address from AdminConfig.Listen is always available and not already in use by another process, with no retry or fallback mechanism

If this fails: If another process is using the admin port (default :2019), Caddy fails to start entirely instead of degrading gracefully or using an alternative port

caddy.go:Instance.Start
warning Temporal unguarded

Admin API requests are processed sequentially and don't interfere with each other, but concurrent config changes aren't synchronized beyond basic HTTP handler isolation

If this fails: Two simultaneous admin API calls modifying different parts of the config could race, with the second overwriting changes from the first without any conflict detection

admin.go:AdminServer
warning Scale unguarded

Token arrays from parsing fit entirely in memory as []Token slices, with no streaming or chunked processing for very large Caddyfiles

If this fails: Parsing a multi-megabyte Caddyfile with thousands of server blocks could exhaust available memory, causing OOM kills in memory-constrained environments

caddyconfig/caddyfile/dispenser.go:Dispenser.tokens
warning Ordering weakly guarded

The ServerType interface implementation exists and is properly initialized when Adapt() is called, but there's no null check on a.ServerType

If this fails: Calling Adapt() with an uninitialized Adapter causes a nil pointer panic instead of the documented 'no server type' error

caddyconfig/caddyfile/adapter.go:Adapter.Adapt
warning Environment weakly guarded

OS provides at least one command line argument in os.Args, specifically that len(os.Args) >= 1 with args[0] containing the executable name

If this fails: In exotic execution environments or containers where os.Args is empty, Caddy prints a fatal error but the array access could panic before the error message

cmd/main.go:Main
info Domain unguarded

Environment variable substitution in {$VAR} format expects valid environment variable names following shell conventions, but doesn't validate variable name syntax

If this fails: Malformed environment variable references like {$123-invalid} or {$} could cause silent substitution failures or unexpected string replacements

caddyconfig/caddyfile/parse.go:Parse

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

Module Registry (registry)
Global map storing all registered module constructors, organized by namespace (http.handlers, tls.providers, etc)
Instance State (in-memory)
Current running configuration and provisioned module instances, maintained for graceful reloads and cleanup
Certificate Storage (file-store)
Persistent storage for TLS certificates, private keys, and ACME account data managed by CertMagic
Import Graph (in-memory)
Dependency tracking for Caddyfile imports to detect cycles and ensure proper resolution order

Feedback Loops

Delays

Control Points

Technology Stack

CertMagic (library)
Handles automatic TLS certificate provisioning, renewal, and storage with ACME provider integration
Zap (library)
Structured logging throughout the system with configurable levels and outputs
Cobra (framework)
CLI framework providing the command structure (start, stop, reload, validate, etc)
QUIC-GO (library)
HTTP/3 and QUIC protocol implementation for next-generation web serving
Prometheus Client (library)
Metrics collection and exposure for monitoring server performance and health
OpenTelemetry (library)
Distributed tracing and observability instrumentation for request tracking
Go Chi Router (framework)
HTTP routing for the admin API endpoints with middleware support
CEL (Common Expression Language) (library)
Expression evaluation for configuration conditions and dynamic behavior

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Backend Api Repositories

Frequently Asked Questions

What is caddy used for?

Serves HTTP/HTTPS sites with automatic TLS certificates and zero-downtime config reloads caddyserver/caddy is a 8-component backend api written in Go. Data flows through 6 distinct pipeline stages. The codebase contains 309 files.

How is caddy architected?

caddy is organized into 6 architecture layers: Command Interface, Core Instance, Module System, Configuration Layer, and 2 more. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through caddy?

Data moves through 6 stages: Parse configuration input → Convert to unified JSON → Load configuration into instance → Start services and admin API → Handle HTTP requests → .... Configuration enters through CLI commands or files, gets parsed and converted to JSON by adapters, validated against module schemas, then applied to the running instance. HTTP requests flow through middleware chains defined by the configuration, while the admin API allows runtime configuration changes without restart. Certificate management happens automatically in background, with certificates stored and renewed as needed. This pipeline design reflects a complex multi-stage processing system.

What technologies does caddy use?

The core stack includes CertMagic (Handles automatic TLS certificate provisioning, renewal, and storage with ACME provider integration), Zap (Structured logging throughout the system with configurable levels and outputs), Cobra (CLI framework providing the command structure (start, stop, reload, validate, etc)), QUIC-GO (HTTP/3 and QUIC protocol implementation for next-generation web serving), Prometheus Client (Metrics collection and exposure for monitoring server performance and health), OpenTelemetry (Distributed tracing and observability instrumentation for request tracking), and 2 more. A focused set of dependencies that keeps the build manageable.

What system dynamics does caddy have?

caddy exhibits 4 data pools (Module Registry, Instance State), 3 feedback loops, 5 control points, 3 delays. The feedback loops handle self-correction and polling. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does caddy use?

5 design patterns detected: Module Plugin Architecture, Graceful Configuration Reload, Adapter Pattern, Context Propagation, Automatic Resource Management.

Analyzed on April 20, 2026 by CodeSea. Written by .