Indefinitely caching a HTTP response via Nginx fails - http

I'm trying to tell nginx to cache some of my assets (js, css) forever, or at least for a very long time.
The idea is that once an asset bundle is compiled and published with an /assets/ URI prefix (e.g. /assets/foo-{fingerprint}.js) it stays there and doesn't ever need to change.
The internets told me I should write the following rule:
location ~ ^/assets/.*-([^.]+)\.(js|css)$ {
gzip_static on; # there's also a .gz of the asset
expires max;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
break;
}
I would expect this would result in responses with HTTP code 304 "Not Modified", but what I get is a consistent HTTP 200 (OK) every time.
I have tried some other approaches, for instance:
a) explicitly setting modification time to a constant point in time in the past;
add_header Last-Modified "Thu, 01 Jan 1970 00:00:00 GMT";
b) switching to If-None-Match checks;
add_header ETag $1;
if_modified_since off;
However, the only thing that really worked as needed was this:
add_header Last-Modified "Thu, 01 Jan 2030 00:00:00 GMT";
if_modified_since before;
I'm lost. This is contrary to everything I thought was right. Please help.

You should change your internets, since they give you wrong advices.
Just remove all add_header lines from your location (as well as surplus brake):
location ~ ^/assets/.*-([^.]+)\.(js|css)$ {
gzip_static on; # there's also a .gz of the asset
expires max;
}
and read the docs from the true Internet: http://nginx.org/r/expires and https://www.rfc-editor.org/rfc/rfc2616

It seems part of my configuration. During my researching I realized that browser uses heuristic analysis to validate requests with ConditionalGet headers (E-Tag, Last-Modified). It makes a lot of sense for back-end responses, so you can handle that to save server resources.
But in terms of static files (js, css, images), you can tell browser to serve them straight away without any Conditional Get validation. It is helpful if you update file name if any change takes place.
This part of configuration makes it happen:
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";

Related

Lighthouse complains about gzip files

we are optimizing our new website and there is one problem we cant get rid of. We have an optimized caching policy that works well. Problem: Lighthouse complains about ttl times for gzips. If I add gzip or gz to the line defining the cache our site looks strange and is only partially loaded.
This is our caching.conf:
location ~* ^.+\.(ico|css|js|gif|jpe?g|png|woff|woff2|eot|svg|ttf|webp|og |mp4|mov|mp3|wmv|webm)$ {
expires 180d;
add_header Pragmapublic;
add_header Cache-Control "public, must-validate";
}
Output from Lighthouse:
Serve static assets with an efficient cache policy 5 resources found
URL Cache TTL Transfer Size
…compressed/merged-e98e980…-482487f….js.165….gzip(xxx.yyyyy.info) None 54 KiB
So, how can I set the TTL for gzip or gz?
Yours
Stefan

nginx cache not working for CSS and JS scripts when checking using curl command

I'm trying to follow this guide: https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04
but every time I execute curl -I http://myjsfile.com/thejsfile.js it doesn't return the cache property
i.e this one:
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
this is what I have in my sites-available file. though there are 2 in there the default and our custom one for Certbot SSL certs. I did apply this to those 2 files.
# Expires map
map $sent_http_content_type $expires {
default off;
text/html epoch;
text/css max;
application/javascript max;
~image/ epoch;
}
So I'm not sure it's caching it and when I checked it using gtmetrix it still gets an F for browser caching.
I also tried this one: NGINX cache static files
and I have this in my nginx.conf inside http
server {
location ~* \.(?:ico|css|js)$ {
expires 30d;
add_header Vary Accept-Encoding;
access_log off;
}
}
but it still didn't work when I checked using the curl command.
so can someone enlighten me on what I'm doing wrong here or is this not the best approach to cache JS and CSS files?

Updating a website served with a large max-age

