Our Life Together  >  Thoughts  >  Adding PageSpeed to an Already-running NGINX Instance  —  { code }

How can you add a dynamic PageSpeed module to an already-built instance of NGINX?

For install automation, I’ve summarized the codes and minimal settings in this Bash script. This script was tested to work on the latest stable version of NGINX. If it’s your first time to compile this, feel free to execute the codes step-by-step. It will help you troubleshoot any peculiarities on your system.


You may choose to automate the installation by simply running the script above. In its default settings, it will process the version number you will pass to it. To get your NGINX’s version number run this command:

nginx -v
nginx version: nginx/1.17.1

Since the version number in this example is 1.17.1, after you have downloaded the bash script above, go to the directory where the script is and run these commands:

chmod +x mkpagespeed
./mkpagespeed 1.17.1

Building PageSpeed may take a few minutes and could be a bit resource-intensive, especially on a server with modest specs. If the script runs through errors please let me know so I may make adjustments to it.

Loading the module

To activate PageSpeed, add this line to NGINX’s main configuration file (mine was at /etc/nginx/nginx.conf), outside any block { ... }, on the top-most section of the config file:


load_module modules/ngx_pagespeed.so;

# http {
#   ...
# }

If you are not sure what your NGINX config file path is, run this command:

nginx -V 2>&1 | grep -o 'conf-path=[^ ]*' | sed 's/conf-path=//'
Configuring filters

What PageSpeed does to your served pages and assets may be fully customized via filters. There are a plethora of configurations to choose from. A pre-selected set of default filters may be activated through:

pagespeed RewriteLevel CoreFilters;

Still, don’t we normally want to fiddle with every little bit of our configuration? Here’s what’s included in my server block:


I also set up PageSpeed Admin Pages, which required the FileCachePath directive to be declared with it. While the Admin Pages location blocks can be retained inside the server block, Admin Pages are declared within the http block, which is outside the server block:


Updating the module

One potential problem with dynamic modules is when NGINX automatically upgrades via a package manager (e.g. apt, yum, or pacman). If you’re like me, all upgrades in my server are automated by scripts. That may cause a snag because dynamic modules are version-specific. NGINX is set not to load modules that were built for a different NGINX version. So how can PageSpeed modules automatically upgrade when NGINX makes an unattended upgrade?

The answer is to make a hook to the package manager during upgrades. In apt this may need making two or three simple scripts:

  1. Hook to apt and call a worker script. (Alternatively, the hook could directly call mkpagespeed and thus skip the need for a worker script.)
  2. The worker script calls one or more build scripts to update the dynamic modules.
  3. Build scripts will build and install the new modules just before NGINX upgrades.

Here is how a hook file could look like in /etc/apt/apt.conf.d/:


And the worker script could contain this:


# Call NGINX module build scripts and pass error codes to apt hook

# Get NGINX version to upgrade to
read ngfile < <(grep '/nginx_') || exit 0
ngver=$(echo $ngfile | sed 's/-.*//' | sed 's/.*_//')

# List of build scripts to run:
/usr/local/sbin/mkpagespeed $ngver || exit $?
# /usr/local/sbin/mkbrotli $ngver || exit $?
# /usr/local/sbin/mkmodsec $ngver || exit $?

This worker should point to our build script earlier, that is, mkpagespeed. So there, dynamic module + dynamic upgrades = chill & relax. 😎 Enjoy speed! ⚡

Brotli compression

Google has another open-source project for the next-generation compression called Brotli. If you’re interested with Brotli, you can check this post: Adding Brotli to an Already-built NGINX Instance.


Categories: Thoughts

Majal Mirasol

Servant of the Creator happily married to Jehovah’s slave girl.

While Majal was absorbed in training for a good foundation in the Maths and Sciences, he learned that there is more to life than simply elucidating complex designs in our universe. He realized that there is a Designer. The Source of our order, an order much superior than what our human brains could conceive.


Niels · November 17, 2019 at 4:55 pm

Hello, im trying to use the script for my website of course but i got the same error => “nginx: [emerg] module “/etc/nginx/modules/ngx_pagespeed.so” is not binary compatible in /etc/nginx/nginx.conf:1″

