Build ngx_pagespeed from source

The maintained PageSpeed module for nginx is open source, and the full source tree is public at We-Amp/mod_pagespeed. It ships as a signed, prebuilt package for the common distributions, so most installs never compile anything. Build from source when you run a custom nginx, or a distribution without a signed package.

Recommended — install the maintained module from the signed repository. It's prebuilt and pinned to your distribution's nginx: no toolchain, and no rebuild every time you upgrade nginx.

Add the signed repository
curl -fsSL https://packages.modpagespeed.com/install.sh | sudo sh
sudo apt install nginx-module-pagespeed   # Debian / Ubuntu
sudo dnf install nginx-module-pagespeed   # AlmaLinux / RHEL 9 and 10
Full install guide

When to build from source

nginx loads a dynamic module only if it was built against the exact nginx version and configuration it loads into — --with-compat does not relax that. The signed packages are therefore built against each distribution's stock nginx. Build from source when:

You run a custom nginx — the nginx.org repository, a self-compiled binary, or a build with extra modules — so no published package matches it.

Your distribution has no signed package — the packages cover Debian, Ubuntu, and the EL9/EL10 family; Amazon Linux and other distributions take this path.

You want to read or change the code. The nginx module lives in pagespeed/nginx/ of the mod_pagespeed tree, next to the Apache, IIS and Envoy integrations. Contributions go through that repository.

The build is one script. It compiles the module's optimization library with Bazel and then links the nginx glue with nginx's own ./configure --add-dynamic-module=… --with-compat and make modules, so the module's version stamp matches the nginx it will load into. It runs inside a container of the distribution you deploy to, because the module inherits the build host's glibc floor: a module built on a newer distribution will not load on an older one.

Step 01

Get the source tree

Clone the public repository and check out the latest release tag. You need Docker on the build machine; everything else is installed inside the build container.

Clone the module source
git clone https://github.com/We-Amp/mod_pagespeed.git
cd mod_pagespeed
git checkout "$(git tag --list 'v*' --sort=-v:refname | head -1)"   # latest release tag

Step 02

Vendor the build dependencies

The container build runs offline, so populate the vendor/ directory once: the Bazel repository cache plus the Cyclone Cache source. The script needs Bazel (or bazelisk) and network access; the repository's dev container has both.

Start the build container
docker compose up -d
docker compose exec dev tools/vendor-deps.sh
docker compose down

On a machine that already has bazelisk, run tools/vendor-deps.sh directly instead.

Step 03

Match your nginx version

Check the version you run. For a distribution's stock nginx, the build script fetches the matching source itself — on Ubuntu and EL it uses the distribution's own patched source, because a distro security update can change nginx's internal structures without changing the version number.

Check the nginx version
nginx -v

For a custom nginx, pin the exact release tarball: download it from nginx.org, verify its signature, and note its checksum. The build script refuses an unverified tarball.

Download the nginx source
curl -fsSLO https://nginx.org/download/nginx-1.26.3.tar.gz   # substitute your version
sha256sum nginx-1.26.3.tar.gz

Step 04

Build inside the target distribution's container

Start a container of the distribution you deploy to, with the source tree mounted, and run the build script for that target. It installs the toolchain, fetches and pre-configures the nginx source, and builds the module.

Build the module
# Debian 12 shown; use the image of the distribution you deploy to
docker run --rm -it -v "$PWD":/src -w /src debian:12 bash

# Inside the container — stock nginx:
install/nginx/build_module_in_container.sh bookworm

# Inside the container — custom nginx version (checksum from step 3):
NGINX_SRC_VERSION=1.26.3 NGINX_SRC_SHA256=<sha256 of the tarball> \
  install/nginx/build_module_in_container.sh bookworm

Targets: bullseye, bookworm, trixie (Debian 11, 12, 13); jammy, noble (Ubuntu 22.04, 24.04); el9, el10 (AlmaLinux, Rocky Linux, RHEL). The script's header documents the remaining overrides, including building against a vanilla nginx.org tarball on Ubuntu or EL. The result is bazel-bin/pagespeed/nginx/ngx_pagespeed_module.so, built for the container's architecture — run the build on an arm64 host for an arm64 module.

Step 05

Install, load, and verify

Copy the module into the nginx modules directory and load it:

Copy the module into place
sudo cp bazel-bin/pagespeed/nginx/ngx_pagespeed_module.so /usr/lib/nginx/modules/   # Debian / Ubuntu
sudo cp bazel-bin/pagespeed/nginx/ngx_pagespeed_module.so /usr/lib64/nginx/modules/ # EL
# At the top of nginx.conf, before the events block:
load_module modules/ngx_pagespeed_module.so;

Add a minimal pagespeed configuration (see the configuration reference), then reload nginx and confirm the X-Page-Speed header:

Test and reload nginx
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://yoursite/ | grep -i x-page-speed

Rebuild the module whenever you upgrade nginx. If a distribution security update changes nginx's internals under a module built earlier, the module detects the mismatch on the first request and degrades to pass-through with one alert in the error log instead of misbehaving.

The legacy open-source module

Google's original ngx_pagespeed remains archived at apache/incubator-pagespeed-ngx, together with its wiki on building PSOL from source. It has had no security patches since 2020 and none of the current features. The maintained tree above is its drop-in continuation — existing pagespeed directives keep working — so build from it rather than from the archive.

Licensing

mod_pagespeed 2.1 is open source under the Apache License 2.0 and free to install and run, in development and in production — no key, no token, no registration. Building from source does not change that.

Back to the install hub