This patch release contains a large number of minor and some noticeable enhancements and bug fixes. Thank you to everyone who contributed or spent their LLM tokens responsibly to help with this release!
We have much more in the pipeline still, as AI has made contributions of all quality levels cheap and easy. We will be trying to go through them as quickly and efficiently as we can.
Huge thank you to our sponsors for keeping the project alive with resources, and for our maintainers who triage and assist tirelessly in this relentless new age of AI.
:warning: Please read the breaking changes below before upgrading. Most of them come from security hardening, and most configs won't notice. If you were relying on one of the old behaviors, though, you'll want to know about it.
Highlights
- New
url_patternrequest matcher: Match requests with the URLPattern standard, the same syntax used by browsers (JS) and many web frameworks. It supports named groups, wildcards, and regexp components. Captured groups become placeholders ({http.url_pattern.<component>.<group>}), and there's a matchingurl_patternCEL function too. Thanks @dunglas! (#7787) - Slowloris mitigation: New idle read/write timeouts reset on every successful read or write. A stalled connection gets cut off, and a slow one that's still making progress is left alone. You can also set optional minimum transfer rates, and there's a new
timeoutshandler directive for per-route tuning. (#7913) - New
tls_automate_namesglobal option: Manage certificates for names without serving them in a site block. (#8015) - New
expected_underscore_headersserver option: If dropping header fields with underscores in 2.11.4 broke your app, you can now list the specific headers to keep. (#7809) - HTTP/3 over Tailscale and other low-MTU links now works, because the initial QUIC packet size is smaller. (#7886)
- Reverse proxy got more love:
- partial responses are flushed to clients properly (#7849)
- TCP half-close is propagated on upgraded streams (#8027)
versions 3upstreams now honortls_trust_pool(#8042)- active health check state is kept separate per check config, so one handler's failing probes don't mark the upstream down for everyone else (#7916)
- the
random_choosepolicy distributes correctly now (#7873) - Server-sent events behind
encodenow stream immediately instead of being buffered. (#7905) - Graceful shutdown now waits for servers left over from previous configs, so long-lived responses that started before a reload aren't cut off at exit. (#8009)
- Caddyfile:
importnow works inside named routes (#7986), and quoted braces are treated as literal arguments (#7875). - Logging:
- new
set_cookielog filter (#7888) roll_intervalaccepts days (d) (#7900)- recovered handler panics are logged at ERROR level (#7924)
- write timeout errors show up in access logs (#7945)
- Performance: fewer allocations in request hot paths, encoding negotiation, and the reverse proxy, from @jvoisin and @dunglas. Directory browsing is much faster for large directories. (#7847, [#7903], [#7911], [#7925], [#7926], [#7936])
- Other new stuff:
{http.request.proto_name}placeholder (#7782)- FastCGI populates
SERVER_ADDR(#7912) - multiple
authenticationproviders no longer clobber each other's responses (#7904)
:warning: Breaking changes
- Go 1.26 is now the minimum version for building Caddy and plugins. (#8056)
- Request headers are limited to 16 KiB by default. Before, we used Go's 1 MB default. Requests with larger headers (giant cookies, oversized tokens, etc.) will now get
431 Request Header Fields Too Large. If you need more, raise it with themax_header_sizeserver option. - New 1-minute idle read/write timeouts by default. If a request body read or a response write stalls (makes no progress at all) for longer than that, the connection is aborted. Pauses between writes, like with SSE, don't count. Some long-lived streams where the client goes quiet mid-body may be affected. You can tune these with
read_body_idleandwrite_idlein thetimeoutsserver option, or per-route with thetimeoutsdirective. (#7913) - Request header fields containing
.are now dropped, the same way underscores were in 2.11.4. PHP folds.to_, so these could be used to impersonate legitimate headers. If you need specific ones, allow them with the newexpected_dot_headersserver option. - A wildcard site's
client_authno longer applies to more specific hostnames that have their own site blocks. For example,public.example.comno longer inherits mTLS from*.example.com. If you were counting on that inheritance, configureclient_authon the specific site explicitly. (#7920) - Stricter config validation. Some configs that used to be silently accepted (and probably didn't do what you expected) are now errors:
- duplicate
named_routes(#7800) - duplicate
forward_authuri(#7814) - invalid
weighted_round_robinweights (#7807) - a non-integer
browsefile_limit(#7988) - duplicate or ambiguous
mapinputs (#8067) - malformed
mapdestination placeholders (#8074) - module paths with ambiguous
@version separators (#7974) - Admin API
/loadnow returns400with warnings inside a valid JSON body when a config is invalid. Before, it returned200with two concatenated JSON objects. (#7267) methodmatcher values are normalized to uppercase, somethod getnow matchesGETrequests. (#7832)
Security fixes
Thank you to everyone who reported responsibly and helped with patches:
- reverseproxy: When a route used both
forward_authandreverse_proxy, a request could be sent on the wrong upstream connection. Reported by @carlt, fixed by @WeidiDeng. (GHSA-6365-7ppr-5r92, [#7859]) - reverseproxy: Hop-by-hop headers from upstreams are now stripped from
101 Switching Protocolsresponses too. Thanks @jirn073-76. - caddyhttp:
handle_pathanduristrip_prefix/strip_suffixnow canonicalize the resulting path, so it can't bypass path-based authorization. Thanks @steadytao. - caddyhttp: Extended the 2.11.4 header-alias filter to
.(see above) to prevent bypassingforward_auth copy_headerswith PHP/FastCGI backends. Thanks @dunglas. - caddyhttp: The
path_regexpmatcher now normalizes Windows backslashes like thepathmatcher does. This completes the fix for CVE-2026-52844. Thanks @thientd. (#7858) - fileserver: Windows 8.3 short names are rejected in every path component, not just the last one. Thanks @DavidCarliez. (#7952)
- fileserver: Fixed ETag collisions between files with different modification times and sizes. Thanks @dunglas.
- fastcgi: The client's
Proxyheader is no longer passed to backends asHTTP_PROXY(HTTPoxy). Thanks @bzyy1024. (#7934) - reverseproxy: Sticky session cookie hashes are compared in constant time. Thanks @alhudz. (#7853)
- admin: Request paths are normalized in the remote admin access check, and origin/host allow-lists compare case-insensitively (defense-in-depth). Thanks @AmariahAK, @mohammed90, and @hktitof. (#7910, [#7973], [#7993])
- caddyhttp: Oversized request bodies used through placeholders now correctly return
413. Thanks @hktitof. (#7969)
:warning: These security patches may be breaking if your application relies on the buggy behaviors.
:rotating_light: Notice for Caddy plugin maintainers: Dependabot will probably alert you to the security fixes in Caddy and urge you to upgrade it in your go.mod file. Please ONLY upgrade the Caddy dependency if there's a change to an exported API your plugin uses. Note that doing so now also requires Go 1.26.
Thank you to everyone who was involved this release, especially our 40 new contributors! :tada:
What's Changed
- reverseproxy: replace placeholders specified for sni while using http3 by @WeidiDeng in https://github.com/caddyserver/caddy/pull/7737
- caddyhttp: add {http.request.proto_name} placeholder for spec-compliant protocol names by @Jualhosting in https://github.com/caddyserver/caddy/pull/7782
- httpcaddyfile: error on duplicate named_routes by @vijayvenkatj in https://github.com/caddyserver/caddy/pull/7800
- cmd: colored error message in WrapCommandFuncForCobra (#7760) by @u5surf in https://github.com/caddyserver/caddy/pull/7768
- chore: add missing "is" in SECURITY.md by @AliMickey in https://github.com/caddyserver/caddy/pull/7802
- reverseproxy: validate on weighted_round_robin loadbalancing policy by @vijayvenkatj in https://github.com/caddyserver/caddy/pull/7807
- forwardauth: error on duplicate uri subdirective by @vijayvenkatj in https://github.com/caddyserver/caddy/pull/7814
- encode: add standard benchmark and conformance harness by @ottenhoff in https://github.com/caddyserver/caddy/pull/7804
- caddyhttp: restore allow_underscore_in_headers server option by @bluegate-studio in https://github.com/caddyserver/caddy/pull/7809
- rewrite: fix wrong index check in trimPathPrefix by @alhudz in https://github.com/caddyserver/caddy/pull/7812
- intercept: fix replace_status being silently dropped by @oksusucha in https://github.com/caddyserver/caddy/pull/7810
- fileserver: append repeated hide subdirectives instead of overwriting by @luccinmasirika in https://github.com/caddyserver/caddy/pull/7817
- rewrite: scope keyed query replace to its named key by @alhudz in https://github.com/caddyserver/caddy/pull/7818
- reverseproxy: log status 499 instead of 0 when client disconnects by @larrasket in https://github.com/caddyserver/caddy/pull/7827
- tracing: fix BatchSpanProcessor goroutine leak on config reload by @Dean2026 in https://github.com/caddyserver/caddy/pull/7826
- caddyhttp: normalize method names to uppercase in MatchMethod.Provision by @yintaisha in https://github.com/caddyserver/caddy/pull/7832
- caddyhttp: add URL pattern request matcher by @dunglas in https://github.com/caddyserver/caddy/pull/7787
- caddyhttp: fix escaped path matcher over-matching longer paths by @alhudz in https://github.com/caddyserver/caddy/pull/7828
- core: preserve metrics registry in Context.WithValue by @dunglas in https://github.com/caddyserver/caddy/pull/7861
- reverseproxy: compare sticky-session cookie hash in constant time by @alhudz in https://github.com/caddyserver/caddy/pull/7853
- reverseproxy: fix misleading handle_response error for extra matcher args by @TowyTowy in https://github.com/caddyserver/caddy/pull/7869
- reverseproxy: save dial info in a context key instead of a variable k… by @WeidiDeng in https://github.com/caddyserver/caddy/pull/7859
- caddyhttp: fix path_regexp (MatchPathRE) Windows backslash bypass by @thientd in https://github.com/caddyserver/caddy/pull/7858
- intercept: fix misleading handle_response error for extra matcher args by @TowyTowy in https://github.com/caddyserver/caddy/pull/7871
- build(deps): bump cel-go from v0.28.1 to v0.29.2 by @techknowlogick in https://github.com/caddyserver/caddy/pull/7872
- reverseproxy: fix broken reservoir sampling in random_choose policy by @TowyTowy in https://github.com/caddyserver/caddy/pull/7873
- caddyfile: treat quoted braces as literal arguments by @elee1766 in https://github.com/caddyserver/caddy/pull/7875
- logging: hash query parameter values in QueryFilter by @PichuChen in https://github.com/caddyserver/caddy/pull/7884
- chore: fix sabotage spelling in nolint comments by @futurehua in https://github.com/caddyserver/caddy/pull/7892
- pki: Handle error immediately after reading root from disk by @hslatman in https://github.com/caddyserver/caddy/pull/7896
- log: support
d(day) inroll_intervaldirective by @mohammed90 in https://github.com/caddyserver/caddy/pull/7900 - deps: update GitHub Actions and Go modules by @steadytao in https://github.com/caddyserver/caddy/pull/7876
- build(deps): bump google.golang.org/grpc from 1.81.1 to 1.82.1 by @dependabot[bot] in https://github.com/caddyserver/caddy/pull/7908
- core: reduce QUIC initial packet size for low-MTU paths by @Salynn in https://github.com/caddyserver/caddy/pull/7886
- rewrite: preserve non-canonical path encoding after uri replace by @larrasket in https://github.com/caddyserver/caddy/pull/7907
- caddyhttp: use canonical header key casing to avoid re-canonicalization by @dunglas in https://github.com/caddyserver/caddy/pull/7911
- caddyconfig: Register nested named-route invokes transitively by @SillyZir in https://github.com/caddyserver/caddy/pull/7898
- encode: reduce allocations in AcceptedEncodings by @jvoisin in https://github.com/caddyserver/caddy/pull/7847
- encode: flush headers immediately for server-sent events responses by @SillyZir in https://github.com/caddyserver/caddy/pull/7905
- fileserver: speed up directory browsing for large directories by @firefart in https://github.com/caddyserver/caddy/pull/7903
- caddyauth: isolate provider responses to prevent cross-provider clobbering by @SillyZir in https://github.com/caddyserver/caddy/pull/7904
- log: don't allow overwriting singly-assigned vals by @mohammed90 in https://github.com/caddyserver/caddy/pull/7927
- caddyconfig: cancel HTTP loader requests with context by @cuishuang in https://github.com/caddyserver/caddy/pull/7918
- feat(fastcgi): populate SERVER_ADDR by default by @renich in https://github.com/caddyserver/caddy/pull/7912
- reverseproxy: reduce allocation/CPU overhead in request hot paths by @jvoisin in https://github.com/caddyserver/caddy/pull/7925
- reverseproxy: preallocate upstream slices with known sizes by @jvoisin in https://github.com/caddyserver/caddy/pull/7926
- network_proxy: reject proxy URLs that resolve to a port with no host by @r0h1tb in https://github.com/caddyserver/caddy/pull/7922
- caddyhttp: log recovered handler panics at ERROR level by @ousamabenyounes in https://github.com/caddyserver/caddy/pull/7924
- caddyhttp: allocate the request UUID lazily instead of on every request by @jvoisin in https://github.com/caddyserver/caddy/pull/7936
- caddyhttp: shield specific hostnames from a covering wildcard's client auth by @SillyZir in https://github.com/caddyserver/caddy/pull/7920
- reverseproxy: isolate active health-check state per distinct check config by @SillyZir in https://github.com/caddyserver/caddy/pull/7916
- logging: add set_cookie log filter for Set-Cookie response headers by @steffenbusch in https://github.com/caddyserver/caddy/pull/7888
- caddyhttp: fix url_pattern authorization bypass via encoded-slash traversal by @dunglas in https://github.com/caddyserver/caddy/pull/7941
- fix: close resources on error paths by @ittakestwo123 in https://github.com/caddyserver/caddy/pull/7940
- fastcgi: fix HTTPoxy vulnerability by @bzyy1024 in https://github.com/caddyserver/caddy/pull/7934
- caddyhttp: mitigate slowloris via idle read/write deadlines by @dunglas in https://github.com/caddyserver/caddy/pull/7913
- chore: fix lint errors from newer golangci-lint by @faiyazrahmann in https://github.com/caddyserver/caddy/pull/7958
- pki: honor skip_install_trust for explicit tls internal issuers by @gautamrizwani in https://github.com/caddyserver/caddy/pull/7894
- caddyfile: clarify ArgErr documentation by @0jaspahwa in https://github.com/caddyserver/caddy/pull/7960
- rewrite: fix URI splitting when a query or fragment arrives via a placeholder by @francislavoie in https://github.com/caddyserver/caddy/pull/7947
- admin: normalize request path in remote admin access-control check (defense-in-depth) by @AmariahAK in https://github.com/caddyserver/caddy/pull/7910
- fileserver: reject short names in every path component by @DavidCarliez in https://github.com/caddyserver/caddy/pull/7952
- rewrite: fix strip_path_suffix ignoring percent-encoding by @TowyTowy in https://github.com/caddyserver/caddy/pull/7877
- admin: stabilise log redaction test by @steadytao in https://github.com/caddyserver/caddy/pull/7942
- chore: fix canonicalheader failures by @steadytao in https://github.com/caddyserver/caddy/pull/7964
- cmd: upgrade automemlimit to v1.0.0 by @dunglas in https://github.com/caddyserver/caddy/pull/7978
- caddy: fix ParseNetworkAddress port-range span off-by-one by @mohammed90 in https://github.com/caddyserver/caddy/pull/7975
- usagepool: avoid lock inversion after constructor failure by @kojah in https://github.com/caddyserver/caddy/pull/7968
- cmd: reject ambiguous module version separators by @mohammed90 in https://github.com/caddyserver/caddy/pull/7974
- admin: fix origin allow-list host comparison to be case-insensitive by @mohammed90 in https://github.com/caddyserver/caddy/pull/7973
- caddyfile: fix importGraph self-loop and stale-edge bugs by @mohammed90 in https://github.com/caddyserver/caddy/pull/7971
- caddyhttp: remove unused QUICConfig from the HTTP/3 server by @faiyazrahmann in https://github.com/caddyserver/caddy/pull/7980
- fileserver: reject non-integer browse file_limit by @SashaMIT in https://github.com/caddyserver/caddy/pull/7988
- caddyhttp: surface write timeout errors in access log by @faiyazrahmann in https://github.com/caddyserver/caddy/pull/7945
- admin: fix host allow-list comparison to be case-insensitive by @hktitof in https://github.com/caddyserver/caddy/pull/7993
- caddytls: synchronize storage cleaner with TLS.Stop via context and WaitGroup by @jum in https://github.com/caddyserver/caddy/pull/7954
- httpcaddyfile: give each adaptation its own directive order by @faiyazrahmann in https://github.com/caddyserver/caddy/pull/7995
- listen: don't wedge a reloaded listener sharing a socket on Windows by @alexandre-daubois in https://github.com/caddyserver/caddy/pull/7999
- caddyhttp: demote Alt-Svc ErrNoAltSvcPort to debug level by @jum in https://github.com/caddyserver/caddy/pull/8000
- events: skip dispatch setup when nothing is subscribed by @u5surf in https://github.com/caddyserver/caddy/pull/7997
- reverseproxy: replace only known placeholders in health check body by @IslamElsayed in https://github.com/caddyserver/caddy/pull/8003
- acmeserver: say when the CA database is locked by another process by @faiyazrahmann in https://github.com/caddyserver/caddy/pull/8007
- fix: require module path boundaries when matching packages by @wangjingshuiku in https://github.com/caddyserver/caddy/pull/7957
- caddyhttp: preserve unknown placeholders in static response headers by @hktitof in https://github.com/caddyserver/caddy/pull/8014
- build(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.1 by @dependabot[bot] in https://github.com/caddyserver/caddy/pull/7984
- reverseproxy: propagate TCP half-close on upgraded streams by @btncwn in https://github.com/caddyserver/caddy/pull/8027
- build(deps): bump google.golang.org/grpc from 1.83.1 to 1.83.2 by @dependabot[bot] in https://github.com/caddyserver/caddy/pull/8028
- caddyfile: Expand imports inside named routes by @XiaoleC05 in https://github.com/caddyserver/caddy/pull/7986
- chore(deps): bump cel-go and switch import to new url by @techknowlogick in https://github.com/caddyserver/caddy/pull/8030
- core: synchronize Stop with concurrent config reloads by @H-XX-D in https://github.com/caddyserver/caddy/pull/8038
- reverse_proxy with versions 3 silently ignores tls_trust_pool and verifies against the system roots by @tippexs in https://github.com/caddyserver/caddy/pull/8042
- admin: fix warnings and status code in /load API by @amirdaraby in https://github.com/caddyserver/caddy/pull/7267
- fastcgi: explain 411 responses for unknown-length bodies by @Rohilalala in https://github.com/caddyserver/caddy/pull/7956
- Move websocket header normalization later by @nfreya in https://github.com/caddyserver/caddy/pull/7921
- chore: remove AI moderator workflow by @mohammed90 in https://github.com/caddyserver/caddy/pull/8059
- caddyhttp: surface 413 for oversized request body placeholders by @hktitof in https://github.com/caddyserver/caddy/pull/7969
- reverseproxy: Fix partial response not flushed to clients by @WeidiDeng in https://github.com/caddyserver/caddy/pull/7849
- caddyhttp: fix randString sameCase dictionary to match its docs by @mohammed90 in https://github.com/caddyserver/caddy/pull/7972
- requestbody: replace only known placeholders in the set body by @hktitof in https://github.com/caddyserver/caddy/pull/8008
- internal: fix
MaxSizeSubjectsListForLogoff-by-one whenmaxToDisplayis0by @mohammed90 in https://github.com/caddyserver/caddy/pull/7970 - caddyauth: only replace known placeholders in basic auth credentials by @hktitof in https://github.com/caddyserver/caddy/pull/8017
- map: Distinguish duplicate literal and regexp inputs by @Indra55 in https://github.com/caddyserver/caddy/pull/8067
- map: reject malformed destination placeholders by @sleet0922 in https://github.com/caddyserver/caddy/pull/8074
- httpcaddyfile: new
tls_automate_namesglobal option by @IslamElsayed in https://github.com/caddyserver/caddy/pull/8015 - build: bump all dependencies - (Go 1.26 floor) by @steadytao in https://github.com/caddyserver/caddy/pull/8056
- caddyhttp: wait for servers from previous configs on exit by @dunglas in https://github.com/caddyserver/caddy/pull/8009
- caddyhttp: use errors.AsType for request body limit errors by @mholt in https://github.com/caddyserver/caddy/pull/8090
- ci: pin cosign to v2 for release signing by @francislavoie in https://github.com/caddyserver/caddy/pull/8092
New Contributors
- @vijayvenkatj made their first contribution in https://github.com/caddyserver/caddy/pull/7800
- @AliMickey made their first contribution in https://github.com/caddyserver/caddy/pull/7802
- @bluegate-studio made their first contribution in https://github.com/caddyserver/caddy/pull/7809
- @alhudz made their first contribution in https://github.com/caddyserver/caddy/pull/7812
- @oksusucha made their first contribution in https://github.com/caddyserver/caddy/pull/7810
- @luccinmasirika made their first contribution in https://github.com/caddyserver/caddy/pull/7817
- @larrasket made their first contribution in https://github.com/caddyserver/caddy/pull/7827
- @Dean2026 made their first contribution in https://github.com/caddyserver/caddy/pull/7826
- @yintaisha made their first contribution in https://github.com/caddyserver/caddy/pull/7832
- @TowyTowy made their first contribution in https://github.com/caddyserver/caddy/pull/7869
- @thientd made their first contribution in https://github.com/caddyserver/caddy/pull/7858
- @PichuChen made their first contribution in https://github.com/caddyserver/caddy/pull/7884
- @futurehua made their first contribution in https://github.com/caddyserver/caddy/pull/7892
- @Salynn made their first contribution in https://github.com/caddyserver/caddy/pull/7886
- @SillyZir made their first contribution in https://github.com/caddyserver/caddy/pull/7898
- @jvoisin made their first contribution in https://github.com/caddyserver/caddy/pull/7847
- @firefart made their first contribution in https://github.com/caddyserver/caddy/pull/7903
- @renich made their first contribution in https://github.com/caddyserver/caddy/pull/7912
- @r0h1tb made their first contribution in https://github.com/caddyserver/caddy/pull/7922
- @ousamabenyounes made their first contribution in https://github.com/caddyserver/caddy/pull/7924
- @ittakestwo123 made their first contribution in https://github.com/caddyserver/caddy/pull/7940
- @bzyy1024 made their first contribution in https://github.com/caddyserver/caddy/pull/7934
- @faiyazrahmann made their first contribution in https://github.com/caddyserver/caddy/pull/7958
- @gautamrizwani made their first contribution in https://github.com/caddyserver/caddy/pull/7894
- @0jaspahwa made their first contribution in https://github.com/caddyserver/caddy/pull/7960
- @AmariahAK made their first contribution in https://github.com/caddyserver/caddy/pull/7910
- @DavidCarliez made their first contribution in https://github.com/caddyserver/caddy/pull/7952
- @kojah made their first contribution in https://github.com/caddyserver/caddy/pull/7968
- @SashaMIT made their first contribution in https://github.com/caddyserver/caddy/pull/7988
- @hktitof made their first contribution in https://github.com/caddyserver/caddy/pull/7993
- @IslamElsayed made their first contribution in https://github.com/caddyserver/caddy/pull/8003
- @wangjingshuiku made their first contribution in https://github.com/caddyserver/caddy/pull/7957
- @btncwn made their first contribution in https://github.com/caddyserver/caddy/pull/8027
- @XiaoleC05 made their first contribution in https://github.com/caddyserver/caddy/pull/7986
- @H-XX-D made their first contribution in https://github.com/caddyserver/caddy/pull/8038
- @tippexs made their first contribution in https://github.com/caddyserver/caddy/pull/8042
- @amirdaraby made their first contribution in https://github.com/caddyserver/caddy/pull/7267
- @Rohilalala made their first contribution in https://github.com/caddyserver/caddy/pull/7956
- @nfreya made their first contribution in https://github.com/caddyserver/caddy/pull/7921
- @Indra55 made their first contribution in https://github.com/caddyserver/caddy/pull/8067
Full Changelog: https://github.com/caddyserver/caddy/compare/v2.11.4...v2.11.6