I all ready try to add some argument like –with-cc-opt=’-DNGX_HTTP_HEADERS’ but i got the same problem

    Majal Mirasol · November 18, 2019 at 3:31 pm

    Hi Niels! I’m sorry but I still don’t know why this doesn’t work on other systems. Would it be possible for you to supply us with your specific system setup?

    James Botkin · July 19, 2020 at 10:05 am

    Got similar problem. Not binary compatibe means the args/option isn’t the same build. here’s how I do it.

    $ nginx -V
    – copy all args, and see your version.
    – delete all local args (which having local reference ( =tmp/BlabLa/.. ). calm down, the script reference you back what module isn’t installed.

    modify mkpagespeed on line 38:
    nice -n 19 ionice -c 3 bash <(curl -f -L -sS https://ngxpagespeed.com/install) -n ${ngver} -m -b ${builddir} -a ‘YOUR ARGS HERE’ -y || { echo ‘!! error with module creation, exiting…’; exit 1; }
    – be sure to use ” because all args/option inside an ‘.

    in your case:
    nice -n 19 ionice -c 3 bash <(curl -f -L -sS https://ngxpagespeed.com/install) -n ${ngver} -m -b ${builddir} -a ‘-with-cc-opt=”-DNGX_HTTP_HEADERS”‘ -y || { echo ‘!! error with module creation, exiting…’; exit 1; }

    chmod +x and Run mkpagespped
    $ ./mkpagespeed yournginxversion

    Then, check the moddir, is it .so. or .so.old, if .so.old, rename it to .so.

    For check only:
    Then load pagespeed module at nginx.conf in any outside bracket of http or server.
    load_module modules/ngx_pagespeed.so;

    Reload nginx configuration.
    if the configuration reloaded with no error then you are good to make pagespeed on and adding another option, don’t forget to reload nginx after.

    Note: if you have “–with-debug” args, just strip it off. nginx pagespeed doesn’t suppoer –with-debug, and Yes, it will produce same binary.

      Majal Mirasol · July 19, 2020 at 10:11 am

      Awesome solution James. Thank you. I’m sorry I haven’t paid attention on this one for so long. I’ll update this when I have time. Thanks for posting back the solution. Will be helpful to future readers. 🙂 Have a good and safe day!

solut2000 · May 31, 2020 at 3:05 pm

It works great! thx!

James Botkin · July 19, 2020 at 12:35 am

IF i run the script the way it is. the configuration will not match. return:
nginx: [emerg] module “/usr/share/nginx/modules/ngx_pagespeed.so” is not binary compatible in /etc/nginx/nginx.conf:2

IF I modify the script to get matching configuration. Pagespeed have no –with-debug option etc.

    James Botkin · July 19, 2020 at 9:42 am

    Now, it works!
    I strip all the local defined option. With no “–with debug” agrs.
    Somehow the script not renaming back from ngx_pagespeed.so.old to .so, I rename it to .so, update nginx.conf and reload it.

    Also I modify the script to access pagespeed admin with .htpasswd, more simple than setup vpn or specify IP to access it.


Gregory · September 6, 2020 at 9:12 pm


I can’t make it works with cloudflare and Let’s Encrypt

Beginning of my server block:

server {
listen 80;
listen [::]:80;

server_name domain.com www.domain.com;

root /var/www/html;

# Add index.php to the list if you are using PHP
index index.php index.html index.htm index.nginx-debian.html;

# Pagespeed
pagespeed on;

pagespeed SslCertDirectory /etc/letsencrypt/live/domain.com;
pagespeed SslCertFile /etc/letsencrypt/live/domain.com/cert.pem;

pagespeed MapOriginDomain "http://domain.com" "https://www.domain.com";

# WordPress-specific configurations, change according to your domain and installation path

pagespeed LoadFromFile https://www.domain.com/wp-content/ /var/www/html/wp-content/;
pagespeed LoadFromFile https://www.domain.com/wp-includes/ /var/www/html/wp-includes/;

any ideas?


    Majal Mirasol · September 8, 2020 at 11:50 am

    Hi Gregory! Thanks for stopping by. PageSpeed acts on the produced HTML before it is sent to Cloudflare. Does your site work if you disabled PageSpeed? If it does, then there your Cloudflare and SSL configurations are okay, and we can focus on PageSpeed configs. If it does not work, they you’ll have to fix those first.

    PageSpeed configs are a bit tricky. You’ll have to experiment on what doesn’t break your site. At a quick glance though, I noticed that you used domain.com in your confs? I mean you should change it to your actual domain name if you have not done so yet.

Bùi Lê Chí Bảo · June 19, 2021 at 12:37 am

Thank you! It worked on Centos 7 and Nginx 1.20.1!

Josh J. · March 15, 2022 at 3:51 am

What is wrong?

bash: ./mkpagespeed: /usr/bin/bash^M: bad interpreter: No such file or directory

Leave a comment