To tak, żeby cache miał sens, to nazwa zasobu musi być unikalna (w nazwie pliku hash z zawartości). Wtedy można cache ustawić na bardzo długi czas i jeśli zmieni się zawartość, hash się przeliczy i będzie nowy link.
Czyli de facto musisz tu mieć jakiś builder wpleciony. Krok po kroku to wygląda tak:
1. Budujesz całą stronę (html, js, css).
2. Dla assetów (js, css) wyliczasz ich hashe z zawartości pliku.
3. Zmieniasz nazwę (np z main.css, main.js na odpowiedniki z hashem w nazwie => main-a0a9af.css main-8a98asdf.js).
4. We wszystkich plikach HTML podmieniasz linki z main.css na main-a0a9af.css i main.js na main-8a98asdf.js
Cache plików HTML pownien być krótki, tak aby przeglądarka dość często pobierała samą stronę, natomiast assety można w takim przypadku wrzucać do cache nawet np na rok, albo w sumie też do nieskończoności ;-) Jeśli nastąpią zmiany w treści, wygeneruje się nowy hash, nowa nazwa pliku => przeglądarka pobierze nowe pliki.
CDN może serwować nagłówki z serwera źródła. Cache na poziomie serwera www można zrobić na kilka sposobów, w zależności od wersji, dostępnych modułów.
Przykłady dla Apache:
<IfModule mod_headers.c>
# Images - 1 year
<filesMatch "\.(jpg|jpeg|png|gif|ico|svg)$">
Header set Cache-Control "max-age=31536000, public"
Header unset Set-Cookie
</filesMatch>
# Fonts - 1 year
<filesMatch "\.(ttf|otf|eot|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
Header unset Set-Cookie
</filesMatch>
# JS/CSS - 1 year
<filesMatch "\.(css|js)$">
Header set Cache-Control "max-age=31536000, public"
Header unset Set-Cookie
</filesMatch>
# Media files - 1 month
<FilesMatch "\.(txt|pdf|flv|swf|mp3|mp4)$">
Header set Cache-Control "max-age=2628000, public, must-revalidate"
Header unset Set-Cookie
# Create the ETag to check resource hash every time
FileETag MTime Size
</FilesMatch>
# XML - 1 hour
<FilesMatch "\.xml$">
Header set Cache-Control "max-age=3600, public, must-revalidate, no-cache"
# Create the ETag to check resource hash every time
FileETag MTime Size
</FilesMatch>
# Short, 1 min cache for html files, forcing re-validate with ETag
<FilesMatch ".(htm|html)$">
Header set Cache-Control "max-age=60, public, must-revalidate, no-cache"
# Create the ETag to check resource hash every time
FileETag MTime Size
</FilesMatch>
# PHP and JSON - disabled
<FilesMatch "\.(php|json)$">
Header set Cache-Control: "max-age=0, no-store, no-cache"
</FilesMatch>
# Make sure old browser won't get compressed files
<FilesMatch ".(js|css|xml|svg|json|gz|html|htm)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
<IfModule mod_expires.c>
# Set basic Expires header as a fallback
# If there is a Cache-Control header with the "max-age" or "s-maxage" directive in the response,
# the Expires header is ignored.
ExpiresActive on
# By default cache all for 1 minute only
# (so nothing will be cached for too long)
ExpiresDefault "access plus 60 seconds"
# Images
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/pipeg "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
# Icons
ExpiresByType image/ico "access plus 1 year"
ExpiresByType image/icon "access plus 1 year"
ExpiresByType text/ico "access plus 1 year"
ExpiresByType image/x-ico "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType application/ico "access plus 1 year"
ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
# Audio
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType audio/basic "access plus 1 month"
ExpiresByType audio/mid "access plus 1 month"
ExpiresByType audio/midi "access plus 1 month"
ExpiresByType audio/mpeg "access plus 1 month"
ExpiresByType audio/x-aiff "access plus 1 month"
ExpiresByType audio/x-mpegurl "access plus 1 month"
ExpiresByType audio/x-pn-realaudio "access plus 1 month"
ExpiresByType audio/x-wav "access plus 1 month"
# Video
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
ExpiresByType video/x-msvideo "access plus 1 month"
ExpiresByType video/mpeg "access plus 1 month"
ExpiresByType video/quicktime "access plus 1 month"
ExpiresByType video/x-la-asf "access plus 1 month"
ExpiresByType video/x-ms-asf "access plus 1 month"
ExpiresByType x-world/x-vrml "access plus 1 month"
# Fonts
ExpiresByType font/truetype "access plus 1 year"
ExpiresByType font/opentype "access plus 1 year"
ExpiresByType application/x-font-ttf "access plus 1 year"
ExpiresByType application/x-font-woff "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
# Scripts and styles
ExpiresByType text/css "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
ExpiresByType text/x-javascript "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType application/x-javascript "access plus 1 year"
# Data
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType image/vnd.wap.wbmp "access plus 1 month"
ExpiresByType application/vnd.wap.wbxml "access plus 1 month"
ExpiresByType application/smil "access plus 1 month"
# Text
ExpiresByType text/html "access plus 1 minute"
ExpiresByType text/plain "access plus 1 minute"
ExpiresByType text/xml "access plus 1 minute"
ExpiresByType application/xml "access plus 1 minute"
# RSS
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/atom+xml "access plus 1 hour"
ExpiresByType text/x-component "access plus 1 hour"
# Live data
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/ld+json "access plus 0 seconds"
# Manifest
ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
ExpiresByType text/cache-manifest "access plus 0 seconds"
# PHP - diable to be cached unless they explicitly send cache headers themselves.
<FilesMatch \.php$>
ExpiresActive Off
</FilesMatch>
</IfModule>
<IfModule mod_deflate.c>
# Compress HTML, CSS, JavaScript, Text, XML and 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
</IfModule>