I'm trying to set some headers only for specific location
blocks in nginx.
The problem I have is that those location
blocks contain rewrite
statements, which apparently seem to drop the custom headers.
In this example, I have two rules I want:
- Files inside
/static
should haveexpires max;
(which sets the headersCache-Control: max-age=some huge value
andExpires: some future date really far off
) and have their names be rewritten to something that doesn't contain/static
- Files everywhere else should have
Cache-Control: public
(nomax-age
)
Here's the configuration I tried:
server {
listen [::]:80;
root /somepath;
location /static {
expires max;
rewrite /static(.*) /whatever$1;
}
add_header Cache-Control public;
}
And having the following directory structure:
/somepath
/somepath/f1.txt
/somepath/static/f2.txt
Then we get the following:
f1.txt
:Cache-Control: public
, noExpires
headerf2.txt
:Cache-Control: public
, noExpires
header
That's valid for f1.txt
but not f2.txt
. I want it to be like this:
f1.txt
:Cache-Control: public
, noExpires
headerf2.txt
:Cache-Control: max-age=some huge value
,Expires: some future date really far off
The problem, I think, stems from the rewrite /static(.*) /whatever$1;
line, which makes nginx cancel the headers it has added so far and then add them again (thus re-adding Cache-Control
). As such, a trivial workaround would be this:
server {
listen [::]:80;
root /somepath;
location /static {
rewrite /static(.*) /whatever$1;
}
location /whatever {
expires max;
}
add_header Cache-Control public;
}
The problem is that in my real config file, the rewrite
isn't as friendly-looking as that. The rewritten URL is not easily matchable in a way that wouldn't also match some files that shouldn't have expires max
, so I can't really use this workaround.
Is there a way to make those headers stick after a rewrite
?
EDIT: Here's what my real URLs look like:
location ~ /(?:posts-)?img/.*-res- {
access_log off;
expires max;
rewrite "/img/(.*)-res-.{8}(.*)" /img/$1$2;
rewrite "/posts-img/(.*)-res-.{8}(.*)" /posts/$1$2;
}
While I can add a location
block for /img
which would take care of files rewritten using the first rewrite
rule, I cannot add one for the second one (/posts
) because some files in /posts
are not cacheable resources and thus shouldn't have expires max
.
EDIT 2: Full config (or at least containing all the relevant parts):
server {
listen [::]:80;
root /somepath;
server_name domain.tld;
location ~ /(?:posts-)?img/.*-res- {
access_log off;
expires max;
rewrite "/img/(.*)-res-.{8}(.*)" /img/$1$2;
rewrite "/posts-img/(.*)-res-.{8}(.*)" /posts/$1$2;
}
add_header Cache-Control public;
}
Directory structure:
/somepath
/somepath/img/f1.png
/somepath/posts/post1.html
/somepath/posts/d1/f2.png
/somepath/posts/d2/f2.png
Expected behavior according to HTTP request:
GET /somepath
: Serves/somepath
withCache-Control: public
GET /somepath/img/f1.png
: Serves/somepath/img/f1.png
withCache-Control: public
GET /somepath/img/f1-res-whatever.png
: Serves/somepath/img/f1.png
with the headers sent byexpires max
GET /somepath/posts/post1.html
: Serves/somepath/posts/post1.html
withCache-Control: public
GET /somepath/posts/d1/f2.png
: Serves/somepath/posts/d1/f2.png
withCache-Control: public
GET /somepath/posts-img/d1/f2-res-whatever.png
: Serves/somepath/posts/d1/f2.png
with the headers sent byexpires max