Setting cache-control max-age using Apache not working - apache

I'm trying to setup HTTP Caching for my website. Following is my configuration settings
# 1 YEAR
<FilesMatch "\.(ico|svg|woff|eot|ttf)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
# 1 WEEK
<FilesMatch "\.(jpg|png|gif|css|js)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
Does it make a difference if I place this in my <VirtualHost> settings or outside it? I've placed it inside the <VirtualHost>.
I tried checking the HTTP response for one of the png image using redbot.org and this is what it returned.
HTTP/1.1 200 OK
Date: Fri, 12 Sep 2014 09:28:33 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Tue, 26 Aug 2014 05:43:32 GMT
ETag: 1409031812.69
Content-Length: 23907
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: image/png
Why is there no Cache-Control max-age header tag?
I also checked using the Google PageSpeed Insights and it still says expiration not specified for all the files.
Did I miss something?

The .htaccess file was not being taken into account due to some missing configuration settings in my apache2.conf file. Making the required changes in the conf file solved the issue.

Related

Images ignoring Cache-Control in .htaccess

In my images folder, I have an .htaccess file with the following:
<IfModule mod_headers.c>
# Browsers may cache images for 24 hours, including disk cache for SSL
Header set Cache-Control "max-age=2628000, public, must-revalidate"
</IfModule>
When I curl an image in that folder, I get the following (Notice Cache-Control missing "public" and "must-revalidate"):
HTTP/1.1 200 OK
Server: nginx/1.11.8
Date: Fri, 14 Dec 2018 17:57:00 GMT
Content-Type: image/jpeg
Content-Length: 46563
Last-Modified: Fri, 29 Sep 2017 03:16:20 GMT
Connection: keep-alive
ETag: "59cdbb04-b5e3"
Expires: Fri, 21 Dec 2018 17:57:00 GMT
Cache-Control: max-age=604800
Strict-Transport-Security: max-age=31536000
Accept-Ranges: bytes
It does not matter what I put in the .htaccess file, I always get the above response.
If I create a new image in that folder, I also get the same above response.
If I change the extension on an image in that folder (.bak) I get the expected response (Cache-Control is correct):
HTTP/1.1 200 OK
Server: nginx/1.11.8
Date: Fri, 14 Dec 2018 17:59:35 GMT
Content-Type: image/gif
Content-Length: 19164
Connection: keep-alive
Last-Modified: Fri, 14 Dec 2018 16:07:12 GMT
ETag: "183ca-4adc-57cfd9fbbac00"
Accept-Ranges: bytes
Cache-Control: max-age=2628000, public, must-revalidate
Strict-Transport-Security: max-age=31536000
Any ideas what is going on here? I looked at all parent .htaccess files and apache config, I can not find anything!
Please help!!!
For anyone else experiencing this issue, the Apache .htaccess directive was being overridden by the following Nginx config:
location ~* ^(.+?)(?:\.\d+)?\.(jpe?g|gif|png|svg|ico|bmp|js|css|ttf|eot|woff2?)$ {
root /var/www;
try_files $1.$2 #apache;
expires 7d;
}
Replacing "expires 7d;" with the following did the trick:
add_header Cache-Control "max-age=2628000, public, must-revalidate";

Apache (not the browser) is caching my file

The browser is not caching it. It gets the response headers:
Accept-Ranges:bytes
Cache-Control:max-age=0, no-cache, no-store, must-revalidate
Connection:Keep-Alive
Content-Length:425169
Content-Type:application/javascript
Date:Thu, 09 Mar 2017 20:06:53 GMT
Expires:Wed, 11 Jan 1984 05:00:00 GMT
Keep-Alive:timeout=5, max=100
Last-Modified:Thu, 09 Mar 2017 20:06:49 GMT
Pragma:no-cache
Server:Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16
My settings in Apache:
<VirtualHost *:80>
<Directory "/webapps/apps/devsite">
Allow from all
AllowOverride All
Order allow,deny
</Directory>
DocumentRoot /webapps/apps/devsite
ServerName testing.devsite.com
SSLEngine off
</VirtualHost>
My .htaccess:
<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<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>
</FilesMatch>
The following loads a new, non-cached version:
on the server run: rm -f /webapps/apps/devsite/scripts/script.js
Reload in the web browser (thus getting a 404)
Copy the file back on to server
Reload in browser
The following does loads an old, CACHED version!:
On the server run: rm -f /webapps/apps/devsite/scripts/script.js
Copy the file back on to server (NOTE: I did not reload in browser yet)
Reload in browser
This shows that Apache is somehow caching it until it gets a new request and cannot find it. Why? How do i fix this?
The issue was it was using the kernel's SendFile which caused it to miss the file being changed. This is a Virtual Machine shared folder. Adding the following fixes it:
EnableSendfile off
(the "file" is lowercase)
More info here: https://www.vagrantup.com/docs/synced-folders/virtualbox.html
http://httpd.apache.org/docs/2.2/mod/core.html#enablesendfile
Apache does not permanently watch all files, only when you request a specific resource.
When you hit the 404 error, Apache loses the information about the file it has had found before.
The last modified timestamp does not change when you don't request a resource in the meantime.

Client-side caching of static files not working (Apache)

