Caddy 2.10 is here! Aside from bug fixes, this release features:
- Encrypted ClientHello (ECH): This new technology encrypts the last plaintext portion of a TLS connection: the ClientHello, which includes the domain name being connected to. The draft spec for ECH is almost finalized, so we can now support this privacy feature for TLS. This is a powerful but nuanced capability; we highly recommend reading the ECH documentation on our website.
- Post-quantum (PQC) key exchange: Caddy now supports the standardized
x25519mlkem768 cryptographic group by default.
- ACME profiles: ACME profiles are an experimental draft that allow you to choose properties of your certificates with more flexibility than traditional CSR methods. For example, Let's Encrypt will issue 6-day certificates under a certain profile. Caddy may eventually use that profile by default.
- Via header: The reverse proxy now sets a Via header instead of a duplicate Server header.
- Global DNS provider: You can now specify a default "global" DNS module to use instead of having to configure it locally in every part of your config that requires a DNS provider (for example, ACME DNS challenges, and ECH). This is the
dns global option in the Caddyfile, or in JSON config, it's the dns parameter in the tls app configuration.
- Wildcards used by default: Previously, Caddy would obtain individual certificates for every domain in your config literally; now wildcards, if present, will be utilized for subdomains, rather than obtaining individual certificates. This change was motivated by the novel possibility for subdomain privacy afforded by ECH. It can be overridden with
tls force_automate in the Caddyfile. The experimental auto_https prefer_wildcard option has been removed.
- libdns 1.0 APIs: Many of you use DNS provider modules to solve ACME DNS challenges or to enable dynamic DNS. They implement interfaces defined by libdns to get, set, append, and delete DNS records. After 5 years of production experience, including lessons learned with ECH, libdns APIs have been updated and 1.0 beta has been tagged. DNS provider packages will need to update their code to be compatible, which will help ensure stability and well-defined semantics for the future. Several packages have already updated or are in the process of updating (cloudflare, rfc2136, and desec to name a few).
- Global
dns config: Now that several components of Caddy configuration may affect DNS records (ACME challenges, ECH publication, etc.), there is a new dns global option that can be used to specify your DNS provider config in a single place. This prevents repetition of credentials for servers where all the domains are managed by a single DNS provider.
Thank you to the many contributors who have helped to make this possible! :tada: :partying_face: :champagne:
:warning: While have traditionally supported the last 2 minor Go versions to accommodate some distribution / package manager policies, we now only support the latest minor Go version. The privacy and security benefits added in new Go versions (such as post-quantum cryptography) are worth making available to everyone as soon as possible, rather than holding back the entire user base or maintaining multiple code compilation configurations.
Encrypted ClientHello (ECH) details
(This is a brief overview. We recommend reading the full documentation.)
Typically, server names (domain names, or "SNI") are sent in the plaintext ClientHello when establishing TLS connections. With ECH, the true server name is encrypted (and wrapped) by an "outer" ClientHello which has a generic SNI of your choosing. With many sites on the same server sharing the same outer SNI, both clients and the server have more privacy related to domain names.
Caddy implements fully automated ECH, meaning that it generates (and soon, rotates), publishes, and serves ECH configurations simply by specifying a DNS provider, and the outer/public domain name to use.
Fully automated ECH requires a DNS module built into your Caddy binary. In order for a client, such as a browser, to know it can use ECH, and what parameters to use, the server's ECH configuration must be published. This config includes the public name, cryptographic parameters, and a public key for encrypting the inner ClientHello. By convention, browsers read the standardized HTTPS-type DNS record containing a ech SvcParamKey. Caddy sets this DNS record for all domains being protected, but it needs that DNS provider module plugged in and configured in order to do this. If you are already using the DNS ACME challenge, you should already have a DNS provider plugged in. If you prefer to build Caddy from source with a DNS module, it's easy with xcaddy, for example: $ xcaddy build --with github.com/caddy-dns/cloudflare
The minimum config needed to enable ClientHello is also the recommended config, as it maximizes privacy benefits in most situations. You just need the ech global option and a DNS provider specified. Here's an example using Cloudflare as the nameserver:
Caddyfile:
{
debug # not required; recommended while testing
dns cloudflare {env.CLOUDFLARE_API_KEY}
ech ech.example.net
}
example.com {
respond "Hello there!"
}
This protects all your sites (example.com in this case) behind the public name of ech.example.net. (As another example, Cloudflare uses cloudflare-ech.com for all the sites it serves. We recommend choosing a single public domain and use it to protect all your sites.)
The outer/public name you choose should point to your server. Caddy will obtain a certificate for this name in order to facilitate safe, reliable connections for clients when needed. Without a certificate, clients may be forced to connect insecurely, or fail to connect at all, in some cases, which not only leaves them vulnerable, but also risks exposing the names of your server's sites.
Caddy then uses the specified DNS provider to publish the ECH config(s) for your various site names. It creates (or augments) HTTPS-type records for the domains of your sites (not your ECH public name). Note that DNS provider modules are independently-maintained, and may not have been tested for compatibility with HTTPS-type records. Please contact your module's maintainers if you experience issues.
If you have more advanced configuration needs, you can use the JSON configuration (more details coming soon; for now, see #6862 or look at the source code; or use caddy adapt to convert a Caddyfile to JSON).
Testing and verifying Encrypted ClientHello
First make sure Caddy runs successfully with ECH enabled (and a DNS module) in the config. You should see logs that it is generating an ECH config and publishing it to your domain name(s).
You will need to use a client that supports ECH. Some custom builds of curl do, and Firefox and modern Chrome-based browsers do as well, but you need to enable DNS-over-HTTPS or DNS-over-TLS first (since, obviously, querying DNS in plaintext for a protected domain name will expose the domain and defeat the purpose of ECH).
If reusing an existing domain name, clear your DNS cache. Firefox has a way of doing this for its cache at about:networking#dns.
Once you have a suitable client, use Wireshark to capture network packets as you load your site. You should see only the outer/public name as SNI (ServerName Indicator) values in the packet capture. If at any time you see the true site name, ECH is not working properly -- it could be a client or server issue. Before filing a bug, please try to pinpoint it as a server issue first. But definitely report server bugs! Thank you!
(Note that ECH is not automatically published for CNAME'd domains, and the domain must already have a record in the zone.)
Commits
Beta 1:
- 96c5c554c1241430ac9ddea6f4b68948adcc961b admin: fix index validation for PUT requests (#6824)
- 3644ee31cae8e20493d7ccd0c55b0a9c21f20693 build(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 (#6876)
- eacd7720e99f51b6d2dd340849897c0ff812b8c8 build(deps): bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4 (#6871)
- 9996d6a70ba76a94dfc90548f25fbac0ce9da497 build(deps): bump github.com/golang/glog from 1.2.2 to 1.2.4 (#6814)
- 11151586165946453275b66ef33794d41a5e047b caddyhttp: ResponseRecorder sets stream regardless of 1xx
- 8861eae22350d9e8f94653db951faf85a50a82da caddytest: Support configuration defaults override (#6850)
- d7764dfdbbee04d2f63aa1b05150737dfddc0bcf caddytls: Encrypted ClientHello (ECH) (#6862)
- a807fe065959baa8ee2ad95156183c0850c2b584 caddytls: Enhance ECH documentation
- bc3d497739444a5ce550696b7b0da36e6e3bc777 caddytls: Fix broken refactor
- 7b8f3505e33139de0d542566478e98b361bb84bf caddytls: Fix sni_regexp matcher to obtain layer4 contexts (#6804)
- 2c4295ee48f494bc8dda5fa09b37612d520c8b3b caddytls: Initial support for ACME profiles
- d7872c3bfa673ce9584d00f01a725b93fa7bedf1 caddytls: Refactor sni matcher (#6812)
- 172136a0a0f6aa47be4eab3727fa2482d7af6617 caddytls: Support post-quantum key exchange mechanism X25519MLKEM768
- 066d770409917b409d0bdc14cb5ba33d3e4cb33e cmd: automatically set GOMEMLIMIT (#6809)
- 1f35a8a4029a338e89998acafa95e1e931a46a27 fastcgi: improve parsePHPFastCGI docs (#6779)
- 22563a70eb7b590fcb698680a3ec6d76c0968748 file_server: use the UTC timezone for modified time (#6830)
- cfc3af67492eba22686fd13a2b2201c66cd737f3 fix: update broken link to Ardan Labs (#6800)
- 99073eaa33af62bff51c31305e3437c57d936284 go.mod: Upgrade CertMagic to v0.21.7
- 1641e76fd742408c85363e4826451ba9ef22bc99 go.mod: Upgrade dependencies
- 0d7c63920daecec510202c42816c883fd2dbe047 go.mod: remove glog dependency (#6838)
- 932dac157a3c4693b80576477498bb86208b9b30 logging: Always set fields func; fix #6829
- 9e0e5a4b4c2babda81c58f28fe61adfa91d04524 logging: Fix crash if logging error is not HandlerError (#6777)
- 904a0fa368b7eacac3c7156ce4a1f6ced8f61f34 reverse_proxy: re-add healthy upstreams metric (#6806)
- e7da3b267bcec986aaca960dd22ef834d3b9d4a6 reverseproxy: Via header (#6275)
- 9283770f68f570f47ca20aa9c6f9de8cc50063ba reverseproxy: ignore duplicate collector registration error (#6820)
Beta 2:
- f4432a306ac59feee1fc45c8efefad3619e37629 caddyfile: add error handling for unrecognized subdirective/options in various modules (#6884)
- 84364ffcd06e35a93c9bb08ed80617bde72d4f74 caddypki: Remove lifetime check at Caddyfile parse (fix #6878)
- adbe7f87e6bda96a1dddd94ecedefe3219a5304d caddytls: Only make DNS solver if not already set (fix #6880)
- d57ab215a2f198a465ea33abe4588bb5696e7abd caddytls: Pointer receiver (fix #6885)
- 4ebcfed9c942c59f473f12f8108e1d0fa92e0855 caddytls: Reorder provisioning steps (fix #6877)
- a686f7c346fe011ad153a3bd4ac3e31e6758bcce cmd: Only set memory/CPU limits on run (fix #6879)
- 19876208c79a476a46beec2430e554d4161ab426 cmd: Promote undo maxProcs func to caller
- 220cd1c2bcecc07bcf6a0141069538c1b1109907 reverseproxy: more comments about buffering and add new tests (#6778)
Beta 3:
- b3e692ed09f8ba15b741621c4b16d8bfee38f8a1 caddyfile: Fix formatting for backquote wrapped braces (#6903)
- 55c89ccf2a39dcfd7286fcaed54787821ff9a1aa caddytls: Convert AP subjects to punycode
- 1f8dab572ca9681464fdadc65bfb5f250fc496c3 caddytls: Don't publish ECH configs if other records don't exist
- 782a3c7ac60c82311fe9fb8889dd843dfe26c0bc caddytls: Don't publish HTTPS record for CNAME'd domain (fix #6922)
- 49f9af9a4ab2a28fa5c445630017f5284a5afa48 caddytls: Fix TrustedCACerts backwards compatibility (#6889)
- e276994174983dbb190d4bb9acaab157ef14373b caddytls: Initialize permission module earlier (fix #6901)
- 39262f86632401ae4915600b042ef5a28141d3d5 caddytls: Minor fixes for ECH
- 173573035c7484bb4aad4498a90bf5a1cf1bb5be core: add modular
network_proxy support (#6399)
- 86c620fb4e7bfad5888832c491147af53fd5390a go.mod: Minor dependency upgrades
- af2d33afbb52389cda139a6a0fd8a9d65f558676 headers: Allow nil HeaderOps (fix #6893)
- dccf3d8982d1b428e840d43f71fa5c3becf6ea8f requestbody: Add set option to replace request body (#5795)
- 2ac09fdb2046957597e17096adf6335a6d589a2f requestbody: Fix ContentLength calculation after body replacement (#6896)
v2.10.0:
- f297bc0a04dcab6c2585b47f3672d045c4f6b54b admin: Remove host checking for UDS (close #6832)
- 0b2802faa47faa378181a3de5b0d1dcc769a715d build(deps): bump golang.org/x/net from 0.37.0 to 0.38.0 (#6960)
- 5be77d07ab730e6035ec7a47fb0fe161785af35c caddyauth: Set authentication provider error in placeholder (#6932)
- b06a9496d130cb06466156d53138a9691342e5a2 caddyhttp: Document side effect of HTTP/3 early data (close #6936)
- 35c8c2d92d26208642cea0d1549c77a00124e154 caddytls: Add remote_ip to HTTP cert manager (close #6952)
- fb22a26b1a08a2fa3b2526d1852467904ee140f6 caddytls: Allow missing ECH meta file
- 1bfa111552eff8b30bc1a5f76516426f29c66a88 caddytls: Prefer managed wildcard certs over individual subdomain certs (#6959)
- ea77a9ab67d8c04f513adaf0a1c648c738e25922 caddytls: Temporarily treat "" and "@" as equivalent for DNS publication
- 5a6b2f8d1d4633622b551357f3cc9d27ec669d02 events: Refactor; move Event into core, so core can emit events (#6930)
- 137711ae3e2d9aa48d7c48dba5ca176af628f073 go.mod: Upgrade acmez and certmagic
- 9becf61a9f5bafb88a15823ce80c1325d3a30a4f go.mod: Upgrade to libdns 1.0 beta APIs (requires upgraded DNS providers)
- 6c38ae7381b3338b173c59706673d11783091dee reverseproxy: Add valid Upstream to DialInfo in active health checks (#6949)
What's Changed
New Contributors
Full Changelog: https://github.com/caddyserver/caddy/compare/v2.9.1...v2.10.0