The Admin API is Caddy's HTTP-based management interface for runtime configuration. It provides RESTful endpoints to query and modify the active configuration without restarting the server. The API supports both a local plaintext endpoint (default: localhost:2019) and an optional remote TLS endpoint with mutual authentication for secure remote administration.
For information about the configuration lifecycle and how configs are loaded and provisioned, see Configuration Lifecycle. For details about the module system that the Admin API can manage, see Module System.
Sources: admin.go61-119 caddy.go104-143
Caddy maintains two separate admin servers with different security models:
Diagram: Admin Server Architecture and Security Layers
The adminHandler type encapsulates the HTTP handler with security configuration. Local and remote servers use the same routing logic but different security enforcement mechanisms.
Sources: admin.go217-281 admin.go756-869
The Admin API is configured through the AdminConfig struct in the top-level Caddy configuration:
| Field | Type | Description |
|---|---|---|
Disabled | bool | Completely disables the admin endpoint |
Listen | string | Local endpoint bind address (default: localhost:2019 or $CADDY_ADMIN) |
EnforceOrigin | bool | Enables strict Origin header validation |
Origins | []string | Allowed origins for CORS (defaults to listen address) |
Config | *ConfigSettings | Configuration management options (persistence, dynamic loading) |
Identity | *IdentityConfig | Server identity credentials for remote admin |
Remote | *RemoteAdmin | Remote admin endpoint configuration |
The local admin server is started during config provisioning by replaceLocalAdminServer(), while the remote server is started later by replaceRemoteAdminServer() after identity management is established.
Sources: admin.go61-119 admin.go376-471 admin.go520-627
/config/*The /config/ endpoint provides path-based access to the active configuration structure:
Diagram: Configuration Endpoint Request Flow
Supported HTTP methods:
The configuration path is hierarchical using forward slashes. For example:
/config/apps/http/servers/srv0/listen accesses the listen addresses for server srv0/config/apps/tls/automation/policies/0 accesses the first automation policyETag Support: The API generates ETags using xxhash for optimistic concurrency control. Clients can provide an If-Match header with format "<path> <hash>" to ensure their change applies to the expected configuration state.
Sources: admin.go992-1072 caddy.go159-265 admin.go974-982
/id/{id}/*The /id/ endpoint allows accessing configuration objects by their @id field rather than path:
Diagram: ID-Based Configuration Access
The @id field can be added to any configuration object as metadata. The indexConfigObjects() function builds an index mapping IDs to paths during configuration loading. When a request arrives at /id/{id}/..., the handler looks up the ID, rewrites the request path to the full config path, and internally redirects to handleConfig().
Sources: admin.go1074-1108 caddy.go276-311
/stopThe /stop endpoint triggers graceful shutdown:
Diagram: Graceful Shutdown Process
Only POST requests are allowed. The shutdown process runs asynchronously to allow the API response to complete before the server exits.
Sources: admin.go1110-1120 caddy.go751-830
The Admin API exposes standard Go profiling and metrics endpoints:
| Endpoint | Handler | Purpose |
|---|---|---|
/debug/pprof/ | pprof.Index | Profile index |
/debug/pprof/cmdline | pprof.Cmdline | Command line arguments |
/debug/pprof/profile | pprof.Profile | CPU profile |
/debug/pprof/symbol | pprof.Symbol | Symbol resolution |
/debug/pprof/trace | pprof.Trace | Execution trace |
/debug/vars | expvar.Handler | Exported variables |
Sources: admin.go264-269
The admin handler implements a multi-layer security model:
Diagram: Admin Request Processing Sequence
The handler performs defense-in-depth security checks:
no-cors modeSources: admin.go768-869 admin.go801-868
For local admin endpoints, security relies on origin and host validation:
Diagram: Origin Validation Logic
Host checking is disabled for Unix domain sockets and file descriptor networks because DNS rebinding attacks don't apply to these transport types.
Sources: admin.go304-374 admin.go911-972
The remote admin endpoint enforces mutual TLS authentication:
Diagram: Remote Admin Security Architecture
Access control is configured per-client using base64-encoded DER certificates:
The enforceAccessControls() method validates that the client certificate's public key matches an authorized key and that the request path and method are permitted.
Sources: admin.go474-518 admin.go520-627 admin.go674-729
Identity management allows the Caddy instance to obtain and maintain TLS certificates for itself:
| Component | Purpose |
|---|---|
IdentityConfig | Defines server identifiers and certificate issuers |
identityCertCache | Global certificate cache for identity certificates |
manageIdentity() | Sets up automated certificate management |
IdentityCredentials() | Returns client credentials for outbound TLS |
The identity system uses CertMagic with custom issuers (ACME, ZeroSSL, or internal PKI) to obtain certificates. These certificates can be used for remote admin authentication or as client credentials when Caddy needs to authenticate to other services.
Sources: admin.go150-166 admin.go474-518 context.go653-668
The unsyncedConfigAccess() function implements all configuration mutations:
Diagram: Configuration Access Implementation
The function operates on the rawCfg map, which holds the configuration as generic any types. It traverses the path components, performing type assertions to navigate maps and slices. The mutations are applied in-place, and then changeConfig() encodes the entire configuration to JSON and reloads it.
Array operations:
...): Append multiple elements from array inputSources: admin.go1122-1285 caddy.go159-265
The Admin API supports optional configuration persistence:
Diagram: Configuration Autosave Logic
By default, configurations pushed via the Admin API are persisted to disk. This behavior can be disabled:
Dynamically-loaded configs (via config loaders) are never persisted, only configs explicitly pushed to the API.
Sources: caddy.go361-387
Third-party modules can register custom admin endpoints:
Diagram: Custom Admin Route Registration
Example implementation:
The AdminHandler interface returns errors instead of writing error responses, allowing the admin handler to log errors and increment metrics consistently.
Sources: admin.go271-281 admin.go283-302 admin.go745-754
The Admin API tracks Prometheus metrics for observability:
| Metric | Type | Labels | Description |
|---|---|---|---|
caddy_admin_http_requests_total | Counter | handler, path, code, method | Total admin API requests |
caddy_admin_http_request_errors_total | Counter | handler, path, method | Admin API request errors |
Metrics are registered in the context's metrics registry and exposed via the standard /debug/vars endpoint or Prometheus exporters.
Sources: admin.go230-254 admin.go243-250
The Admin API uses several mutexes to ensure thread-safe config management:
| Mutex | Scope | Purpose |
|---|---|---|
rawCfgMu | Global | Protects rawCfg, rawCfgJSON, rawCfgIndex |
currentCtxMu | Global | Protects currentCtx (active context) |
serverMu | Global | Protects localAdminServer, remoteAdminServer |
Configuration changes acquire rawCfgMu for the entire operation to prevent concurrent modifications. This ensures that only one config change can occur at a time, preventing race conditions during the load/provision/start cycle.
Sources: caddy.go1179-1184 caddy.go169-170
Refresh this wiki