Add Expires headers on Yslow doesn't have any effect - .htaccess

I have mod_expires and mod_headers enabled on the server and this code in htaccess:
<FilesMatch "\.(htm|html|xhtml|css|js|php)$">
AddDefaultCharset UTF-8
Header set Content-Language "en-US"
</FilesMatch>
<IfModule mod_headers.c>
Header set Vary "Accept-Encoding"
</IfModule>
php_value session.cookie_domain "www.domain.com"
Options -Indexes
# year
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf|mp3|mp4)$">
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
</FilesMatch>
#2 hours
<FilesMatch "\.(html|htm|xml|txt|xsl)$">
Header set Cache-Control "max-age=7200, must-revalidate"
</FilesMatch>
<FilesMatch "\.(js|css)$">
SetOutputFilter DEFLATE
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
</FilesMatch>
<FilesMatch ".(eot|ttf|otf|woff)">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*.domain.com"
</IfModule>
</FilesMatch>
<IfModule mod_deflate.c>
# Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
</IfModule>
</IfModule>
# Compress all output labeled with one of the following MIME-types
# (for Apache versions below 2.3.7, you don't need to enable `mod_filter`
# and can remove the `<IfModule mod_filter.c>` and `</IfModule>` lines as
# `AddOutputFilterByType` is still in the core directives)
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/atom+xml \
application/javascript \
application/json \
application/rss+xml \
application/vnd.ms-fontobject \
application/x-font-ttf \
application/xhtml+xml \
application/xml \
font/opentype \
image/svg+xml \
image/x-icon \
text/css \
text/html \
text/plain \
text/x-component \
text/xml
</IfModule>
</IfModule>
Options +FollowSymlinks
RewriteEngine On
<ifModule mod_headers.c>
Header unset ETag
</ifModule>
FileETag None
<IfModule mod_expires.c>
ExpiresActive on
# Perhaps better to whitelist expires rules? Perhaps.
ExpiresDefault "access plus 1 month"
# cache.appcache needs re-requests in FF 3.6 (thx Remy ~Introducing HTML5)
ExpiresByType text/cache-manifest "access plus 0 seconds"
# Your document html
ExpiresByType text/html "access plus 0 seconds"
# Data
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
# Favicon (cannot be renamed)
ExpiresByType image/x-icon "access plus 1 month"
# Media: 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"
# HTC files (css3pie)
ExpiresByType text/x-component "access plus 1 month"
# Webfonts
ExpiresByType font/truetype "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"
# CSS and JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
<IfModule mod_headers.c>
Header append Cache-Control "public"
</IfModule>
</IfModule>
In GTmatrix in Google pagespeed I have 100% but on Yslow the "Add Expires headers" is 0. I've tried everything but I can't seem to make Yslow work.
Can someone help?
Thanks.

You're setting the expiration to be in the past, which means they expire straight away. The idea behind adding expires headers is that you tell the browser that it doesn't even need to make an http request at all for this resource until some date in the future, instead it should just use the cached copy.
Probably only a good idea to use it on assets you know are not going to change. If you do end up changing an asset with a future expires date you'll need to change the url to it (which you can do by adding a query string on the end like blah.css?1234.
Also check that the expires headers are definitely coming through in the response headers of the assets by inspecting them with your web inspector.

Related

Cannot edit .htaccess without server error 500 contact webmaster message

