How can I make browsers cache html files? - apache

I want browsers to cache html files. I set up Apache2.4 and confirm css, js, png are cached, but html files are never cached.
Chrome 90 and Edge 90
Apache 2.4
/etc/httpd/conf/httpd.conf
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 30 days"
</IfModule>

Hi try to add ExpiresByType text/html "access plus 7200 seconds". Hope it works !

Related

PHP site not showing cache-control. Not caching anything

INTRO
I have a task to fix existing site's problem that nothing is being cached (except for browser session). When closing session and opening browser again, page loads a lot of images, JS and CSS again. As I have ~60 items every time, there is a big load problem.
PROBLEM
Looking at Chrome console, Audit shows The following resources are missing a cache expiration...
And in Network item in "Response Headers" doesn't even show "cache-control" line.
TRIED SOLUTIONS
I have set info in .htaccess file and made sure mod_expires is active:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"
</IfModule>
I added Cache-control meta-tag in html head that is also showing in page's code source so it is compiled.
<meta http-equiv="Cache-control" content="public" content="max-age=604800">
And I'd like to add that it most likely isn't a server issue as production page's host has set it to a usual default. (And I don't have access to that server anyways)
I'd be super delighted, if someone could give me some pointers of what I am missing or haven't checked or simply don't understand.
Added main.css headers
Thanks!
You can set the headers through php since this is a php site.
<?php
header("Cache-Control: max-age=2592000"); //30days (60sec * 60min * 24hours * 30days)
?>
Also you can use the FilesMatch like this in your .htaccess
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
Well, although stupid (as I expected), but I didn't read about it anywhere and just forget about the need of it.
Solution
It turned out all those things changed (as I said everything was activated on server, access files etc). And the problem was that I didn't clear the cache after changing caching info. Now after three days I started working on some CSS, needed to reset the cache and boom - all the new headers are active for all the items.

Apache2 mod_expires not working

I have recently deployed a website on a VPS that supports Apache2, and was working on performance improvement suggestions by YSlow.
Among those improvements were using mod_deflate and mod_expires, and since I have root access, I can directly edit the Apache config files.
mod_deflate is now working, but I am having issues with mod_expires so here is what I have done:
enable expires module and restart the server
a2enmod expires
service apache2 restart
create a new file "expires.conf" under mods_enabled that contains the following:
<IfModule mod_expires.c>
# Enable expirations
ExpiresActive On
# Default directive
ExpiresDefault "access plus 1 month"
# My favicon
ExpiresByType image/x-icon "access plus 1 year"
# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
# CSS
ExpiresByType text/css "access plus 1 month"
# Javascript
ExpiresByType application/javascript "access plus 1 year"
</IfModule>
However, when checking on various browsers Dev Tools under Network, the files show a Cache Control of None.
I thought of using my mod_expires script above in a .htaccess located in the root directory of my website: /var/www/sitename/public_html, since settings in the .htaccess override any prior settings made in the apache config files.
For that, i enabled the use of htaccess in apache2.conf.
I tested that my htaccess file was indeed working by willingly introducing an error in it (commented out the IfModule open tag). Refreshing the browser gave me a 500 server error. So the htaccess file was being processed.
Unfortunately, the browser dev tools still showed no cache control, and I am running out of ideas.
Am I missing something?
Thanks!
Most likely, your expires.conf is getting parsed before the expires module is loaded, as you have included the configuration file in the mods-enabled folder.
Place your config file in conf.d and restart Apache.
I finally fixed the issue:
firstly i noticed a difference between all the other config files and the one i had created under mods-enabled: the others were symlinks to their respective files under mods-available. This shouldn't be an issue but definitely better stick to the convention.
It seems I may not have restarted the apache2 service after creating the file
In my case, I had to:
Move the expires.conf to /etc/apache2/conf-available/ . I think this would be necessary to load the configs after the module.
mv /etc/apache2/mods-available/expires.conf /etc/apache2/conf-available/
Also I had forgotten to enable the config before restarting apache.
a2enconf expires
service apache2 reload

