Expires header based on dynamic Content-Type in nginx
I have a PHP site where some content is user generated. For example, users can upload photos that are resizable and can be requested. I would like to specify a header Expires
(for caching) based on the MIME type ( Content-Type
response header) in my nginx config.
This is my current config (my host automatically adds http{}
and server{}
):
charset utf-8;
types {
text/css css;
text/javascript js;
}
gzip on;
gzip_types text/html text/css text/javascript application/json image/svg+xml;
location / {
if (!-e $request_filename) {
rewrite . /index.php last;
break;
}
set $expire 0;
if ($upstream_http_content_type = image/jpeg) { set $expire 1; }
if ($upstream_http_content_type = image/png) { set $expire 1; }
if ($upstream_http_content_type = image/gif) { set $expire 1; }
if ($upstream_http_content_type = image/svg+xml) { set $expire 1; }
if ($upstream_http_content_type = text/css) { set $expire 1; }
if ($upstream_http_content_type = text/javascript) { set $expire 1; }
if ($expire = 1) {
expires max;
}
}
This works for static files (like files .png
- they get the correct header Expires
), but it doesn't affect the dynamically generated content from the index.php
(no Expires
) header in any way . Does anyone know what I am doing wrong?
source to share
There is location
no room in your block when you pass a request to a php web app, so I can assume that you are doing it elsewhere, for example in a block location
like this:
location /index.php {
# your code
}
With your config, when a user asks for a static file that exists, the first directive is if
not evaluated and everything goes well. Problems start when the user requests dynamic files and then nginx enters your first block if
:
if (!-e $request_filename) {
rewrite . /index.php last;
break;
}
So what happened? Are you using a last
directive flag rewrite
and what does the nginx doc say about it?
last - ends processing of the current rewrite directives and restarts the process (including rewriting) looking for a match in the URI from all available places.
According to this specification, when the file is dynamic, you have done a correspondence index.php
, and execution leaves a block if
and even a whole block location
, and the next block if
to check content-type
is not even checked. I suppose it will find location
for url /index.php
and there you won't install expires max
.
Do you understand this expansion of your problem?
The resolution to this too will move / copy your serial block if
to check content-type
that place where your configuration passes performance in php (index.php) web application ... or remove the flag last
from rewrite
, if it does not cause any other problems.
Okey, since I promised a little fix for your conf file: change the block location
to two:
location /index.php {
if ($upstream_http_content_type ~ "(image/jpeg)|(image/png)|(image/gif)|(image/svg+xml)|(text/css)|(text/javascript)") {
expires max;
}
if ($sent_http_content_type ~ "(image/jpeg)|(image/png)|(image/gif)|(image/svg+xml)|(text/css)|(text/javascript)") {
expires max;
}
}
location / {
if ($upstream_http_content_type ~ "(image/jpeg)|(image/png)|(image/gif)|(image/svg+xml)|(text/css)|(text/javascript)") {
expires max;
}
if ($sent_http_content_type ~ "(image/jpeg)|(image/png)|(image/gif)|(image/svg+xml)|(text/css)|(text/javascript)") {
expires max;
}
try_files $uri /index.php =404;
}
The first block location
is for your index.php
and dynamic response, and the second is for static files. In the second, we add the header expires max
as the upstream header and as the standard header (just to be sure). I am using one block here if
for all the types that you define in your configuration, matching the regex pattern. At the end we use a directive try_files
which means that if a url based static file can be retrieved, it will be fetched and otherwise try url / index.php or just return with http 404. The first location block is for the url only /index.php
. I didn't find anywhere in your config directiveroot
which should point to the root folder of your application. Try adding this as well ( root doc ).
Hope this solves your problems.
source to share