GetPageSpeed/ngx_immutable
NGINX module for setting immutable caching on static assets
ngx_immutable
This tiny NGINX module can help improve caching of your public static assets, by setting far future expiration with immutable attribute.
Intended audience
Websites and frameworks which rely on the cache-busting pattern:
- static resources include version/hashes in their URLs, while never modifying the resources
- when necessary, updating the resources with newer versions that have new version-numbers/hashes,
so that their URLs are different
Popular frameworks which use cache-busting:
- Magento 2
- Include your own here!
Synopsis
http {
server {
location /static/ {
immutable on;
}
}
}will yield the following HTTP headers:
...
Cache-Control: public,max-age=31536000,stale-while-revalidate=31536000,stale-if-error=31536000,immutable
Expires: Thu, 31 Dec 2037 23:55:55 GMT
...
How it's different to expires max;:
- Sets
immutableattribute, e.g.Cache-Control: public,max-age=31536000,immutablefor improved caching.
That is 1 year and not 10 years, see why below. - Sends
Expiresonly when it's really necessary, e.g. when a client is requesting resources overHTTP/1.0 - Sets
publicattribute to ensure the assets can be cached by public caches, which is typically a desired thing.
Due to the lacking support of immutable in Chromium-based browsers,
we also add stale-while-revalidate=31536000,stale-if-error=31536000 which helps to improve cache hit-ratio in edge cases.
Use of these directives allows serving cached responses beyond their cache lifetime, which is forever in case of immutable resources.
Thus, in most cases, immutable on; can be used as a better alternative to expires max; to implement the cache-busting pattern.
Directives
immutable
Syntax: immutable on | off;
Default: immutable off;
Context: http, server, location
Enables or disables immutable caching headers for the location.
immutable_cache_status
Syntax: immutable_cache_status on | off;
Default: immutable_cache_status off;
Context: http, server, location
Enables the RFC 9211 Cache-Status header for debugging and observability. When enabled, responses include:
Cache-Status: "nginx/immutable"; hit; ttl=31536000
This header helps debug caching behavior across multi-layer caching architectures (NGINX -> CDN -> Browser). Each cache layer can append its own status, creating a chain like:
Cache-Status: "nginx/immutable"; hit; ttl=31536000, "cloudflare"; fwd=uri-miss; stored
Example configuration:
location /static/ {
immutable on;
immutable_cache_status on;
}immutable_types
Syntax: immutable_types mime-type ...;
Default: (none - applies to all types when not specified)
Context: http, server, location
Restricts the immutable caching headers to responses with the specified MIME types. When not specified, immutable headers apply to all responses. This is similar to how gzip_types works for the gzip module.
Example configuration:
location /static/ {
immutable on;
# Only apply immutable headers to JavaScript and CSS files
immutable_types application/javascript text/css;
}Why 31536000 seconds (1 year?)
The RFC defines to use one year to make a response as "never expires":
To mark a response as “never expires,” an origin server sends an
Expires date approximately one year from the time the response is
sent. HTTP/1.1 servers SHOULD NOT send Expires dates more than one
year in the future.
More details in the article.
Ubuntu and Debian packages
It's easy to install the module package for these operating systems.
ngx_immutable is part of the APT NGINX Extras collection, so you can install
it alongside any modules,
including Brotli.
First, set up the repository, then:
sudo apt-get update
sudo apt-get install nginx-module-immutableInstallation for RPM-based systems
GetPageSpeed provides packaging of the nginx-module-immutable in its repositories, as part of its NGINX Extras package collection.
The following operating systems are supported:
- Red Hat Enterprise Linux 6, 7, 8, 9
- CentOS 6, 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2
- Fedora Linux, the 2 most recent releases
The installation requires a subscription for all the operating systems listed, except Fedora Linux, for which it is free.
How to install
For any OS listed above, installation steps are the same:
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-immutableFollow the installation prompt to import GPG public key that is used for verifying packages.
Then add the following at the top of your /etc/nginx/nginx.conf:
load_module modules/ngx_http_immutable_module.so;Example: Magento 2 production configuration
Provided that your store runs in production mode, you have already compiled all the assets.
This sample config can be optimized to:
location /static/ {
immutable on;
# Remove signature of the static files that is used to overcome the browser cache
location ~ ^/static/version {
rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
}
location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2|json)$ {
add_header X-Frame-Options "SAMEORIGIN";
}
location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
add_header Cache-Control "no-store";
add_header X-Frame-Options "SAMEORIGIN";
immutable off;
}
add_header X-Frame-Options "SAMEORIGIN";
}When used together with ngx_security_headers, it can be simplified further:
security_headers on;
location /static/ {
immutable on;
location ~ ^/static/version {
rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
}
location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
add_header Cache-Control "no-store";
immutable off;
}
}