Release notes: 2.3
Last updated Edit this page View as Markdown
mod_pagespeed 2.3.0 release notes: the module and the optimizer worker as one release (packages 1.18.0), with rule packs and security fixes.
mod_pagespeed 2.3.0 is the current release: the module and the optimizer worker, released together on 2026-10-12 and installed as a matching pair. In the signed apt and yum repositories both parts carry the package version 1.18.0; 2.3.0 is the version of the container images and the NuGet packages and the application version of the Helm chart (chart 0.3.7). The release notes index lists every release of every line, and Security updates lists every security fix we have published with the release that carried it.
mod_pagespeed 2.3.0 2026-10-12 module + optimizer worker
mod_pagespeed 2.3.0 adds rule packs and is a security and reliability update for the module and the optimizer worker, released together and installed as a matching pair. In the signed apt and yum repositories both parts carry the package version 1.18.0; 2.3.0 is the version of the container images and the NuGet packages and the application version of the Helm chart (chart 0.3.7). Rule packs let the module add or correct the canonical link, title, meta description, hreflang cluster and JSON-LD of your pages from a JSON file, in report mode first. The release stops some animated images from tying up a server worker, updates Envoy for the Envoy filter, and fixes stale copies of changed CSS, JavaScript and image files in the optimizer worker. On Apache, nginx and IIS the optimizer worker no longer serves HTML; see “Before you upgrade”. Update recommended.
Security
Security: resource exhaustion, image optimization. Some animated images could tie up a server worker. Animated image conversion now stops at a configurable frame limit. Affected: releases up to and including 1.17.0 with image conversion enabled. Update recommended. Animations above the limit are no longer converted; see “Before you upgrade”.
Security: dependency update, Envoy filter. The Envoy filter builds against Envoy 1.37.6, which fixes the Envoy security advisories published on 2026-08-26. Affected: the Envoy filter in releases up to and including 1.17.0, built against Envoy 1.37.5 or older, which lack these fixes. Update recommended.
Security: the nginx bundled with the NuGet sidecar package is updated to 1.30.5. It carries the upstream fix for CVE-2026-90439 in nginx’s HTTP/3 module. The bundled nginx is not built with HTTP/3, so it was not affected; the update keeps vulnerability scans clean.
Before you upgrade
Breaking: the optimizer worker no longer serves HTML on Apache, nginx and IIS. Every HTML response is rewritten by the module’s filter chain; CSS, JavaScript and images are served by the optimizer worker as before. HTML no longer gets the optimizer worker’s own HTML improvements (such as critical CSS and LCP hints); it keeps the module’s own HTML rewriting. On a host with the optimizer worker enabled, the ipro_daemon_fallthrough statistic now rises on HTML requests; adjust any alert on that statistic.
Breaking: animated images with more than 200 frames are no longer converted. An animated GIF with more frames than the new ImageMaxAnimatedFrames (default 200; 0 or a negative value disables the limit) is served unconverted. It can be set in the server, virtual-host or directory configuration, but not through query parameters or request headers. Raise it if you rely on converting longer animations.
Changed (Debian and Ubuntu): if you removed the package with 1.17.0 or earlier and reinstall it, run a2enmod pagespeed once. Newer removals are re-enabled automatically. The package does not restart Apache: run systemctl restart apache2 after the first install.
Rule packs
Added: rule packs. The new rule_packs filter applies a rule pack, a JSON file of rules for the head of your HTML pages, on Apache, nginx and IIS. The rule packs guide has the full reference.
- What it does and how to turn it on. A rule can add a missing canonical link, title, meta description, hreflang cluster or JSON-LD block and remove exact duplicates (
keep, the default), also remove unusable, empty or misplaced copies (repair), or make the page carry exactly the rule’s value (replace). A canonical rule can also keep theLink: rel="canonical"response header in line with the page. Nothing else in the page is edited, and applying a pack fetches nothing over the network. The pack id must beedge-seo; one pack file per server or virtual host. The filter is off by default and in no rewrite level: turn it on withEnableFilters rule_packsand pointRulePackFileat the pack, both in the server or virtual-host scope (Apache:ModPagespeedEnableFilters rule_packsandModPagespeedRulePackFile; nginx: in theserverblock; IIS: at the top level of the site’spagespeed.config).RulePackFileandRulePackModecannot be set in.htaccess,<Directory>, an nginxlocationblock or an IIS match block; in.htaccesssuch a line makes Apache answer 500 for that directory. - Modes and enforcement. A pack starts in report mode: it records what it would change and serves the page unchanged. A rule changes pages only when
RulePackMode enforce, the site’smodeand the rule’senforceall say so. A pack that fails to load leaves the last good pack in use (or the filter off when there is none), and the filter is designed not to fail a response: a page, or the part of a page, it cannot edit safely is left as the origin sent it. - Reload and cache signature. A changed pack file is picked up on a reload, or by a server process the next time it needs the pack once 10 seconds have passed since its last check, so processes can disagree for up to 10 seconds. Enabling the filter on a server changes its cache signature, so that server’s cached resources are rebuilt once.
- Apache early flush. On a host whose pack has a canonical rule with
link_headerset tomatch, response headers go out with the first body bytes or at the end of the response, not on an early flush, so that theLinkheader can still be edited. An origin that flushes its headers early to start browser preloads loses that head start on such a host; a pack without that rule leaves early flushes alone, except that the first response in each server process can still be held until the pack has been read. - Decision log. Decisions are written to
<LogDir>/packs/<pack-id>/decisions-YYYY-MM-DD.jsonl(UTC dates; repeats are suppressed per process; count distinct keys, not lines): about 50 MiB per day across all server processes (after that the rest of the day’s lines are dropped and counted), the newest 14 calendar days kept (today and 13 earlier), no log whenLogDiris empty. Do not rotate or delete the current day’s file. Lines carry the request path with its query string and, for removed elements, their values in clear text, but no client address, cookies or user agent; files are created mode 0640 on Linux and macOS. Treat the log like an access log. Requesting a page with?PageSpeedFilters=+debugshows a comment before each change the pack makes, or would make in report mode. - Admin page. A read-only Rule packs page in the admin pages (
/pagespeed_admin/rule_packs), behind the same access restrictions as the other admin pages and reachable from the admin console’s sidebar. It shows, for the virtual host you ask, whether the filter is on, the pack file and mode, the pack the answering server process has loaded (id, version, publisher, hash, load state, last load error), therule_pack_*statistics, two static links, to the packs catalogue and to the documentation (the server makes no request for them), and the newest lines of today’s (UTC) decision log, filtered with?rule=,?action=,?reason=and?limit=(default 100, up to 1000), or as plain text with?raw=1. - Statistics.
rule_pack_*statistics, per virtual host withUsePerVHostStatistics on, for pack loads and load errors, pages evaluated, modified and that would be modified, pages skipped (host not listed, no head, malformed head, not rewritable, size limit), decisions applied and that would apply, late elements removed and left in place,Linkheader changes, and decision-log lines written and dropped. There are no per-rule counters; the decision log has the per-rule detail. - Limits. A pack loads only within 1 MiB, 200 rules and 50,000 table entries. A page gets at most 64 KiB of added content, and a value longer than 2,048 bytes for a URL, 300 characters for a title, 1,000 characters for a description or 16 KiB of expanded JSON-LD is not applied. The full list is in the rule packs guide.
- Signed packs. A pack file may carry an Ed25519 signature in a
.sigsidecar;RulePackTrustKeynames a trusted publisher key andRulePackRequireSigned(off by default) refuses a pack without a valid signature. WithRulePackRequireSignedoff, a pack without a valid signature still loads and logs a warning once per file version per server process; a second warning gives the reason when a signature file is present but fails its check. Sixrule_pack_*statistics count the outcomes, andtools/rule-packs/sign-pack.shin the source tree signs and verifies packs. See Signed packs.RulePackTrustKeyis not available on Envoy. - Licence fields. The
packobject may carry alicenseobject with anentitlementname, anexpiresdate (YYYY-MM-DD) and atermsURL (https://). The module checks their format and writes them to the server log (at info level) once per pack version per server process, when that version is first used; they are informational and do not change what the pack does. The top-level keysignatureis reserved; a pack that uses it does not load.
Added: a free edge-SEO rule pack template, packs/edge-seo/pack.example.json, with a README, for the rule_packs filter of mod_pagespeed 1.18.0 and later. It lists one placeholder host in report mode and one rule per kind (canonical, title, description, hreflang, JSON-LD); replace the example values with your own. It is not signed.
Optimizer worker
Fixed: after a file changed on the origin, mod_pagespeed could keep sending the previous version of a CSS, JavaScript or image file until the old copy’s cache lifetime ran out. For CSS and JavaScript every client was affected. For images, the converted WebP and AVIF copies could stay stale for every client that accepts them, and with DaemonServeStoredEncodings on so could the gzip and brotli copies, while other clients already got the new version. The optimizer worker now replaces its stored copies as soon as the web server has recorded the new version. If you have been resetting the optimizer worker’s cache after each deploy to work around this, that is no longer needed.
Fixed: with gzip_level or brotli_level set to 0, the optimizer worker never learned whether a CSS, JavaScript or unsupported-image file had really changed. After the origin changed, each re-record of the file made it purge and rebuild its stored copies, at most once per URL every 10 seconds, and clients received unoptimized bytes until the rebuild finished. The optimizer worker now tracks the file whenever the encodings that are turned on have been stored, so a file whose bytes did not change is simply refreshed instead of rebuilt.
Fixed (Linux): the optimizer worker’s Debian package no longer aborts configuration when systemctl daemon-reload fails during install or upgrade; the RPM scriptlet is guarded the same way.
Added: the worker’s --help output now lists --agent-render-allow-hosts with its default and meaning. The flag itself is unchanged.
Changed: the bundled crossbeam-epoch library is updated to 0.9.20 (RUSTSEC-2026-0204), so dependency scanners no longer report it.
Changed: the packaged systemd unit describes the service as the “PageSpeed Optimizer Worker” (what systemctl status shows) and the README calls the optimizer process the worker throughout. Names that keep the word daemon for compatibility (the pagespeed_daemon.conf file, CLI flags, API paths and metric names) are unchanged.
All servers
Fixed: JavaScript minification now handles a comment between the * of an object or class generator method and its name (for example { */* c */await(){} }). Such scripts were previously left unminified when the method was named await or yield; they are now minified like the same code without the comment. In the optimizer worker the output also no longer differs between passes.
Fixed: the built-in fetcher no longer takes a 100 Continue or 103 Early Hints interim response for the final response: the origin’s real status and headers are used. Before, such a fetch completed with the interim status and headers only.
Fixed: the log line for a fetch that failed in the built-in fetcher now carries libcurl’s own explanation and, when a proxy refused the CONNECT request of an HTTPS fetch, the proxy’s answer to CONNECT, for example proxy CONNECT response 405.
Fixed: fetch, rewrite and shutdown deadlines are no longer cut short or stretched when the system clock is adjusted.
Apache
Fixed: a HEAD request or an empty-body HTML response no longer loses the origin’s Link, Set-Cookie and other response headers.
Fixed (Debian and Ubuntu): the package upgrade no longer re-enables the module, or the pagespeed_libraries and pagespeed_daemon confs, that you disabled with a2dismod or a2disconf. They are enabled on a first install or a reinstall after removal (the daemon conf is also enabled once when upgrading from a release that did not ship it); upgrades and dpkg-reconfigure leave your choice alone. See “Before you upgrade” for a reinstall after a removal with 1.17.0 or earlier.
IIS and Windows
Fixed: on Windows, AVIF conversion (and WebP conversion when a WebP time limit is set) is no longer abandoned as timed out right away.
Rule packs on IIS are configured at the top level of the site’s pagespeed.config, not inside a host: match block; keep the pack outside the web root, readable by the application pool identity.
Release files
Added: each release now also publishes its software bill of materials (SPDX) and its vulnerability exploitability statements (OpenVEX) as release assets, pagespeed-1.1-<version>.spdx.json and pagespeed-1.1-<version>.vex.json. They are signed like the packages and listed in SHA256SUMS.
Fixed: the release SHA256SUMS file lists each downloadable file once, under the name it has on the release page, so sha256sum -c SHA256SUMS works on the downloaded files as they are. Earlier releases could list a file twice, or under a name with ~ where the download has ..
Added: the nginx module tarball and the legacy IIS zip now carry LICENSE, NOTICE and THIRD-PARTY-NOTICES at the top of the package directory, as the deb and rpm packages already do.