I was trying to move gzip and cache headers to top of file before wp rocket and it didn't work even just chanhging erasing two blank lines between comments gave a server error even without changing data I tryed changing where gzip is called in .htaccess caus e the planet hosters article sayd to put gzip and the cache headers at the top. Mine starts with wp rocket settings and i can’t put gzip either before at the top or after wp rocket noteven after wordpress or even after double htaccess oath is don at the bottom but it gives an error all the time no matter what you change. I even tryed to erase 2 blank lines between comments that where empty, i didn’t change no data and it served a 500 error just like when htaccess is tamperd with. Now i have a cloudflare firewall and ddos protection, plus css,html and js minification and async going with cloudflare and wp rocket and even have autoptimize for 7 files that the others won’t defer. All those caches including opcache and pagespeed are going.
What is protecting htacess, i managed to change it before no i can’t anymore.
# BEGIN WP Rocket v3.2.3.1
# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset UTF-8
# Force UTF-8 for a number of file formats
<IfModule mod_mime.c>
AddCharset UTF-8 .atom .css .js .json .rss .vtt .xml
</IfModule>
# FileETag None is not enough for every server.
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
# Since we’re sending far-future expires, we don’t need ETags for static content.
# developer.yahoo.com/performance/rules.html#etags
FileETag None
<IfModule mod_alias.c>
<FilesMatch "\.(html|htm|rtf|rtx|txt|xsd|xsl|xml)$">
<IfModule mod_headers.c>
Header set X-Powered-By "WP Rocket/3.2.3.1"
Header unset Pragma
Header append Cache-Control "public"
Header unset Last-Modified
</IfModule>
</FilesMatch>
<FilesMatch>(css|htc|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz| gzip|ico|jpg|jpeg|jpe|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|otf|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
<IfModule mod_headers.c>
Header unset Pragma
Header append Cache-Control "public"
</IfModule>
</FilesMatch>
</IfModule>
# Force deflate for mangled headers
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$
^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-
Encoding
# Don’t compress images and other uncompressible content
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?
g|mp4|webm|webp|pdf)$ no-gzip dont-vary
</IfModule>
</IfModule>
# Compress all output labeled with one of the following MIME-types
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/atom+xml \
application/javascript \
application/json \
application/rss+xml \
application/vnd.ms-fontobject \
application/x-font-ttf \
application/xhtml+xml \
application/xml \
font/opentype \
image/svg+xml \
image/x-icon \
text/css \
text/html \
text/plain \
text/x-component \
text/xml
</IfModule>
<IfModule mod_headers.c>
Header append Vary: Accept-Encoding
</IfModule>
</IfModule>
# END WP Rocket
# PH pagespeed start
<IfModule pagespeed_module>
ModPagespeed on
ModPagespeedRewriteLevel PassThrough
ModPagespeedEnableFilters
</IfModule>
# PH pagespeed end
#PH auth start
ErrorDocument 401 default
<FilesMatch "^((wp-login)\.php|(xmlrpc)\.php|(admin-ajax)\.php)$">
AuthType Basic
AuthUserFile /home/punkmmur/.htpasswd
AuthName "Double Authentification PlanetHoster"
require valid-user
</FilesMatch>
#PH auth end
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
#Expires cache end
# BEGIN Cache-Control Headers
<IfModule mod_expires.c>
<IfModule mod_headers.c>
<filesMatch "\.(ico|jpe?g|png|gif|swf)$">
Header append Cache-Control "public"
</filesMatch>
<filesMatch "\.(css)$">
Header append Cache-Control "public"
</filesMatch>
<filesMatch "\.(js)$">
Header append Cache-Control "private"
</filesMatch>
<filesMatch "\.(x?html?|php)$">
Header append Cache-Control "private, must-revalidate"
</filesMatch>
</IfModule>
</IfModule>
# Disable ETags
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
php_value upload_max_filesize 200M
php_value post_max_size 200M
# Gzip compression
FileETag MTime Size
# Gzip compression
# Active compression
SetOutputFilter DEFLATE
#Activation du Mod Deflate
#Activation du Mod Deflate
<IfModule mod_deflate.c>
# Compresse les fichiers HTML, CSS, JavaScript, Text, XML et les fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
# Ce code est pour assurer une compatibilité avec les anciens
navigateurs
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Header append Vary User-Agent
</IfModule>
#Activation du mod Expires
#Customize expires cache start - adjust the period according to your
needs
# Expires headers (for better cache control)
#Activation du mod Expires
#Customize expires cache start - adjust the period according to
your
needs
# Expires headers (for better cache control)
<IfModule mod_expires.c>
FileETag MTime Size
ExpiresActive on
# Perhaps better to whitelist expires rules? Perhaps.
ExpiresDefault "access plus 1 month"
# cache.appcache needs re-requests in FF 3.6 (thanks Remy
~Introducing HTML5)
ExpiresByType text/cache-manifest "access plus 1 month"
# Your document html
ExpiresByType text/html "access plus 1 month"
# Data
ExpiresByType text/xml "access plus 1 month"
ExpiresByType application/xml "access plus 1 month"
ExpiresByType application/json "access plus 1 month"
# Feed
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/atom+xml "access plus 1 hour"
# Favicon (cannot be renamed)
ExpiresByType image/x-icon "access plus 1 week"
# Media: images, video, audio
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType video/ogg "access plus 1 year"
ExpiresByType audio/ogg "access plus 1 year"
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/webm "access plus 1 year"
# HTC files (css3pie)
ExpiresByType text/x-component "access plus 1 month"
# Webfonts
ExpiresByType application/x-font-ttf "access plus 1 year"
ExpiresByType font/opentype "access plus 1 year"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType application/x-font-woff2 "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
# CSS and JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Others
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
</IfModule>
# BEGIN ShortPixelWebp
# END ShortPixelWebp

