Enable caching of css and js files in Apache - apache

Using Apache 2.4 on Debian 8.2, I am trying to enable caching of all css and js files. Caching of images works fine; that is, the browser receives a 304 status, so it doesn't download again. But I cannot get caching of other files working.
I use this inside a virtual host file:
<IfModule mod_expires.c>
<FilesMatch "\.(jpe?g|png|gif|js|css)$">
ExpiresActive On
ExpiresDefault "access plus 1 week"
</FilesMatch>
</IfModule>
The expires module is enabled. I did restart apache, cleaned browser cookies, etc. No success.
The response for a gif image, from browser developer tools:
Cache-Control:max-age=604800
Connection:Keep-Alive
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"4174a-4e69c97fbf080"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.10 (Debian)
The response for a css file:
Accept-Ranges:bytes
Cache-Control:max-age=604800
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:135
Content-Type:text/css
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"5116-525639d271c78-gzip"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=99
Last-Modified:Wed, 25 Nov 2015 20:50:52 GMT
Server:Apache/2.4.10 (Debian)
Vary:Accept-Encoding
It looks like the expires heading is set correctly, but the browser keeps requesting the file (200 OK).
I tried with Chrome and Firefox.
Summary:
1.) When I follow links inside the web site, the browser uses the cached files. But when I press F5, they re-download the css and js files, but they don't re-download images. Images give 304. That is fine.
2.) When I press Ctrl-F5, naturally enough, all files are re-downloaded. That's fine too.
3.) So the problem is how to enable caching (just like images) for other files. Why is apache discriminating between images and other files? I didn't put anything special to images in the config files.
Q: How to properly enable caching of css and js files?
Another Q: is there a special http header that says to the browser never to request the file. The reason is, sending even a request to check if the file is modified takes 100-200 ms, which is too much. I am sure the files will not be modified. And if they are modified, I can easily put a version string at the end of the css file, such as myFile.css?v=1.1 So I hope there should be a way to stop sending requests completely.
SOLVED
First, there is a bug in apache as mentioned in the answer below.
Second, there was a misunderstanding on my part. I guess this is how modern browsers work:
1.) Follow links inside a web site: No request is sent, even to check if the file has been modified.
2.) F5: Send a request. If file is not modified then the server responds 304.
3.) Ctrl+F5: Full download.
The behavior about F5 does not make sense to me. Anyway.
In case anybody needs it, here is a working solution that I put into virtual host file:
RequestHeader edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\""
Header edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""
LoadModule expires_module /usr/lib/apache2/modules/mod_expires.so
ExpiresActive On
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
ExpiresDefault "access plus 4 weeks"
</FilesMatch>

