caddyserver/caddy
Automatic HTTPS
Caddy turns any HTTP route with a host matcher into a TLS-enabled site by default. The whole pipeline is implemented in modules/caddyhttp/autohttps.go (~33 KB) and feeds into the TLS app.
Purpose
Take "I have a route for example.com" as the only signal needed to:
- Bind the configured HTTPS port (default
443). - Obtain a managed certificate for
example.comfrom an issuer (Let's Encrypt, ZeroSSL, internal). - Redirect plaintext HTTP requests to HTTPS.
- Serve TLS handshakes against the managed cert.
Directory layout
| Path | Role |
|---|---|
modules/caddyhttp/autohttps.go |
The whole flow: harvest hostnames, split into managed/manual/skip, build TLS automation policies, install HTTP→HTTPS redirects |
modules/caddyhttp/autohttps_test.go |
Auto-HTTPS tests |
modules/caddytls/automation.go |
The TLS-side data model the http app fills in |
modules/caddytls/ondemand.go |
On-demand issuance gating |
modules/caddyhttp/httpredirectlistener.go |
Listener that redirects plaintext HTTP traffic on a TLS port |
How it works
graph TD
Provision[App.Provision] --> Phase1[automaticHTTPSPhase1]
Phase1 --> Harvest[Walk every server's routes,<br/>collect hostnames from host matchers]
Harvest --> Buckets["Sort into managed / manual /<br/>skip / on-demand"]
Buckets --> TLSPolicies[Build AutomationPolicies<br/>and push to tls app]
Provision --> Phase2[automaticHTTPSPhase2]
Phase2 --> Bindings[Inject :443 listeners<br/>where missing]
Phase2 --> Redirect[Add HTTP→HTTPS redirect server<br/>on the http port]
Start[App.Start] --> StartTLS[tls.Start obtains certs<br/>via CertMagic]
StartTLS --> Issuers[acme / zerossl / internal]Harvest
automaticHTTPSPhase1 walks each Server's Routes and asks every route for its host matchers. Hostnames go into one of these buckets:
- Managed: Caddy will obtain a cert. This is the default for any non-IP hostname.
- Manual: the user already loaded a cert covering this hostname (via
tls.certificates.load_*). Caddy serves it but doesn't manage it. - Skip: explicitly disabled via
auto_https offfor this site. - On-demand: issuance is deferred to the first TLS handshake (gated by
ondemand.goto prevent abuse).
IP-only and explicitly excluded hostnames don't get certs.
Build TLS automation policies
Phase 1 then calls tls.AddAutomationPolicy for the managed buckets. Each policy:
- Lists the hostnames it covers.
- Names the issuer chain (default:
acmethenzerosslas fallback;internalfor internal-only names). - Carries renewal and key-type knobs.
Listener and redirect injection
automaticHTTPSPhase2 ensures every server that needs TLS has a :443 (or configured HTTPS port) entry in listen, and that the connection-policy list has a default if none was set. It also installs a small HTTP server bound to the HTTP port (default :80) that 301-redirects everything to HTTPS for managed hostnames. That server is generated dynamically — you don't see it in your config.
TLS handshake
When a client connects, caddytls's connection policy machinery (modules/caddytls/connpolicy.go) selects the right cert via CertMagic. If issuance is on-demand, the cert is fetched live during the handshake (with the configured ACME issuer and the on-demand permission check from ondemand.go).
What you see in JSON
A Caddyfile site like:
example.com {
reverse_proxy localhost:8080
}becomes (abbreviated):
{
"apps": {
"http": { "servers": { "srv0": { "listen": [":443"], "routes": [...] } } },
"tls": {
"automation": {
"policies": [
{ "subjects": ["example.com"] }
]
}
}
}
}You can see the same with caddy adapt --config Caddyfile --pretty.
Disabling auto-HTTPS
{
auto_https off
}Or per-site:
example.com {
auto_https off
...
}The first form skips both cert management and the HTTP→HTTPS redirect; the second form skips for that site only.
On-demand issuance
For workloads where you don't know the hostnames in advance (multi-tenant SaaS, dynamic preview environments), enable on-demand:
{
on_demand_tls {
ask https://my-app/check-hostname
}
}
* {
tls {
on_demand
}
}The ask endpoint is consulted at handshake time to authorize issuance. modules/caddytls/ondemand.go implements the rate limiting and permission flow.
Integration points
httpapp: drives the entire flow at provision time.tlsapp: is the consumer; obtains and maintains certs.pkiapp: theinternalissuer issues certs for internal-only names likelocalhost.- Storage: all cert material persists through the configured storage module.
Entry points for modification
- Tweak harvesting heuristics?
automaticHTTPSPhase1inautohttps.go. - Change the redirect server? Same file,
automaticHTTPSPhase2. - Customize the on-demand permission flow?
modules/caddytls/ondemand.go.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.