Skip to main content
mod_pagespeed 2.1 is here — open source (Apache-2.0): the module you know, plus the optimizer worker

Run in production

Production deployment guide for the mod_pagespeed 2.1 ASP.NET Core middleware: configuration, health probes, multi-instance scale, and zero-downtime restarts.

On this page

This page is for teams shipping the mod_pagespeed 2.1 ASP.NET Core middleware (WeAmp.PageSpeed.AspNetCore) into a production ASP.NET Core deployment. If you are still evaluating the middleware locally, start with Install ASP.NET Core middleware instead.

The current NuGet release is v2.1.0. The middleware runs in-process in your request pipeline and, by default, launches the factory_worker binary from the same package as a child process to do the expensive work — image transcoding and critical-CSS extraction — out of process. If you need an in-process native module for Apache, nginx or IIS instead, see mod_pagespeed 2.1, where the module runs in-process in the web server. The IIS package ships from the 1.15 packaging channel.

Prerequisites

  • .NET 8 or .NET 10 runtime on your production host.
  • An ASP.NET Core application that serves HTML responses.
  • A supported runtime identifier — linux-x64, linux-arm64, osx-arm64, or win-x64. The meta-package resolves the matching native asset automatically at restore time.

Install

Add the NuGet package to your project. CI restores the correct native library for the target RID — no per-platform branching in your build.

dotnet add package WeAmp.PageSpeed.AspNetCore

If your build container differs from the deployment target, restore with an explicit RID so the native asset matches the production host:

dotnet publish -c Release -r linux-x64 --self-contained false

Wire up the middleware

Register the services and add UsePageSpeed() early in the pipeline, before any middleware that writes to the response body:

using WeAmp.PageSpeed.AspNetCore;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddPageSpeed(builder.Configuration);

var app = builder.Build();
app.UsePageSpeed();
app.MapHealthChecks("/healthz");
app.MapRazorPages();
app.Run();

Bind a PageSpeed section in your configuration. For the full set of PageSpeedOptions properties and hot-reload semantics, see the ASP.NET Core configuration reference.

Cache backing

The middleware writes a single memory-mapped Cyclone volume file under PageSpeed.Cache.VolumePath (default: /var/cache/pagespeed/volume.dat, 1 GB). For production:

  • Set an explicit PageSpeed__Cache__VolumePath (double-underscore for nesting) on a persistent volume so the cache survives container restarts and isn’t billed against ephemeral disk. The path is a single file, pre-sized to PageSpeed__Cache__VolumeSizeBytes.
  • Ensure the application user has read/write access to the file’s parent directory.
  • Leave CacheMode at Safe for the initial rollout. Safe mode adds must-revalidate to asset responses so a misconfigured option recovers in minutes rather than hours. Switch to Aggressive only after a stable baseline and with a CDN purge path available — see Choose a cache mode for the full trade-off.

Validate the deployment

After deploy, confirm the middleware is active:

curl -I https://your-app.example.com/
# X-PageSpeed: WeAmp.PageSpeed/2.1.0

curl -s https://your-app.example.com/healthz | jq .
# "status": "Healthy"
# entries, version

The /healthz endpoint reports Healthy, with the cache entry count and the middleware version, while the cache is operational, and Unhealthy when the cache cannot be opened — wire your monitoring to alert on Unhealthy.

The worker process exposes its own diagnostic console SPA out-of-process. The middleware starts the worker with --api-no-auth on a loopback-only management port (PageSpeed.Worker.ApiPort; an ephemeral port when left at 0), so the API answers anything on the host and is never reachable off-host — the worker refuses a non-loopback bind without a token. Reach it from the host or through an SSH tunnel rather than by publishing the port.

Scale across multiple instances

mod_pagespeed 2.1 is licensed under Apache-2.0 and free to run in development and in production, so scaling out adds no software cost. Size replica counts for your traffic and availability needs.

Each instance maintains its own on-disk cache. There is no shared cache backing across replicas; each replica builds its own warm cache, which isolates cache state across instances.

Zero-downtime restarts

The middleware honors ASP.NET Core’s standard graceful-shutdown semantics. On SIGTERM, in-flight requests complete against the existing cache before the worker shuts down; new requests route to a fresh instance. Configure your orchestrator’s terminationGracePeriodSeconds (Kubernetes) or equivalent to at least 30 seconds so any mid-flight HTML rewrites complete cleanly.

For container deployments, the Deploy to production guide covers the Docker / Helm shipping path; the systemd and Kubernetes patterns there apply equally to the NuGet middleware when wrapped in your own container image.

See also

Frequently asked questions

Does scaling the ASP.NET Core middleware across multiple instances add per-server cost?

No. mod_pagespeed 2.1 is licensed under Apache-2.0 and free to run in development and in production, so scaling out adds no software cost — size replica counts for traffic and availability.

What does the /healthz check report?

Healthy, with the cache entry count and the middleware version, while the cache is operational; Unhealthy when the cache cannot be opened — wire monitoring to alert on Unhealthy.