yum upgrades for production use, this is the repository for you.
Active subscription is required.
Technical Briefing: ngx_pagespeed on Modern NGINX (Operational Reference)
The 2026-10-16 and 2026-10-17 briefings covered why the classic build fails and walked through the packaged fix. Today’s source is the same GetPageSpeed article with no new developments. This edition is a condensed operational reference. It focuses on channel behavior, version-locking, licensing, and fleet-level drift, which matter when running the module long-term.
Recap: Why the Classic Build Fails
The classic PSOL + ./configure --add-dynamic-module=../incubator-pagespeed-ngx build fails for these reasons:
- The project is retired. Apache retired ngx_pagespeed on 2023-03-17. The final NGINX 1.23.0 compatibility commits were never tagged in a release.
- NGINX 1.23 changed the header API.
r->headers_out.cache_controland similar fields moved fromngx_array_tto a linked list ofngx_table_elt_t. The build breaks on every NGINX from 1.23.0 onward. - PSOL is too old for current glibc. PSOL 1.13.35.2 (2018) references removed or renamed symbols:
sys_siglist,pthread_yield,pthread_mutex_consistent_np,pthread_mutexattr_setrobust_np, and a privategettid. On EL9 (glibc 2.34) and newer, it fails to link or fails atnginx -twith adlopenundefined-symbol error. Rebuilding PSOL isn’t practical because upstream moved to Bazel in 2020. - PSOL is x86_64 only. There was never an aarch64 build.
Choosing a Line: Stable vs. v2 Beta
| Stable | v2 beta | |
|---|---|---|
| Codebase | Original module 1.14.36.x + maintained PSOL rebuild with glibc fixes | From-scratch re-implementation (2.1.0 beta) |
| Architectures | x86_64 | x86_64 and aarch64 |
| Distributions | EL8 and newer | EL9 |
| AVIF | No | Yes |
| Channel | getpagespeed-extras (default) |
getpagespeed-extras-testing (opt-in) |
About v2:
– It is proprietary, supported, and a superset of the original module.
– It contains no PSOL blob. It is built on C++20 with current abseil, protobuf, and image codecs, so it compiles against NGINX 1.30 and glibc 2.34 without patches.
– Existing pagespeed configs carry over.
Licensing: All package downloads require an active NGINX Extras subscription.
Channel Behavior
How you install determines which line dnf upgrade follows afterward.
| Goal | Command |
|---|---|
| Add repo (defines testing channel, disabled by default) | `sudo dnf install -y https://extras.getpagespeed.com/release-latest.rpm` |
| One-time v2 install | sudo dnf install -y --enablerepo=getpagespeed-extras-testing nginx nginx-module-pagespeed |
| Keep upgrades on v2 instead of falling back to stable | sudo dnf config-manager --set-enabled getpagespeed-extras-testing |
| Stable 1.14.36.x on x86_64 | sudo dnf install -y nginx nginx-module-pagespeed |
- Use
--enablerepoalone for a one-off install. Without the persistentconfig-managerstep, later upgrades can fall back to stable. - SELinux works in enforcing mode.
nginx-module-pagespeed-selinuxis pulled in automatically. - Example aarch64 result:
nginx-3:1.30.6-73.el9.gps.aarch64nginx-module-pagespeed-1:1.30.6+2.1.0~beta13-1.el9.gps.aarch64
Minimum Configuration
1. Load the module. Put this at the very top of /etc/nginx/nginx.conf, above the events and http blocks:
load_module modules/ngx_pagespeed.so;
2. Enable PageSpeed in /etc/nginx/conf.d/pagespeed.conf. The package already creates /var/cache/pagespeed with the correct ownership.
pagespeed on;
pagespeed FileCachePath /var/cache/pagespeed;
pagespeed RewriteLevel CoreFilters;
pagespeed EnableFilters convert_jpeg_to_avif,convert_png_to_avif;
CoreFilters is the safe default set. The AVIF filters work only on v2.
3. Add handler locations to each server block you want optimized:
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; }
location ~ "^/pagespeed_static/" { }
location = /ngx_pagespeed_beacon { }
4. Test and reload: sudo nginx -t then sudo systemctl reload nginx
Debian/Ubuntu:
– Install the stable module with sudo apt-get update then sudo apt-get install nginx-module-pagespeed.
– No load_module line is needed because loading is handled automatically.
– The v2 beta is available in the opt-in Ubuntu 24.04 testing suite.
Verification
1. Warm the cache. Request the test page several times:
curl -s -H 'Accept: image/avif,image/webp,*/*' -H 'X-PSA-Blocking-Rewrite: psatest' -o /dev/null http://localhost/demo/index.html
The blocking-rewrite header forces the rewrite to finish before the response. It is useful for testing but should not be sent in production.
2. Check the module header:
curl -sI http://localhost/demo/index.html | grep -i x-page-speed
Expected output: X-Page-Speed: 2.1.0.0-d75c77c
3. Reported results:
– The small CSS and JS files were minified and inlined.
– A 241 KB JPEG was resized to its displayed size (256×192) and converted to AVIF at /demo/256x192xPuzzle.jpg.pagespeed.ic.qzgc6lSV9x.avif.
– The response returned Content-Type: image/avif, Content-Length: 4145, X-Original-Content-Length: 241260, and Cache-Control: max-age=31536000.
– That is 241,260 bytes reduced to 4,145 bytes, with no build step and no PSOL download.
v2.1.0-beta13 Changes (2.1.0~beta13)
- AVIF recompression: Images that are already AVIF are recompressed to the configured quality instead of passed through.
- Hardening:
- size limits on HTML tokens and fetched bodies
- a guard in the image sprite filter
- safe handling of Subresource Integrity–protected resources
- bounds checks on image quality options
- stripping
s-maxagealong withmax-agewhen PageSpeed disables caching on optimized HTML, so shared caches can’t keep stale copies
- WebP fallback: Safari 16+ and Firefox 132+ omit image formats from the Accept header on HTML navigations. Beta13 detects them by version and serves lossy WebP URLs instead of the original format.
- Caveat: This is a beta. It won’t replace stable unless the testing channel is enabled. Validate it on staging first.
Version-Locking and Drift
The module is version-locked to its matching GetPageSpeed NGINX build. Most operational failures come from that lock.
| Symptom | Cause / Fix |
|---|---|
requires nginx-r1.30.5, but none of the providers can be installed |
A newer NGINX is already installed, or was published before the matching module rebuild landed. Install nginx and nginx-module-pagespeed in the same dnf transaction. |
unknown directive "pagespeed" |
The load_module line is missing or sits inside the http block. It must be at the top level of nginx.conf. |
| Pages not rewritten | PageSpeed only rewrites text/html, and the first requests populate the cache. Reload several times, then look for .pagespeed. URLs in the HTML or check the X-Page-Speed header. |
| NGINX from nginx.org or the distro | Remove it and install both packages from the GetPageSpeed repository. |
Fleet-level concern: Version-locked modules can still drift when hosts are upgraded one at a time. For fleet-wide monitoring, the article points to GetPageSpeed Amplify. It runs scheduled gixy scans tied to runtime metrics and is drop-in compatible with the deprecated nginx-amplify-agent (EOL January 2026).
Practical Payoff
- No patching required. A version-matched package avoids the dead-end of patching the original module on x86_64 and the impossibility of running it on aarch64.
- v2 adds capabilities. It brings AVIF conversion and ARM64 support while keeping existing configs compatible.
- The main ongoing discipline:
- Upgrade NGINX and the module together.
- Be deliberate about whether hosts track the stable or testing channel.
Read the full article: ngx_pagespeed Won’t Build on Modern NGINX? Install It