Turn off Etags, they don't play well in Apache when gzip is on for 304s.
See here: Apache is not sending 304 response (if mod_deflate and AddOutputFilterByType is enabled)
As images are already compressed they are typically not gzipped and hence why they work.
ETags are not that useful in my opinion in their current implementation (see my blog here for a more in depth discussion as to why) so, coupled with above bug, I turn them off.
For your second question just set a long expiry.
As discussed in the comments below there are three scenarios:
Normal browsing - in which caching should be used and 304s only used if cache is still valid after expiry (in which case it's set to valid again for same expiry).
F5 or Refresh button. This is an explicit action by the user to confirm the page and all its resources are still valid so they all will be double checked (even those still in cache and still valid according to expiries header) and 304s sent when they haven't changed. It does not mean "just redownload anything which has expired but leave cached items alone as they are still valid" as you think it should. Personally I think the current implementation the browsers use makes sense and your method would be confusing to end users. While some sites may version assets like images, css and JavaScript so rechecking is a waste of time, not all such sites do this.
Ctrl+F5. This is a force refresh. It means "Ignore cache and download everything". It's rarely needed except by developers who change files requested on development servers.
Hope that all makes sense.
Edit 12 May 2016: Looks like Firefox is bringing in the functionality you actually want: https://bitsup.blogspot.ie/2016/05/cache-control-immutable.html?m=1

If nothing else seems to work, don't forget to turn the disable cache from devtools in you browser!!!

Related

apache2 DirectoryIndex change does not bypass cached index

I am trying to make sure that visitors to my website see the latest version. To this end I have written a script to rename appropriate files and requests so that they append a fresh version number at build time. This includes the index file, let's call it index-v123.html.
I have uploaded this built source and pointed my apache2 server to the new index file by including
DirectoryIndex index-v123.html
in my apache2.conf. I have restarted it, and when viewing the website in chrome incognito mode or on hard refresh I can see that all the new files are loaded and the website works as expected.
My issue is that in my normal browser, when I visit the URL, I still load up a cached version of index.html. Clearly changing the DirectoryIndex didn't convince the client to go to the new index file like I'd hoped...
So can I do anything to make this happen?
(Also may be relevant: I am running a progressive web app using Polymer 2.0, with a service-worker.js that is built automatically by polymer build.)
This turned out to be a service worker issue: service-worker.js was being cached on the client side, and hence was providing outdated content as if the client was in offline mode. Could only be updated by deregistering the worker. The solution was to implement max-age=0 on the service worker at the apache2 server side:
<Files index.html|service-worker.js>
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>
Was surprised this wasn't better highlighted in the polymer build/production docs somewhere. For reference, in the google primer on service workers it says:
The caching headers on the service worker script are respected (up to
24 hours) when fetching updates. We're going to make this opt-in
behaviour, as it catches people out. You probably want a max-age of 0
on your service worker script.

Apache2 no cache specific file only

I'm running and Amazon EC2 with Ubuntu 14.4 and Apache2 with no PHP or other server-side script--just a static content site. I used this tutorial to get to the point I am at now with the apache file (see screenshot at link below):
https://www.digitalocean.com/community/tutorials/how-to-configure-apache-content-caching-on-ubuntu-14-04
I want to have a directive (if that is the nomenclature) that tells Apache to not cache a single, specific file only, but still handle everything else as it is already configured. I'm no computer whizz here--just learning. Is there a way to do this? Currently I have made a new directory inside my images folder called "no-cache" where the image I do not want cached lives.
I tried adding a second location tag below the first one with "CacheDisable on" inside it, however this is not supported. Also tried using a Directory tag, but this also does not work with the current configuration.
Thanks in advance!
/etc/apache2/sites-enabled/000.default.conf
The link you provided is a bit confusing since it mentions so many different types of caching.
When dealing with Webservers and caching, what you usually mean is sending cache messages (using http headers) to define how the browser should handle caching, to improve visitors performance. This is the last item discussed in that link of yours, despite being the most common. The first section talks about Apache caching files itself to improve its own performance and is much less common.
If client side caching using mod_expiries is what you mean, then you can control this with location headings:
#Allow long term assets to be cached for 6 months as they are versioned and should never change
<Location /assets/libraries/ >
ExpiresDefault A15724800
Header set Cache-Control "public"
</Location>
#Do not cache these files
<Location /login >
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
</Location>
I've a more detailed blog on this here: https://www.tunetheweb.com/performance/http-performance-headers/caching/.

The files served by my Apache Server are not being saved on browser cache

I have installed and configured an Apache server with a virtualhost which serves images.
When I load my page with images on the browser the second time (the images should be on cache after the first time the page is loaded), the browser doesnt get the images (or files) from cache, and think that it should.
What is wrong? I am using Google Chrome, and when I load some other web from other server the cache works, so I think that I have some problem with the Apache, but I am not sure.
Thank you very much.
The response is a video-segment which is played by Dash player.
Response headers:
accept-ranges:bytes
content-length:194431
date:Wed, 09 Mar 2016 07:42:07 GMT
etag:"2f77f-52acd33f8b167"
last-modified:Tue, 02 Feb 2016 17:55:12 GMT
server:Apache/2.4.18 (Unix) OpenSSL/1.0.2e PHP/7.0.2
status:200
After doing that:
ExpiresActive On
# Set up caching on media files for 1 year (forever?)
<FilesMatch "\.(mp4|m4s)$">
ExpiresDefault "access plus 3600 seconds"
Header set Cache-Control "public"
Header set Content-Type "video/mp4"
Header set Vary "Host"
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
The headers are:
accept-ranges:bytes
access-control-allow-origin:*
cache-control:public
content-length:194431
content-type:video/mp4
But it doesnt save on the cache, I mean, when I reload the web or the video, it does not get it from the cache as it should.
You are not including any cache-control headers telling the browser to cache the resources. The spec is unclear how to handle this but most browsers choose not to cache unless explicitly told to.
You need to include Apache config like this (assuming you are already including the mod_expiries module):
ExpiresActive On
# Set up caching on media files for 1 week
<filesMatch ".([iI][cC][oO]|[gG][iI][fF]|[jJ][pP][gG]|[jJ][pP][eE][gG]|[pP][nN][gG]|[fF][lL][vV]|[pP][dD][fF]|[sS][wW][fF]|[mM][oO][vV]|[mM][pP]3|[wW][mM][vV]|[pP][pP][tT])$">
ExpiresDefault A604800
Header append Cache-Control "public"
</filesMatch>
# Set up caching on font files for 6 months
<filesMatch ".([eE][oO][tT]|[tT][tT][fF]|[sS][vV][gG]|[Ww][Oo][Ff][Ff]|[Ww][Oo][Ff][Ff]2)$">
ExpiresDefault 15552000
Header append Cache-Control "public"
</filesMatch>
Which will then produce a header like this:
cache-control:max-age=10800, public
I've written a blog post on this if you want more details: https://www.tunetheweb.com/performance/http-performance-headers/caching/
OK, I have solved the problem.
I was using an https connection and the certificate I was using didnt have the correct parameters (common name must be the name of the url programmed on the server) and the certificate of the server must be authenticate by some CA, so I have made CA certificates to authenticate the server certificates. This means that if you have an unsecure https connection, Chrome does not save files on cache.
After having all the certificates corrected, I have upload to google chrome the certificates to trust my web (configuration of google Chrome, advanced options, Manage https/ssl certificates). After that, I can save files on cache because of the certificates which makes the https connection secure (green lock on the chrome url bar).
That was my problem and this is how I solved it.
Thanks for your answers and your time!! ;)