How to leverage browser caching for static HTML assets?

I have built my static html on heroku. Here's the link: https://askheating.herokuapp.com/
Now when I am performing a test on GTMetrix, I have got a very bad score due to leverage browser caching.
This is my .htaccess script
AddType application/vnd.ms-fontobject .eot
AddType application/x-font-ttf .ttf
AddType application/x-font-opentype .otf
AddType application/x-font-woff .woff
AddType image/svg+xml .svg
# BEGIN Expire headers
<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"
ExpiresByType text/html "access plus 600 seconds"
ExpiresByType application/xhtml+xml "access plus 600 seconds"
</ifModule>
# END Expire headers
# BEGIN Cache-Control Headers
<ifModule mod_headers.c>
<filesMatch "\.(ico|jpe?g|png|gif|swf)$">
Header set Cache-Control "public"
</filesMatch>
<filesMatch "\.(css)$">
Header set Cache-Control "public"
</filesMatch>
<filesMatch "\.(js)$">
Header set Cache-Control "private"
</filesMatch>
<filesMatch "\.(x?html?|php)$">
Header set Cache-Control "private, must-revalidate"
</filesMatch>
</ifModule>
# END Cache-Control Headers
# This is for gzip, which compresses files
<ifModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>
#Remove the Need for www in Your URL
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www.askheating.herokuapp.com [NC]
RewriteRule ^(.*)$ https://askheating.herokuapp.com/$1 [L,R=301]
RewriteCond %{HTTPS} !on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
# disable directory browsing
Options All -Indexes
But still I'm getting this
Now I dont know how to play with nginx, and whwre to find all that stuff..
please help!!
Browser caching for .htaccess
The code below tells browsers what to cache and how long to "remember" it. It should be added to the top of your .htaccess file.
## EXPIRES CACHING ##
<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>
## EXPIRES CACHING ##
Save the .htaccess file and then refresh your webpage.
How to set different caching times for different file types
You can see in the above code that there are time periods like "1 year" or "1 month". These are associated with file types, as an example the above code states that a .jpg file (image) should be cached for a year.
If you want to change that and say you want your jpg images cached for a month you would simply replace "1 year" with "1 month". The values above are pretty optimized for most webpages and blogs.
Alternate caching method for .htaccess
The above method is called "Expires" and it works for most people using .htaccess so it takes care of caching for most people who are just getting started.
After you are more comfortable with caching, you may want to try Cache-Control, another method of caching which gives us more options.
It is also possible the expires method did not work for your server, in that case you may want to try to use Cache-Control.
Cache-Control
Cache-Control allows us to have a bit more control of our browser caching and many people find it easier to use once setup.
Example use in .htaccess file:
# 1 Month for most static assets
<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>
The above code is setting a cache control header depending on file type.
https://varvy.com/pagespeed/leverage-browser-caching.html
https://medium.com/#codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c

expiration set but still showing as not set

I've been trying to speed out our site and using gtmertix.com to check.
I've been adding / removing code all day and have this in the htaccess file.
I have the following set in .htaccess -
# Leverage Browser Caching
<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>
<IfModule mod_headers.c>
<filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
Header set Cache-Control "max-age=2678400, public"
</filesmatch>
<filesmatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, private, must-revalidate"
</filesmatch>
<filesmatch "\.(pdf)$">
Header set Cache-Control "max-age=86400, public"
</filesmatch>
<filesmatch "\.(js)$">
Header set Cache-Control "max-age=2678400, private"
</filesmatch>
</IfModule>
But i still get the following messages when i check on gtmetrix.com
http://cdn-images.mailchimp.com/embedcode/horizontal-slim-10_7.css (expiration not specified)
http://downloads.mailchimp.com/js/goal.min.js (expiration not specified)
http://buttons-config.sharethis.com/js/58ac087b20428700112b0504.js (1 minute)
http://platform-api.sharethis.com/js/sharethis.js (10 minutes)
https://connect.facebook.net/en_US/fbevents.js (20 minutes)
https://connect.facebook.net/signals/config/247608415681348?v=2.7.10 (20 minutes)
https://google-analytics.com/analytics.js (2 hours)
What can i do to add expiration to the above ? or is it not possible ?