I have a SPA website (VueJS) that I've begun updating on a daily basis. When I was new to the entire process, I borrowed bits and pieces of my nginx configuration from multiple sources and ended up serving all the files in my website with Cache-Control: max-age=31536000.
After having users complain that they're unable to find my recent changes, I've inclined to think that it may be due to the browser caching everything till 2037 :(. This hypothesis is supported by the fact that following my advice of CTRL+F5 fixed their issue.
I have since updated the website different cache rules, but the browser doesn't seem to be hitting my server to fetch these newer rules.
map $sent_http_content_type $expires {
default off;
text/html off;
text/css off;
application/javascript off;
application/x-javascript off;
}
...
server {
...
location / {
add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';
...
}
}
Is there any way to undo this? Do I have to pack up and move to another domain?
If you have had far future Cache-Control lifetime set for all pages, and have a solid user base who were visiting your site when it was effective... then the short answer is: YES.
There is no way to undo use of browser cache as it will not check for new cache policy before currenly cached assets (your pages also, in this case) will not expire..
But you can just account for the fact that people tend to change browsers, run OS optimizer (which clear caches), or have an email campaign for users you know to instruct them to clear browser caches.
Not a good situation any way you look at it.
The setting that seem to work for me is the following using map is the following and I don't need to setup no-cache header any where else.
server {
add_header X-Frame-Options SAMEORIGIN always;
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
expires $expires;
...
}
map $sent_http_content_type $expires {
default off;
"text/html" epoch;
"text/html; charset=utf-8" epoch;
"text/css" epoch;
"application/javascript" epoch;
"~image/" max;
}
This guide has help understand.
https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04

How to add a response header on nginx when using proxy_pass?

I want to add a custom header for the response received from the server behind nginx.
While add_header works for nginx-processed responses, it does nothing when the proxy_pass is used.
add_header works as well with proxy_pass as without. I just today set up a configuration where I've used exactly that directive. I have to admit though that I've struggled as well setting this up without exactly recalling the reason, though.
Right now I have a working configuration and it contains the following (among others):
server {
server_name .myserver.com
location / {
proxy_pass http://mybackend;
add_header X-Upstream $upstream_addr;
}
}
Before nginx 1.7.5 add_header worked only on successful responses, in contrast to the HttpHeadersMoreModule mentioned by Sebastian Goodman in his answer.
Since nginx 1.7.5 you can use the keyword always to include custom headers even in error responses. For example:
add_header X-Upstream $upstream_addr always;
Limitation: You cannot override the server header value using add_header.
Hide response header and then add a new custom header value
Adding a header with add_header works fine with proxy pass, but if there is an existing header value in the response it will stack the values.
If you want to set or replace a header value (for example replace the Access-Control-Allow-Origin header to match your client for allowing cross origin resource sharing) then you can do as follows:
# 1. hide the Access-Control-Allow-Origin from the server response
proxy_hide_header Access-Control-Allow-Origin;
# 2. add a new custom header that allows all * origins instead
add_header Access-Control-Allow-Origin *;
So proxy_hide_header combined with add_header gives you the power to set/replace response header values.
Similar answer can be found here on ServerFault
UPDATE:
Note: proxy_set_header is for setting request headers before the request is sent further, not for setting response headers (these configuration attributes for headers can be a bit confusing).
As oliver writes:
add_header works as well with proxy_pass as without.
However, as Shane writes, as of Nginx 1.7.5, you must pass always in order to get add_header to work for error responses, like so:
add_header X-Upstream $upstream_addr always;
There is a module called HttpHeadersMoreModule that gives you more control over headers. It does not come with Nginx and requires additional installation. With it, you can do something like this:
location ... {
more_set_headers "Server: my_server";
}
That will "set the Server output header to the custom value for any status code and any content type". It will replace headers that are already set or add them if unset.
You could try this solution :
In your location block when you use proxy_pass do something like this:
location ... {
add_header yourHeaderName yourValue;
proxy_pass xxxx://xxx_my_proxy_addr_xxx;
# Now use this solution:
proxy_ignore_headers yourHeaderName // but set by proxy
# Or if above didn't work maybe this:
proxy_hide_header yourHeaderName // but set by proxy
}
I'm not sure would it be exactly what you need but try some manipulation of this method and maybe result will fit your problem.
Also you can use this combination:
proxy_hide_header headerSetByProxy;
set $sent_http_header_set_by_proxy yourValue;

nginx status code 200 and 304

I'm using nginx + passenger. I'm trying to understand the nginx response 200 and 304. What does this both means? Sometimes, it responses back in 304 and others only 200. Reading the YUI blog, it seems browser needs the header "Last-Modified" to verify with the server. I'm wondering why the browser need to verify the last modified date. Here is my nginx configuration:
location / {
root /var/www/placexpert/public; # <--- be sure to point to 'public'!
passenger_enabled on;
rack_env development;
passenger_use_global_queue on;
if ($request_filename ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|swf)$) {
expires max;
break;
}
}
How would I add the header "Last-Modified" to the static files? Which value should I set?
Try this.
if (...){
expires max;
add_header Last-Modified $sent_http_Expires;
break;
}

Resources