How can I stop Joomla (Apache) from caching the admin backend?

I've a big cache issue with my Joomla 1.5.26 (Apache/2.2.14 Ubuntu) administrator panel.
Everything is cached for about 15 minutes, and by everything I mean everything.
If I go to global configuration and change any value there, for example the Site Name from "MyTestSite" to "MyTestSite2", or the Feed length from 15 to 30 and save it a message is displayed that everything was saved and the cache was cleaned. If I go immediately to the global config again, I see that the old values (MyTestSite and 15) are still there. If I look into configuration.php I see that the file was correctly changed. Also, if I wait 15 minutes I can see the correct value. This is not related only to configuration, but even to article editing!
It's the same on 2 computers, and with Firefox, Chrome, and IE.
I've tried to fix it by placing a .htaccess in /admistrator/ to disable any caching, but to no avail.
I've tried this:
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
or this:
ExpiresActive On
ExpiresDefault "access plus 1 minute"
What is going on here? (it was working fine for 2 years). How can I stop Joomla from caching the admin backend?

How to get mod_python site to allow clients to cache selected image content?

I have a small dynamic site implemented in mod_python. I inherited this, and while I have successfully made relatively minor changes to its content and logic, with HTTP caching I'm out of my depth. The site works fine already, so this isn't "the usual question" about how to disable caching for a dynamic site.
My problem is there is one large banner image on each page (the same image from same URL on each page) which accounts for ~90% of site bandwidth but which so far as I can tell isn't being cached; as I browse the site every time I click to a new page (or back to a previously visited one) there it is downloading it yet again.
If I wget the banner's image URL (to see the headers) I see:
$ wget -S http://example.com/site/gif?name=banner.gif
--2012-04-04 23:02:38-- http://example.com/site/gif?name=banner.gif
Resolving example.com... 127.0.0.1
Connecting to example.com|127.0.0.1|:80... connected.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Date: Wed, 04 Apr 2012 22:02:38 GMT
Server: Apache/2.2.14 (Ubuntu)
Content-Location: gif.py
Vary: negotiate
TCN: choice
Set-Cookie: <blah blah blah>
Connection: close
Content-Type: image/gif
Length: unspecified [image/gif]
Saving to: `gif?name=banner.gif'
and the code which is serving it up isn't much more than
req.content_type = 'image/gif'
req.sendfile(fullname)
where fullname is a file-path munged from the request's name parameter.
My question is: is there some quick fix along the lines of setting an Expires: or Vary: field in the image's request response which will result in clients being less keen to repeatedly download it ?
The site is hosted on Ubuntu 10.04 and doesn't have any non-default apache mods enabled other than rewrite.
I note that most (not all) of the site pages' headers themselves do contain
Pragma: no-cache
Cache-Control: no-cache
Expires: -1
Vary: Accept-Encoding
(and the original site author has clearly thought about this as no-cache is applied selectively to non-static content pages). I don't know enough about caching to know whether this somehow poisons the included .gif IMG into being reloaded every time too though.
I don't know if my answer can help you or not, but I post it anyway.
Instead of serving image files from within python application, you can create another virtualhost within apache (on same server) just to serve static and image file. In your python application, you can embed image likes this
<img src="http://img.yoursite.com/banner.gif" alt="banner" />
With separate virtualhost, you can add various header to various content type using mode header, or add another caching layer for your static file.
Hope this help.