How to Set Varnish Cache-Control Headers - http-headers

I am hoping someone can advise on the proper method for getting Varnish to send cache-control headers. Currently, my configuration is sending "Cache-Control: no-cache" to clients.
Thanks in advance to anyone who might be able to help...

Your back-end is sending "Cache-Control: no-cache" to Varnish which implies two things:
Varnish will not store the response in the cache (so a next lookup will fail)
Your clients (browsers and intermediate proxies) will not cache responses (and request them over and over).
The solution is simple: remove the cache-control headers after fetching the response from the back-end (and before storing them in the cache).
In your vcl file do:
sub vcl_fetch {
remove beresp.http.Cache-Control;
set beresp.http.Cache-Control = "public";
}
You can choose to only do this for certain urls (wrap it in ( if req.url ~ "" ) logic) and do way more advanced stuff.

Varnish ignores Cache-Control: nocache as per the documentation. Here is evidence confirming that:
http://drupal.org/node/1418908
To get that result, you should detect the header Cache-Control .nocache. from your backend, and then invalidate the cache, set the backend response to not cacheable, or issue max-age: 0 in the other header (I forget the name right now).

[ivy] has good advice, and/but it gets a little complicated when you try to obey a servers intent for end user (browser) caching. I found this resource to be helpful in understanding a way to configure Varnish to hold onto a cache longer than a browser is instructed to...
https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching

Related

Cloudflare doesn't respect my origin cache control header

My nginx server return
cache-control: public, max-age=14400, s-maxage=2592000
for every request.
But for html files, it still returns
cf-cache-status: DYNAMIC
for other cachable file extensions, it returns:
cf-cache-status: EXPIRED
I've already purge all cache and refresh my browser for several times.
Something wrong with my settings?
Check cloudfalre cache level settings.

Remove a header based on query param with varnish

I want to remove a cache-control header from URL's with a specific query params. e.g. when the query paramater ajax=1 is present.
e.g
www.domain.com?p=3&scroll=1&ajax=1&scroll=1
These are getting cached by chrome browsers for longer than I would like and I would like to stop that in this specific case. I have tried with .htaccess which works for static files however not in action on the URL's mentioned above.
RewriteEngine on
RewriteCond %{QUERY_STRING} (^|&)ajax=1(&|$)
Header unset "Cache-Control"
I could use a cache buster in the next website release but difficult in production and worried it would unnecessarily cache lots of files in user browsers so would rather achieve server side.
My server has Cloudflare then NGINX terminating SSL to Varnish then Apache with a Magento 2 instance running on there. So thinking i could possibly achieve this with NGINX or Varnish configs, or even Cloudflare. I however couldn't seem to find a way to achieve this with page rules in Cloudflare, or could not find examples for Varnish or Nginx.
I'm assuming you don't want to cache when ajax=1 is part of your URL params?
You can do this in Varnish using the following VCL snippet:
sub vcl_backend_response {
if(bereq.url ~ "\?([^&]*&)*ajax=1(&[^&]*)*$") {
set beresp.http.cache-control = "private, no-cache, no-store";
set beresp.uncacheable = true;
}
}
This snippet will make sure Varnish doesn't cache responses where the URL contains an ajax=1 URL parameter. It will also make sure any caching proxy that sits in front will not cache, because of the Cache-Control: private, no-cache, no-store.
Is this what you're looking for?

Why does http.sys (before IIS) return badrequest when requests have certain acceptable accept-encoding header values?

Given a web app (netcoreapp3.0 hosted in IIS) -- any requests with certain values for Accept-Encoding header never gets to the application. http.sys parses and spits out a 400 - BadRequest.
i.e., Accept-Encoding: application/gzip,gzip
The issue seems to be the '/' character.
We are not in control of the client(s) and would like to not ask to have them conform/change their client's requests. Their requests work with other (non IIS) servers.
Unless I'm reading the spec incorrectly -- I believe the above value is valid for the header.
Thought about asking or reporting a bug in github - dotnet/aspnetcore - but not sure if it's a bug.
Thanks for any advice.
Would like to avoid a Kestrel w/ apache | nginx reverse proxy.
As far as I know, the accept and accept-Encoding is not the same header. So you read the wrong article.
The right RFC article is :https://www.rfc-editor.org/rfc/rfc7231#section-5.3.4
The "Accept-Encoding" header field can be used by user agents to
indicate what response content-codings (Section 3.1.2.1) are
acceptable in the response. An "identity" token is used as a synonym
for "no encoding" in order to communicate when no encoding is
preferred.
Accept-Encoding = #( codings [ weight ] )
codings = content-coding / "identity" / "*"
So it doesn't support the "/". There is no way to modify the setting to allow IIS access the wrong header.

Apache: Disable Cache-Control: max-age?

A book about performance reads that you should use Expires or Cache-Control: max-age but not both .
Expires was easy to configure on my Apache.
Now I would like to disable the unneeded Cache-Control: max-age but I don't how to.
Your mention of both headers suggests that you're using mod_expires.
You cannot select only one header using mod_expires. The code that sets the headers in mod_expires.c unconditionally sets both headers to equivalent values:
apr_table_mergen(t, "Cache-Control",
apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT,
apr_time_sec(expires - r->request_time)));
timestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
apr_rfc822_date(timestr, expires);
apr_table_setn(t, "Expires", timestr);
However, using mod_header may allow you to set what you want, using something like:
Header unset Cache-Control
There is a case for using both: Cache-Control allows much finer control than Expires, while Expires may help much older clients.

Prevent Apache from chunking gzipped content

When using mod_deflate in Apache2, Apache will chunk gzipped content, setting the Transfer-encoding: chunked header. While this results in a faster download time, I cannot display a progress bar.
If I handle the compression myself in PHP, I can gzip it completely first and set the Content-length header, so that I can display a progress bar to the user.
Is there any setting that would change Apache's default behavior, and have Apache set a Content-length header instead of chunking the response, so that I don't have to handle the compression myself?
You could maybe play with the sendBufferSize to get a value big enough to contain your response in one chunk.
Then chunked content is part of the HTTP/1.1 protocol, you could force an HTTP/1.0 response (so not chunked: “A server MUST NOT send transfer-codings to an HTTP/1.0 client.”) by setting the force-response-1.0 in your apache configuration. But PHP breaks this settings, it's a long-known-bug of PHP, there's a workaround.
We could try to modify the request on the client side with an header preventing the chunked content, but w3c says: "All HTTP/1.1 applications MUST be able to receive and decode the "chunked" transfer-coding", so I don't think there's any header like 'Accept' and such which can prevent the server from chunking content. You could however try to set your request in HTTP/1.0, it's not really an header of the request, it's the first line, should be possible with jQuery, certainly.
Last thing, HTTP/1.0 lacks one big thing, the 'host' headers is not mandatory, verify your requests in HTTP/1.0 are still using the 'host' header if you work with name based virtualhosts.
edit: by using the technique cited in the workaround you can see that you could tweak Apache env in the PHP code. This can be used to force the 1.0 mode only for your special gzipped content, and you should use it to prevent having you complete application in HTTP/1.0 (or use the request mode to set the HTTP/1.0 for you gzip requests).