Reconsidering Nginx Cache Generation with the map Directive
Hello, this is Munou.
When blog posts are updated frequently, I don't want old caches to be loaded along with the article updates.
However, I want to deliver from cache as much as possible, so I'll think about it.
Discontinue cache determination using if
It seems that the approach of setting a flag with $do_not_cache as introduced in articles like this, and then using an if statement to change cached content, is now deprecated.
Introduction to an architecture (OpenResty+Redis) that allows common use of Nginx proxy cache even when redundant, to make WordPress blazing fast
That said, where should cache determination be done?
The map directive evaluates the content of an Nginx variable and assigns the result as a value to another variable.
2022-03-01 Trying to filter Nginx logs
While researching, I found a very simple syntax posted.
Adding location-block to cache files makes those files return 404
map $uri $expire {
~\.(?:j|cs)s$ 180d;
~\.(?:jpe?g|png|webp|woff2?|ttf)$ 365d;
default off;
}
map $uri $cache_control {
~\.(?:js|css|jpe?g|png|webp|woff2?|ttf)$ public;
}
server {
...
expires $expire;
add_header Pragma $cache_control;
add_header Cache-Control $cache_control;
...
}
I see, that's clear.
Desired Cache
Basically, I want to keep a long cache for files other than html files, and only cache html files for a short period.
The reason is that in case of DOS or flood attacks, I want the Nginx server to respond as much as possible.
For now, I'll try setting it up as follows.
map $uri $expire {
~\.(jpg|jpeg|png|webp|gif|mp4|css|js|ico|woff2)(\?.*)?$ 365d;
~\.html$ 5m;
}
map $uri $cache_control {
~\.(jpg|jpeg|png|webp|gif|mp4|css|js|ico|woff2)(\?.*)?$ public;
~\.html$ public;
}
With this, I'll run nginx -t, service nginx restart, and test with curl.
If html is not present in the request URI, it won't cache...
It seems that since I'm caching with html files as the key, it won't try to cache on a domain basis.
alleycat:[haturatu]:~/git$ curl -I https://soulminingrig.com
HTTP/2 200
server: nginx/1.27.0
date: Sat, 23 Nov 2024 12:20:55 GMT
content-type: text/html
content-length: 15699
vary: Accept-Encoding
last-modified: Sat, 23 Nov 2024 12:08:31 GMT
etag: "3d53-627935ba8f789"
accept-ranges: bytes
vary: Accept-Encoding
content-security-policy: upgrade-insecure-requests
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
alleycat:[haturatu]:~/git$ curl -I https://soulminingrig.com/index.html
HTTP/2 200
server: nginx/1.27.0
date: Sat, 23 Nov 2024 12:21:00 GMT
content-type: text/html
content-length: 15699
vary: Accept-Encoding
last-modified: Sat, 23 Nov 2024 12:08:31 GMT
etag: "3d53-627935ba8f789"
accept-ranges: bytes
vary: Accept-Encoding
expires: Sat, 23 Nov 2024 12:26:00 GMT
cache-control: max-age=300
content-security-policy: upgrade-insecure-requests
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
pragma: public
cache-control: public
The fact that cache-control information is missing when I ran curl -I https://soulminingrig.com means it's not included in this cache determination.
Although index.html is actually being displayed, Nginx doesn't understand it as a determination, so this time I'll try this.
map $uri $expire {
~\.(jpg|jpeg|png|webp|gif|mp4|css|js|ico|woff2)(\?.*)?$ 365d;
~\.html$ 5m;
~\.*$ 5m;
}
map $uri $cache_control {
~\.(jpg|jpeg|png|webp|gif|mp4|css|js|ico|woff2)(\?.*)?$ public;
~\.html$ public;
~\.*$ public;
}
This way, it will unconditionally hold the cache for 5 minutes for anything matching the regular expression.
Let's try curl -I again.
alleycat:[haturatu]:~/git$ curl -I https://soulminingrig.com
HTTP/2 200
server: nginx/1.27.0
date: Sat, 23 Nov 2024 12:44:43 GMT
content-type: text/html
content-length: 15699
vary: Accept-Encoding
last-modified: Sat, 23 Nov 2024 12:08:31 GMT
etag: "3d53-627935ba8f789"
accept-ranges: bytes
vary: Accept-Encoding
expires: Sat, 23 Nov 2024 12:49:43 GMT
cache-control: max-age=300
content-security-policy: upgrade-insecure-requests
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
pragma: public
cache-control: public
alleycat:[haturatu]:~/git$ curl -I https://soulminingrig.com/top.png
HTTP/2 200
server: nginx/1.27.0
date: Sat, 23 Nov 2024 12:44:47 GMT
content-type: image/png
content-length: 46584
vary: Accept-Encoding
last-modified: Sat, 23 Nov 2024 12:08:31 GMT
etag: "b5f8-627935ba12787"
accept-ranges: bytes
expires: Sun, 23 Nov 2025 12:44:47 GMT
cache-control: max-age=31536000
content-security-policy: upgrade-insecure-requests
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
pragma: public
cache-control: public
alleycat:[haturatu]:~/git$ curl -I https://soulminingrig.com/index.html
HTTP/2 200
server: nginx/1.27.0
date: Sat, 23 Nov 2024 12:44:51 GMT
content-type: text/html
content-length: 15699
vary: Accept-Encoding
last-modified: Sat, 23 Nov 2024 12:08:31 GMT
etag: "3d53-627935ba8f789"
accept-ranges: bytes
vary: Accept-Encoding
expires: Sat, 23 Nov 2024 12:49:51 GMT
cache-control: max-age=300
content-security-policy: upgrade-insecure-requests
alt-svc: h3=":443"; ma=86400
x-content-type-options: nosniff
pragma: public
cache-control: public
Successfully, everything is now cached.
By doing this caching, the configuration file syntax has become considerably shorter, and changing cache settings now only requires modifying the map directive, which has made it much more comfortable.
That's all for now. See you again.