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 thedns
parameter in thetls
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 experimentalauto_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 newdns
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:
:::caddy
{
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:
- [96c5c5] admin: fix index validation for PUT requests (#6824)
- [3644ee] build(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 (#6876)
- [eacd77] build(deps): bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4 (#6871)
- [9996d6] build(deps): bump github.com/golang/glog from 1.2.2 to 1.2.4 (#6814)
- [111515] caddyhttp: ResponseRecorder sets stream regardless of 1xx
- [8861ea] caddytest: Support configuration defaults override (#6850)
- [d7764d] caddytls: Encrypted ClientHello (ECH) (#6862)
- [a807fe] caddytls: Enhance ECH documentation
- [bc3d49] caddytls: Fix broken refactor
- [7b8f35] caddytls: Fix sni_regexp matcher to obtain layer4 contexts (#6804)
- [2c4295] caddytls: Initial support for ACME profiles
- [d7872c] caddytls: Refactor sni matcher (#6812)
- [172136] caddytls: Support post-quantum key exchange mechanism X25519MLKEM768
- [066d77] cmd: automatically set GOMEMLIMIT (#6809)
- [1f35a8] fastcgi: improve parsePHPFastCGI docs (#6779)
- [22563a] file_server: use the UTC timezone for modified time (#6830)
- [cfc3af] fix: update broken link to Ardan Labs (#6800)
- [99073e] go.mod: Upgrade CertMagic to v0.21.7
- [1641e7] go.mod: Upgrade dependencies
- [0d7c63] go.mod: remove glog dependency (#6838)
- [932dac] logging: Always set fields func; fix [#6829]
- [9e0e5a] logging: Fix crash if logging error is not HandlerError (#6777)
- [904a0f] reverse_proxy: re-add healthy upstreams metric (#6806)
- [e7da3b] reverseproxy: Via header (#6275)
- [928377] reverseproxy: ignore duplicate collector registration error (#6820)
Beta 2:
- [f4432a] caddyfile: add error handling for unrecognized subdirective/options in various modules (#6884)
- [84364f] caddypki: Remove lifetime check at Caddyfile parse (fix [#6878])
- [adbe7f] caddytls: Only make DNS solver if not already set (fix [#6880])
- [d57ab2] caddytls: Pointer receiver (fix [#6885])
- [4ebcfe] caddytls: Reorder provisioning steps (fix [#6877])
- [a686f7] cmd: Only set memory/CPU limits on run (fix [#6879])
- [198762] cmd: Promote undo maxProcs func to caller
- [220cd1] reverseproxy: more comments about buffering and add new tests (#6778)
Beta 3:
- [b3e692] caddyfile: Fix formatting for backquote wrapped braces (#6903)
- [55c89c] caddytls: Convert AP subjects to punycode
- [1f8dab] caddytls: Don't publish ECH configs if other records don't exist
- [782a3c] caddytls: Don't publish HTTPS record for CNAME'd domain (fix [#6922])
- [49f9af] caddytls: Fix TrustedCACerts backwards compatibility (#6889)
- [e27699] caddytls: Initialize permission module earlier (fix [#6901])
- [39262f] caddytls: Minor fixes for ECH
- [173573] core: add modular
network_proxy
support (#6399) - [86c620] go.mod: Minor dependency upgrades
- [af2d33] headers: Allow nil HeaderOps (fix [#6893])
- [dccf3d] requestbody: Add set option to replace request body (#5795)
- [2ac09f] requestbody: Fix ContentLength calculation after body replacement (#6896)
v2.10.0:
- [f297bc] admin: Remove host checking for UDS (close [#6832])
- [0b2802] build(deps): bump golang.org/x/net from 0.37.0 to 0.38.0 (#6960)
- [5be77d] caddyauth: Set authentication provider error in placeholder (#6932)
- [b06a94] caddyhttp: Document side effect of HTTP/3 early data (close [#6936])
- [35c8c2] caddytls: Add remote_ip to HTTP cert manager (close [#6952])
- [fb22a2] caddytls: Allow missing ECH meta file
- [1bfa11] caddytls: Prefer managed wildcard certs over individual subdomain certs (#6959)
- [ea77a9] caddytls: Temporarily treat "" and "@" as equivalent for DNS publication
- [5a6b2f] events: Refactor; move Event into core, so core can emit events (#6930)
- [137711] go.mod: Upgrade acmez and certmagic
- [9becf6] go.mod: Upgrade to libdns 1.0 beta APIs (requires upgraded DNS providers)
- [6c38ae] reverseproxy: Add valid Upstream to DialInfo in active health checks (#6949)
What's Changed
- docs: improve parsePHPFastCGI docs by @dunglas in https://github.com/caddyserver/caddy/pull/6779
- Fixes crash if logging error is not HandlerError by @kkroo in https://github.com/caddyserver/caddy/pull/6777
- chore: update quic-go to v0.49.0 by @marten-seemann in https://github.com/caddyserver/caddy/pull/6803
- chore: don't use deprecated
archives.format_overrides.format
by @mohammed90 in https://github.com/caddyserver/caddy/pull/6807 - caddytls: Fix sni_regexp matcher to obtain layer4 contexts by @vnxme in https://github.com/caddyserver/caddy/pull/6804
- feat: automatically set GOMEMLIMIT by @dunglas in https://github.com/caddyserver/caddy/pull/6809
- caddytls: Refactor sni matcher by @vnxme in https://github.com/caddyserver/caddy/pull/6812
- reverse_proxy: re-add healthy upstreams metric by @mohammed90 in https://github.com/caddyserver/caddy/pull/6806
- fix: update broken link to Ardan Labs by @sbruens in https://github.com/caddyserver/caddy/pull/6800
- build(deps): bump github.com/golang/glog from 1.2.2 to 1.2.4 by @dependabot in https://github.com/caddyserver/caddy/pull/6814
- reverseproxy: ignore duplicate collector registration error by @mohammed90 in https://github.com/caddyserver/caddy/pull/6820
- fix: fix index validation for PUT requests by @debug-ing in https://github.com/caddyserver/caddy/pull/6824
- file_server: use the UTC timezone for modified time by @WeidiDeng in https://github.com/caddyserver/caddy/pull/6830
- feat/tests: tests for error handling & metrics in admin endpoints by @gdhameeja in https://github.com/caddyserver/caddy/pull/6805
- chore: upgrade Go version to 1.24 by @mohammed90 in https://github.com/caddyserver/caddy/pull/6839
- remove glog dependency by @Ns2Kracy in https://github.com/caddyserver/caddy/pull/6838
- update quic-go to v0.50.0 by @marten-seemann in https://github.com/caddyserver/caddy/pull/6854
- Support Caddy Test Configuration Defaults Override. by @baruchyahalom in https://github.com/caddyserver/caddy/pull/6850
- chore: upgrade cobra by @mohammed90 in https://github.com/caddyserver/caddy/pull/6868
- build(deps): bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4 by @dependabot in https://github.com/caddyserver/caddy/pull/6871
- caddytls: Encrypted ClientHello (ECH) by @mholt in https://github.com/caddyserver/caddy/pull/6862
- build(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 by @dependabot in https://github.com/caddyserver/caddy/pull/6876
- docs: replaced the name and twitter link by @sashaphmn in https://github.com/caddyserver/caddy/pull/6874
- ci: allow using the toolchain Go "toolchain" by @dunglas in https://github.com/caddyserver/caddy/pull/6846
- chore: more comments about reverse_proxy buffering and add new tests by @WeidiDeng in https://github.com/caddyserver/caddy/pull/6778
- Add error handling for unrecognized subdirective/options by @steffenbusch in https://github.com/caddyserver/caddy/pull/6884
- Fix TrustedCACerts backwards compatibility by @jjiang-stripe in https://github.com/caddyserver/caddy/pull/6889
- requestbody: Add
replace
for optional body replacement by @AdrienPensart in https://github.com/caddyserver/caddy/pull/5795 - requestbody: Fix ContentLength calculation after body replacement by @steffenbusch in https://github.com/caddyserver/caddy/pull/6896
- Fix caddy fmt breaks backquote wrapped braces in template by @keystroke3 in https://github.com/caddyserver/caddy/pull/6903
- update quic-go to v0.50.1 by @marten-seemann in https://github.com/caddyserver/caddy/pull/6918
- core: add modular
network_proxy
support by @mohammed90 in https://github.com/caddyserver/caddy/pull/6399 - events: Refactor; move Event into core, so core can emit events by @mholt in https://github.com/caddyserver/caddy/pull/6930
- chore: fix comment by @riyueguang in https://github.com/caddyserver/caddy/pull/6950
- bug: Fix the incorrect parameter order by @cuishuang in https://github.com/caddyserver/caddy/pull/6951
- Add a valid Upstream to the DialInfo when doing active health checks by @jbro in https://github.com/caddyserver/caddy/pull/6949
- caddyauth: Set authentication provider error in placeholder by @steffenbusch in https://github.com/caddyserver/caddy/pull/6932
- build(deps): bump golang.org/x/net from 0.37.0 to 0.38.0 by @dependabot in https://github.com/caddyserver/caddy/pull/6960
- caddytls: Prefer managed wildcard certs over individual subdomain certs by @mholt in https://github.com/caddyserver/caddy/pull/6959
New Contributors
- @sbruens made their first contribution in https://github.com/caddyserver/caddy/pull/6800
- @debug-ing made their first contribution in https://github.com/caddyserver/caddy/pull/6824
- @Ns2Kracy made their first contribution in https://github.com/caddyserver/caddy/pull/6838
- @baruchyahalom made their first contribution in https://github.com/caddyserver/caddy/pull/6850
- @sashaphmn made their first contribution in https://github.com/caddyserver/caddy/pull/6874
- @AdrienPensart made their first contribution in https://github.com/caddyserver/caddy/pull/5795
- @keystroke3 made their first contribution in https://github.com/caddyserver/caddy/pull/6903
- @riyueguang made their first contribution in https://github.com/caddyserver/caddy/pull/6950
Full Changelog: https://github.com/caddyserver/caddy/compare/v2.9.1...v2.10.0