How to specify a cache validator for PNG files in .htaccess?

I would like to cache all images and videos on the website for at least a month at user cache to speed up the loading process.
But the http://gtmetrix.com Speed Report gives me following error:
The following resources are missing a cache validator. Resources that
do not specify a cache validator cannot be refreshed efficiently.
Specify a Last-Modified or ETag header to enable cache validation for
the following resources:
// all *.png files currently on my page listed here //
Expiration times:
### CACHING ###
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
# cache.appcache needs re-requests in FF 3.6 (thx Remy ~Introducing HTML5)
ExpiresByType text/cache-manifest "access plus 0 seconds"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/rss+xml "access plus 1 hour"
# media: favicon, images, video, audio
ExpiresByType image/x-icon "access plus 1 month"
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"
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
# htc files (css3pie)
ExpiresByType text/x-component "access plus 1 month"
# webfonts
ExpiresByType font/truetype "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"
# css and javascript
ExpiresByType text/css "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
ExpiresByType text/javascript "access plus 1 week"
Cache control:
<IfModule mod_headers.c>
<FilesMatch "\.(ico|pdf|flv|jpe?g|png|gif|swf|ogg)$">
Header set Cache-Control "max-age=2592000, public"
Header unset Last-Modified
Header unset ETag
FileETag None
</FilesMatch>
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
<FilesMatch "\.(js)$">
Header set Cache-Control "max-age=604800, private"
</FilesMatch>
<FilesMatch "\.(xml|txt)$">
Header set Cache-Control "max-age=216000, public, must-revalidate"
</FilesMatch>
<FilesMatch "\.(x?html?|php)$">
Header set Cache-Control "max-age=1, private, must-revalidate"
</FilesMatch>
<FilesMatch "\.(eot|font.css|otf|ttc|ttf|woff)$">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
</IfModule>
</IfModule>
### / CACHING ###
What can I do to fix it?
BTW i found this: htaccess 'Header unset Last-Modified' caching issue but it looks like the guy doesn't have a problem with images
Given this warning:
Specify a Last-Modified or ETag header to enable cache
validation for the following resource
I suspect these lines in your config is the culprit:
Header unset Last-Modified
Header unset ETag
FileETag None
Your config is removing the header info used for cache validation.

Add Expires Headers for Specific Images

All of the expires headers articles I've looked at give more or less the following solution:
ExpiresByType image/gif A2592000
ExpiresByType image/png A2592000
ExpiresByType image/jpg A2592000
ExpiresByType image/jpeg A2592000
But it doesn't make sense to me because I know which of my images are going to change and which aren't, so I want to be able to add specific expiration dates to specific image files. How would I go about this?
You can use a FilesMatch, eg.
<FilesMatch "\.(js|css)$">
ExpiresActive on
ExpiresDefault "access plus 1 month"
</FilesMatch>
Or for some specific files:
<FilesMatch "^(example.js|sample.css)$">
ExpiresActive on
ExpiresDefault "access plus 1 month"
</FilesMatch>
Note that using ExpiresDefault for specific files will not work if you already used ExpiresByType. You need to use ExpiresByType again.
So this will NOT work (service-worker.js would still have +1 year expiry):
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType application/javascript "access plus 1 year"
<FilesMatch "^(service-worker.js)$">
ExpiresDefault "access plus 0 seconds"
</FilesMatch>
</IfModule>
But this will work (service-worker.js will have +0 seconds expiry):
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType application/javascript "access plus 1 year"
<FilesMatch "^(service-worker.js)$">
ExpiresByType application/javascript "access plus 0 seconds"
</FilesMatch>
</IfModule>
You might also use Header unset Expires. This would remove Expires header no matter what was set above it. You should also modify (or remove) Cache-Control header. It seems that mod_expires sets both.
<FilesMatch "^(service-worker.js)$">
Header unset Expires
Header set Cache-Control "max-age=0"
</FilesMatch>

Resources