Last active
October 25, 2024 14:52
-
-
Save peterjaap/006169c5d95eeffde3a1cc062de1b514 to your computer and use it in GitHub Desktop.
Updated Magento 2 Varnish 6 VCL, in cooperation with Varnish Software
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A number of these changes come form the following PR's; , combines changes in https://github.com/magento/magento2/pull/29360, https://github.com/magento/magento2/pull/28944 and https://github.com/magento/magento2/pull/28894, https://github.com/magento/magento2/pull/35228, https://github.com/magento/magento2/pull/36524, https://github.com/magento/magento2/pull/34323 | |
# VCL version 5.0 is not supported so it should be 4.0 even though actually used Varnish version is 6 | |
vcl 4.1; | |
import std; | |
# The minimal Varnish version is 6.0 | |
# For SSL offloading, pass the following header in your proxy server or load balancer: '/* {{ ssl_offloaded_header }} */: https' | |
backend default { | |
.host = "/* {{ host }} */"; | |
.port = "/* {{ port }} */"; | |
.first_byte_timeout = 600s; | |
.probe = { | |
.url = "/health_check.php"; | |
.timeout = 2s; | |
.interval = 5s; | |
.window = 10; | |
.threshold = 5; | |
} | |
} | |
acl purge { | |
/* {{ ips }} */ | |
} | |
sub vcl_recv { | |
# Add support for Prismic preview functionality | |
if (req.http.Cookie ~ "io.prismic.preview") { | |
return (pass); | |
} | |
# Remove empty query string parameters | |
# e.g.: www.example.com/index.html? | |
if (req.url ~ "\?$") { | |
set req.url = regsub(req.url, "\?$", ""); | |
} | |
# Remove port number from host header | |
set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); | |
# Sorts query string parameters alphabetically for cache normalization purposes | |
set req.url = std.querysort(req.url); | |
# Remove the proxy header to mitigate the httpoxy vulnerability | |
# See https://httpoxy.org/ | |
unset req.http.proxy; | |
# Add X-Forwarded-Proto header when using https | |
if (!req.http.X-Forwarded-Proto && (std.port(server.ip) == 443 || std.port(server.ip) == 8443)) { | |
set req.http.X-Forwarded-Proto = "https"; | |
} | |
# Reduce grace to the configured setting if the backend is healthy | |
# In case of an unhealthy backend, the original grace is used | |
if (std.healthy(req.backend_hint)) { | |
set req.grace = /* {{ grace_period }} */s; | |
} | |
if (req.method == "PURGE") { | |
if (client.ip !~ purge) { | |
return (synth(405, "Method not allowed")); | |
} | |
# To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header | |
# has been added to the response in your backend server config. This is used, for example, by the | |
# capistrano-magento2 gem for purging old content from varnish during it's deploy routine. | |
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { | |
return (purge); | |
} | |
if (req.http.X-Magento-Tags-Pattern) { | |
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); | |
} | |
if (req.http.X-Pool) { | |
ban("obj.http.X-Pool ~ " + req.http.X-Pool); | |
} | |
return (synth(200, "Purged")); | |
} | |
if (req.method != "GET" && | |
req.method != "HEAD" && | |
req.method != "PUT" && | |
req.method != "POST" && | |
req.method != "PATCH" && | |
req.method != "TRACE" && | |
req.method != "OPTIONS" && | |
req.method != "DELETE") { | |
return (pipe); | |
} | |
# We only deal with GET and HEAD by default | |
if (req.method != "GET" && req.method != "HEAD") { | |
return (pass); | |
} | |
# Bypass health check requests | |
if (req.url ~ "^/(pub/)?(health_check.php)$") { | |
return (pass); | |
} | |
# Collapse multiple cookie headers into one | |
std.collect(req.http.Cookie); | |
# Remove all marketing get parameters to minimize the cache objects | |
if (req.url ~ "(\?|&)(_branch_match_id|srsltid|_bta_c|_bta_tid|_ga|_gl|_ke|_kx|campid|cof|customid|cx|dclid|dm_i|ef_id|epik|fbclid|gad_source|gbraid|gclid|gclsrc|gdffi|gdfms|gdftrk|hsa_acc|hsa_ad|hsa_cam|hsa_grp|hsa_kw|hsa_mt|hsa_net|hsa_src|hsa_tgt|hsa_ver|ie|igshid|irclickid|matomo_campaign|matomo_cid|matomo_content|matomo_group|matomo_keyword|matomo_medium|matomo_placement|matomo_source|mc_cid|mc_eid|mkcid|mkevt|mkrid|mkwid|msclkid|mtm_campaign|mtm_cid|mtm_content|mtm_group|mtm_keyword|mtm_medium|mtm_placement|mtm_source|nb_klid|ndclid|origin|pcrid|piwik_campaign|piwik_keyword|piwik_kwd|pk_campaign|pk_keyword|pk_kwd|redirect_log_mongo_id|redirect_mongo_id|rtid|sb_referer_host|ScCid|si|siteurl|s_kwcid|sms_click|sms_source|sms_uph|toolid|trk_contact|trk_module|trk_msg|trk_sid|ttclid|twclid|utm_campaign|utm_content|utm_creative_format|utm_id|utm_marketing_tactic|utm_medium|utm_source|utm_source_platform|utm_term|wbraid|yclid|zanpid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") { | |
set req.url = regsuball(req.url, "(_branch_match_id|srsltid|_bta_c|_bta_tid|_ga|_gl|_ke|_kx|campid|cof|customid|cx|dclid|dm_i|ef_id|epik|fbclid|gad_source|gbraid|gclid|gclsrc|gdffi|gdfms|gdftrk|hsa_acc|hsa_ad|hsa_cam|hsa_grp|hsa_kw|hsa_mt|hsa_net|hsa_src|hsa_tgt|hsa_ver|ie|igshid|irclickid|matomo_campaign|matomo_cid|matomo_content|matomo_group|matomo_keyword|matomo_medium|matomo_placement|matomo_source|mc_cid|mc_eid|mkcid|mkevt|mkrid|mkwid|msclkid|mtm_campaign|mtm_cid|mtm_content|mtm_group|mtm_keyword|mtm_medium|mtm_placement|mtm_source|nb_klid|ndclid|origin|pcrid|piwik_campaign|piwik_keyword|piwik_kwd|pk_campaign|pk_keyword|pk_kwd|redirect_log_mongo_id|redirect_mongo_id|rtid|sb_referer_host|ScCid|si|siteurl|s_kwcid|sms_click|sms_source|sms_uph|toolid|trk_contact|trk_module|trk_msg|trk_sid|ttclid|twclid|utm_campaign|utm_content|utm_creative_format|utm_id|utm_marketing_tactic|utm_medium|utm_source|utm_source_platform|utm_term|wbraid|yclid|zanpid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+(){}%.]+&?", ""); | |
set req.url = regsub(req.url, "[?|&]+$", ""); | |
} | |
# Static files caching | |
if (req.url ~ "^/(pub/)?(media|static)/") { | |
# Static files should not be cached by default | |
return (pass); | |
# But if you use a few locales and don't use CDN you can enable caching static files by commenting previous line (#return (pass);) and uncommenting next 3 lines | |
#unset req.http.Https; | |
#unset req.http./* {{ ssl_offloaded_header }} */; | |
#unset req.http.Cookie; | |
} | |
# Don't cache the authenticated GraphQL requests | |
if (req.url ~ "/graphql" && req.http.Authorization ~ "^Bearer") { | |
return (pass); | |
} | |
return (hash); | |
} | |
sub vcl_hash { | |
if (req.url !~ "/graphql" && req.http.cookie ~ "X-Magento-Vary=") { | |
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1")); | |
} | |
# To make sure http users don't see ssl warning | |
hash_data(req.http./* {{ ssl_offloaded_header }} */); | |
/* {{ design_exceptions_code }} */ | |
if (req.url ~ "/graphql") { | |
if (req.http.X-Magento-Cache-Id) { | |
hash_data(req.http.X-Magento-Cache-Id); | |
} else { | |
# if no X-Magento-Cache-Id (which already contains Store & Currency) is not set, use the HTTP headers | |
hash_data(req.http.Store); | |
hash_data(req.http.Content-Currency); | |
} | |
} | |
} | |
sub vcl_backend_response { | |
# Serve stale content for three days after object expiration | |
# Perform asynchronous revalidation while stale content is served | |
set beresp.grace = 3d; | |
# All text-based content can be parsed as ESI | |
if (beresp.http.content-type ~ "text") { | |
set beresp.do_esi = true; | |
} | |
# Allow GZIP compression on all JavaScript files and all text-based content | |
if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") { | |
set beresp.do_gzip = true; | |
} | |
# Add debug headers | |
if (beresp.http.X-Magento-Debug) { | |
set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control; | |
} | |
# Only cache HTTP 200 and HTTP 404 responses | |
if (beresp.status != 200 && beresp.status != 404) { | |
set beresp.ttl = 120s; | |
set beresp.uncacheable = true; | |
return (deliver); | |
} | |
# Don't cache if the request cache ID doesn't match the response cache ID for graphql requests | |
if (bereq.url ~ "/graphql" && bereq.http.X-Magento-Cache-Id && bereq.http.X-Magento-Cache-Id != beresp.http.X-Magento-Cache-Id) { | |
set beresp.ttl = 120s; | |
set beresp.uncacheable = true; | |
return (deliver); | |
} | |
# Remove the Set-Cookie header for cacheable content | |
# Only for HTTP GET & HTTP HEAD requests | |
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) { | |
unset beresp.http.Set-Cookie; | |
} | |
} | |
sub vcl_deliver { | |
if (obj.uncacheable) { | |
set resp.http.X-Magento-Cache-Debug = "UNCACHEABLE"; | |
} else if (obj.hits) { | |
set resp.http.X-Magento-Cache-Debug = "HIT"; | |
set resp.http.Grace = req.http.grace; | |
} else { | |
set resp.http.X-Magento-Cache-Debug = "MISS"; | |
} | |
# Not letting browser to cache non-static files. | |
if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") { | |
set resp.http.Pragma = "no-cache"; | |
set resp.http.Expires = "-1"; | |
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0"; | |
} | |
if (!resp.http.X-Magento-Debug) { | |
unset resp.http.Age; | |
} | |
unset resp.http.X-Magento-Debug; | |
unset resp.http.X-Magento-Tags; | |
unset resp.http.X-Powered-By; | |
unset resp.http.Server; | |
unset resp.http.X-Varnish; | |
unset resp.http.Via; | |
unset resp.http.Link; | |
} |
Updated the tracking parameters list to match https://github.com/mpchadwick/tracking-query-params-registry/blob/master/_data/params.csv
Notable differences
- VCL Version and Compatibility
- Magento VCL: Uses vcl 4.0 for compatibility, even though Varnish version 6 or 7 is used.
- Optimized VCL: Uses vcl 4.1—a more current version—while still maintaining compatibility with Varnish 6 and 7.
- Request Handling (sub vcl_recv)
- Magento VCL: Focuses on request normalization (removing marketing parameters, handling cache control for specific URL paths) but lacks improvements like query parameter sorting or more sophisticated request cleaning.
- Optimized VCL:
- Query String Optimization: Sorts query parameters using std.querysort() to improve cache efficiency.
- Empty Query Parameter Removal: Eliminates empty query strings for normalization.
- Host Header Cleanup: Removes port numbers from the Host header for better cache key normalization.
- Httpoxy Vulnerability Mitigation: Unsets the proxy header to mitigate potential vulnerabilities.
- Grace Period for Healthy Backend: Dynamically adjusts the grace period based on backend health.
- Advanced Query Param Removal: Removes more marketing-related query parameters compared to the original Magento VCL, optimizing cache objects even further.
- Cookie and Header Management
- Magento VCL: Uses std.collect() on cookies but doesn't perform additional cookie header collapsing or aggressive cleanup of unnecessary headers.
- Optimized VCL: Collapses multiple Cookie headers and removes headers like proxy for more efficient processing and enhanced security.
- Cache Key Generation (sub vcl_hash)
- Magento VCL: Hashes certain request headers and applies logic for GraphQL and Magento's X-Magento-Vary cookies, but has room for better structure and logic consolidation.
- Optimized VCL:
- Consolidation: Handles GraphQL requests and Magento cache ID more elegantly by ensuring either the X-Magento-Cache-Id or fallback headers (Store, Content-Currency) are used for hashing.
- General Security: Adds more structured logic for SSL offloading, improving HTTPS handling and hash key integrity.
- Backend Response Handling (sub vcl_backend_response)
- Magento VCL:
- Basic TTL Control: Caches 200 and 404 responses but unsets cookies in a less optimized way.
- Hit-For-Pass: Implements a basic Hit-For-Pass strategy when responses are uncachable.
- Optimized VCL:
- Grace and Stale Content: Keeps stale content for up to 3 days, using asynchronous revalidation to refresh the cache while still serving expired content.
- Set-Cookie Header: Proactively unsets Set-Cookie for cacheable content (GET and HEAD requests) to improve cache hit rates.
- Strict TTL Control: Sets a short (120s) TTL for uncacheable content and mismatched GraphQL cache IDs to avoid excessive pass-throughs.
- Header Management on Delivery (sub vcl_deliver)
- Magento VCL: Unsets a range of headers such as X-Magento-Tags, X-Powered-By, and Server, but includes debugging information in a basic form.
- Optimized VCL:
- Improved Debugging: Adds more specific debugging headers (X-Magento-Cache-Debug), including detailed cache hit/miss reporting.
- More Aggressive Header Cleanup: Unsets additional headers like X-Varnish, Via, and Link to streamline responses and reduce unnecessary data sent to clients.
- Security Enhancements
- Magento VCL: Implements basic security by removing sensitive headers but lacks more advanced threat mitigations.
- Optimized VCL: Includes explicit X-Forwarded-Proto logic for HTTPS, better security header management (e.g., removing proxy headers), and optimizations like the removal of the HTTPoxy vulnerability.
- GraphQL Request Handling
- Magento VCL: Caches only authorized GraphQL requests with appropriate X-Magento-Cache-Id headers, but with slightly less efficient logic for hashing and caching.
- Optimized VCL: More streamlined and optimized logic for handling GraphQL cache keys, including fallback mechanisms to ensure cache key integrity even if X-Magento-Cache-Id is not set.
- Simplified Logic and Performance Improvements
- The Optimized VCL is much cleaner, with more consolidated logic, fewer repetitive conditions, and more robust performance enhancements (e.g., cookie collapsing, better query handling, etc.). It also introduces enhanced debugging features and more granular cache control based on real-time conditions such as backend health and dynamic grace periods.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Melleschepers done!