Apache not caching static content

I read the official caching guide of the latest Apache httpd version, but did not understand how to get a minimal caching setup for static content.
Googling around, I finally added these rules to my /etc/apache2/apache2.conf (I'm using Ubuntu):
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 5 seconds"
ExpiresByType image/x-icon "access plus 2592000 seconds"
ExpiresByType image/jpeg "access plus 2592000 seconds"
ExpiresByType image/png "access plus 2592000 seconds"
ExpiresByType image/gif "access plus 2592000 seconds"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
ExpiresByType text/css "access plus 604800 seconds"
ExpiresByType text/javascript "access plus 216000 seconds"
ExpiresByType application/javascript "access plus 216000 seconds"
ExpiresByType application/x-javascript "access plus 216000 seconds"
</IfModule>
<IfModule mod_headers.c>
Header set Cache-Control "public"
</IfModule>
FileETag None
Obviously, I already enabled expires, headers, cache modules.
When I try to access an image, a css or js file, I see 200 OK the first time, and 304 the next ones. So, I thought I was right... but Google Pagespeed (for example) still complains about files that are not cached.
Actually, I had some suspects that I'm missing something:
I didn't activate mod_cache or mod_cache_disk. Should I? What's the basic set of rules for doing so?
Why is it necessary to disable the ETag?
I absolutely need my cache to expire suddenly when the file is changed: ideally, the expiration time (for css, js) could be very long, let's say, two weeks, but if the file changes after one hour, the user should mandatory get the updated file! Is that behavior automatically managed by Apache?
I absolutely need my cache to expire suddenly when the file is changed
TWhen you use mod_expires to send an Expires header the client doesn't have to make sure the file is fresh and you can't force a change ever.
If you drop mod_expires, your static files will have an ETAG and a last-modified-time which allows browsers to make sure the file hasn't changed (these are the 304 responses).
You'll need to a) scrutinize the pagespeed messages more closely B) assess them against your requirement and C) look at real world traffic in your access log wrt 304s.
You do not want mod_cache for static files.

Setting expire headers and gzipping data via .htaccess

I'm trying to set it up so that the browser will cache the webfonts for a long period and also attempting to gzip them for a faster download.
From what I can understand you can do this via your httpd.conf file in Apache or via .htaccess.
I'm not sure how to tell if gzip is enabled though, I read something about searching your httpd.conf file for DEFLATE; I did that, but found nothing - so not sure if it's enabled or not!?
Anyway, I have put this code below into the .htaccess file, partially because I didn't know where to put it in the httpd.conf file and partially because it's easier to make changes in .htaccess file without bothering my host continually.
Here is the code..
# Add correct content-type for fonts
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType font/x-woff .woff
AddType image/svg+xml .svg
# Compress compressible fonts
AddOutputFilterByType DEFLATE font/ttf font/otf image/svg+xml
# Add a far future Expires header for fonts
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType font/otf "access plus 1 year"
ExpiresByType font/x-woff "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
Now, I'm wondering if this is correct or not as I also seen this similar, but different code for the expiry..
ExpiresByType application/x-font-ttf "access plus 1 month"
ExpiresByType font/opentype "access plus 1 month"
ExpiresByType application/x-font-woff "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
Does it matter where you place it in the .htaccess file or can it go anywhere?
ExpiresByType can go in your httpd.conf, virtualhost config or htaccess, as shown in the apache documentation overview box at the top of each directive entry:
http://httpd.apache.org/docs/2.2/mod/mod_expires.html#expiresbytype
The Context listing is how you can tell which configuration files you can put your various Apache directive types into.
Assuming you are using PHP, your phpinfo details should tell you if gzip is enabled.
Edit
In response to your question about correct way MIME type for your fonts, in terms of their file association with the Apache Server, my mime.types file (found in apache conf folder where your httpd.conf lives) tells me that
application/x-font-(extension)
would be the association to use with ExpiresByType. I would suggest getting the fonts working first, and then checking the headers for the font url to see if its giving proper expiration date.
As for the browsers receiving the web fonts, this article seems to indicate that MIME types aren't considered and thus don't matter. But yet this one seems to contradict that. As I understand it, there is no official font/ MIME type so any browser implementation is outside the MIME specifications.
Related questions:
Proper MIME type for fonts
Correct Apache AddType directives for font MIME types
I've not seen anything specifying placement requirements in .htaccess so you should be safe putting these rules wherever you see fit, although if you do AddTypes you need to do so above any further directives that reference that declared Type. It's probably best to put these near the top above your rewrite rules.

Last modification date of web page unknown

I would like to check the age of the document in the webpage, but it does not show! Here is the result of a telnet to the server:
telnet av.hostoi.com 80
Connected to av.hostoi.com. HEAD / HTTP/1.0
HTTP/1.1 200 OK Date: Tue, 23 Oct 2012 16:55:40 GMT
Server: Apache
X-Powered-By: PHP/5.2.17
Connection: close
Content-Type: text/html
Connection closed by foreign host.
On another server the following 2 lines are also included which are not present above:
Last-Modified: Fri, 17 Jun 2011 11:17:45 GMT
ETag: "2ce392-b1-4a5e688eae840"
So I searched the Internet and as far as I could figure out, there should be a configuration in Apache to set headers on and etag on in htaccess. But I couldn't find any place that shows me that.
Here are the loaded modules in Apache if it would help:
core mod_authn_file mod_authn_default mod_authz_host mod_authz_groupfile mod_authz_user mod_authz_default mod_auth_basic mod_include mod_filter mod_log_config mod_env mod_expires mod_headers mod_setenvif mod_version prefork http_core mod_mime mod_status mod_autoindex mod_asis mod_info mod_vhost_alias mod_negotiation mod_dir mod_actions mod_alias mod_rewrite mod_so mod_php5 mod_ruid2
As far as I read mod_header must be enabled which seems to be the case.
Any help on this?
edit:
tried the proposed solution:
put a .htaccess file in / folder even though there is a file named do not upload here.
contents of .htaccess:
<code>
# Do not remove this line, otherwise mod_rewrite rules will stop working
RewriteBase /
Options -Indexes
SSILastModified on
<IfModule mod_expires.c>
FileETag MTime Size
ExpiresActive on
ExpiresDefault "access plus 10 days"
ExpiresByType application/javascript "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType application/x-shockwave-flash "access plus 1 week"
ExpiresByType text/css "access plus 1 week"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/x-icon "access plus 6 month"
ExpiresByType image/ico "access plus 6 month"
</IfModule>
</code>
i put this file in public_html folder and in the sub folder nod_update3 where the file update.ver exists.
then i execute the script that checks the age of the document like so:
./check_http -H av.hostoi.com -u /nod_update3/update.ver -M 2d
HTTP CRITICAL: HTTP/1.1 200 OK - Document modification date unknown - 26316 bytes in 0,159 second response time |time=0,158965s;;;0,000000 size=26316B;;;0
as you can see no modification date is shown even though on the ftp client it shows it was last modified 25.10.2012
i tried the check on another file in the same folder like so:
./check_http -H av.hostoi.com -u /nod_update3/em000_32_l0.nup -M 2d
HTTP CRITICAL: HTTP/1.1 200 OK - Last modified 13,5 days ago - 56472 bytes in 1,059 second response time |time=1,059014s;;;0,000000 size=56472B;;;0
srvmon plugins #
as you can see the date modification is known. so why the problem with ver file?
the file can be checked in this url:
http://av.hostoi.com/nod_update3//update.ver
The problem is that you have caching of static content enabled on first server, and on second one that is not the case.
Please take a look in apache main configuration file,virtual host or .htacess on second server
if you have something similar to:
<IfModule mod_expires.c>
FileETag MTime Size
ExpiresActive on
<filesMatch "\.ver$">
ExpiresDefault "modification plus 2 week"
</filesMatch>
</IfModule>
Also you need to enable apache module mod_expires.
Hope this helps!
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);
}
One possible solution here is to replace "SSILastModified on" with "Xbithack Full".