I'm trying to use mod_expires and mod_headers to enable browser caching for my site. I have this in my VirtualHost:
<FilesMatch ".(gif|jpg|jpeg|png|ico|swf|js|css|pdf)$">
ExpiresActive On
ExpiresDefault "access plus 1 week"
Header set Cache-Control "public"
Header unset Last-Modified
</FilesMatch>
The Expires and Cache-Control headers are set correctly in my responses:
HTTP/1.1 200 OK
Date: Tue, 28 Jun 2016 16:09:26 GMT
Server: Apache/2.4.7 (Ubuntu)
ETag: "8f44-526a1625962b5-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Cache-Control: public
Expires: Tue, 05 Jul 2016 16:09:26 GMT
Content-Length: 8504
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: application/javascript
Unfortunately, my browser (Chrome) is still requesting all these static files every time I load my page. I see these requests in my access.log and browser console. What am I doing wrong?
EDIT:
I do have caching enabled in the developer toolbar:
Check if client-side caching is disabled. Google Chrome may disable client-side caching when the DevTools window is open (F12).

Conditional request not honored in Includes

I'm trying to dynamically concatenate a bunch of javascript files into a single file using the INCLUDE filter. The include.shtml.js test script is
<!--#include virtual="/static/script2.js" -->
<!--#include virtual="/static/script1.js" -->
The virtual server config has both SSIETag and SSILastModified set to On for that file
<VirtualHost *:80>
ServerName test.dkt
ServerAlias test.com
UseCanonicalName Off
ErrorLog logs/test.dkt-error_log
CustomLog logs/test.dkt-access_log combined
LogLevel info
FileEtag All
AddType application/javascript .js
DocumentRoot /var/www/html/test.com
<Directory /var/www/html/test.com>
Options -Indexes
ExpiresActive Off
ExpiresDefault "access plus 1 years"
Header append Cache-Control "public"
Order deny,allow
Allow from all
</Directory>
<Directory /var/www/html/test.com/static>
<FilesMatch "\.shtml\.js$">
SSIETag On
SSILastModified On
Options +Includes
SetOutputFilter INCLUDES
</FilesMatch>
</Directory>
</VirtualHost>
It correctly serves the concatenated scripts but is always a full 200 OK in instead of a 304 Not Modified. The Firebug log
Response Headers
HTTP/1.1 200 OK
Date: Fri, 24 Jan 2014 16:57:12 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Fri, 24 Jan 2014 16:53:32 GMT
Etag: "460bbc-5c-4f0ba32b7447d"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Cache-Control: public
Content-Length: 40
Connection: close
Content-Type: application/javascript
Request Headers
GET /static/include.shtml.js HTTP/1.1
Host: test.dkt
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pt-br,en-us;q=0.9,es;q=0.7,en;q=0.6,zh-tw;q=0.4,ar-sa;q=0.3,ar;q=0.1
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
If-Modified-Since: Fri, 24 Jan 2014 16:53:32 GMT
If-None-Match: "460bbc-5c-4f0ba32b7447d"
Cache-Control: max-age=0
Is there a hard coded restriction on conditional requests for the INCLUDE filter?
I'm aware that I should "touch" the including script whenever there is a change in any of the included scripts. The Apache version is 2.2 running in Centos 6
EDIT
Using the #covener answer I made it work setting the group execute permission of the file and adding the XBitHack full directive
Even though you've opted into the etags, it seems you need to separately enable xbithack to allow a 304 to be generated (ap_meets_conditions in the core checks no_local_copy flag referenced in mod_include
http://httpd.apache.org/docs/current/mod/mod_include.html#xbithack
/* When our xbithack value isn't set to full or our platform isn't
* providing group-level protection bits or our group-level bits do not
* have group-execite on, we will set the no_local_copy value to 1 so
* that we will not send 304s.
*/
if ((conf->xbithack != XBITHACK_FULL)
|| !(f->r->finfo.valid & APR_FINFO_GPROT)
|| !(f->r->finfo.protection & APR_GEXECUTE)) {
f->r->no_local_copy = 1;
}
When having
SSILastModified on
XBitHack full
together in configuration file, the setting "SSILastModified On" is a silent misconfiguration, because whether "SSILastModified" is on or not, it does not change any program behavior.
By tracking back to the source code of Apache, we can see the root cause of this misconfiguration is that the semantics enabled by "Xbithack Full" implicitly overwrite the semantics enabled by "SSILastModified On".
if (conf->lastmodified > 0) {
... {
ap_update_mtime(r, r->finfo.mtime);
ap_set_last_modified(r);}}
else if (((conf->xbithack == XBITHACK_FULL ||
(conf->xbithack == XBITHACK_UNSET &&
DEFAULT_XBITHACK == XBITHACK_FULL))
...)) {
ap_update_mtime(r, r->finfo.mtime);
ap_set_last_modified(r);
}
So one possible solution would be just keep this
Xbithack full

Apache: mod_disk_cache setup for specific url pattern with LocationMatch

i'm trying to setup mod_disk_cache for a url pattern. Server runs Apache/2.2.22
Wanted:
All requests to 'domain.com/location/anyHtmlFile' should be served from cache.
Config:
CacheEnable disk /
CacheIgnoreCacheControl On
SetEnv no-cache
I want this to work:
"if url starts with "/location" do 'UnsetEnv no-cache'
In the apache vhost I tried
<LocationMatch "^/location/.+\.html$">
<LocationMatch "/location/">
and desperately
<LocationMatch "location">
UnsetEnv no-cache
</LocationMatch>
<Location /location/>
UnsetEnv no-cache
</Location>
didn't work, too.
An html file in /location/ has following caching-relevant header attributes (Firefox):
Cache-Control: max-age=14400, public
Date Wed, 05 Jun 2013 11:17:00 GMT
Expires Wed, 05 Jun 2013 15:17:00 GMT
I have just recognized that the requestheader for the same file in chrome says
Cache-Control:public
Cache-Control:no-cache, must-revalidate
I'm setting Cache-Control to 'public' explicitely in the expires.conf.
I commented the global
#SetEnv no-cache
out in my vhost config, but there are still both Cache-Controls in the header. But this shouldn't be the problem as I have 'CacheIgnoreCacheControl On', should it?
Any help?