Skip to content

Instantly share code, notes, and snippets.

@peterjaap
Last active September 19, 2024 13:34
Show Gist options
  • Save peterjaap/006169c5d95eeffde3a1cc062de1b514 to your computer and use it in GitHub Desktop.
Save peterjaap/006169c5d95eeffde3a1cc062de1b514 to your computer and use it in GitHub Desktop.
Updated Magento 2 Varnish 6 VCL, in cooperation with Varnish Software
# 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|_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|_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;
}
@ThijsFeryn
Copy link

@peterjaap I'll continue look at this and suggest small fixes on Monday

@peterjaap
Copy link
Author

@ThijsFeryn thanks! I updated the gist accordingly.

@peterjaap
Copy link
Author

@ThijsFeryn we also have some rules in some of our VCLs to bypass routes that are never cached in Magento, does that make sense?

     # Bypass customer, shopping cart, checkout, admin
     if (req.url ~ "/customer" || req.url ~ "/checkout" || req.url ~ "/admin") {
        return (pass);
    }

@ThijsFeryn
Copy link

@ThijsFeryn we also have some rules in some of our VCLs to bypass routes that are never cached in Magento, does that make sense?

     # Bypass customer, shopping cart, checkout, admin
     if (req.url ~ "/customer" || req.url ~ "/checkout" || req.url ~ "/admin") {
        return (pass);
    }

If these pages return Cache-Control: private response headers or variations like Cache-Control: no-cache or Cache-Control: no-store, there is no need to explicitly have those rules for /customer, /checkout and /admin in VCL. Varnish will respect the Cache-Control header and bypass these requests from hitting the cache.

However, if the Cache-Control header doesn't return the right value, you need to write VCL.

Long story short: only write VCL in situations where the built-in VCL doesn't provide a native solution.

@ThijsFeryn
Copy link

@peterjaap The Varnish6.vcl file below you diff has the following code:

sub process_graphql_headers {
    if (req.http.X-Magento-Cache-Id) {
        hash_data(req.http.X-Magento-Cache-Id);

        # When the frontend stops sending the auth token, make sure users stop getting results cached for logged-in users
        if (req.http.Authorization ~ "^Bearer") {
            hash_data("Authorized");
        }
    }

    hash_data(req.http.Store);

    hash_data(req.http.Content-Currency);
}

This code implies that authorized /graphql calls can be cached in Magento. Is that the desired behavior? I was under the impression that authorized /graphql calls should bypass the cache.

Please clarify.

@peterjaap
Copy link
Author

peterjaap commented Nov 29, 2022

@ThijsFeryn from the Magento 2 docs;

Adobe Commerce and Magento Open Source can cache pages rendered from the results of certain GraphQL queries with full-page caching. Full-page caching improves response time and reduces the load on the server. Without caching, each page might need to run blocks of code and retrieve large amounts of information from the database. Only queries submitted with an HTTP GET operation can be cached. POST queries cannot be cached.

Indeed, I feel Authorized graphql calls should bypass the cache.

@JeroenBoersma
Copy link

Further optimization we do is skipping Varnish fully for certain requests..
Varnish doesn't support SSL so because we hit nginx for static files and immediately serve them by Nginx...

For instance: /static are only files which can be served with nginx

location /media/customer/ { deny all; }
location /media/import/   { deny all; }
location /magento_version { deny all; }

location /static {
  expires max;

  # Remove signature of the static files that is used to overcome the browser cache
  location ~ ^/static/version {
    rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
  }

  add_header Cache-Control "public";
  add_header X-Frame-Options "SAMEORIGIN";

  allow all;
}

@JeroenBoersma
Copy link

@ThijsFeryn
Copy link

ThijsFeryn commented Nov 29, 2022

Further optimization we do is skipping Varnish fully for certain requests.. Varnish doesn't support SSL so because we hit nginx for static files and immediately serve them by Nginx...

For instance: /static are only files which can be served with nginx

location /media/customer/ { deny all; }
location /media/import/   { deny all; }
location /magento_version { deny all; }

location /static {
  expires max;

  # Remove signature of the static files that is used to overcome the browser cache
  location ~ ^/static/version {
    rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
  }

  add_header Cache-Control "public";
  add_header X-Frame-Options "SAMEORIGIN";

  allow all;
}

@JeroenBoersma
But that is if you use Nginx as a TLS proxy. I actually advise using Hitch as a TLS proxy:

  • It's developed by Varnish Software
  • It's open source
  • It's a pure TLS proxy that has no HTTP awareness
  • It supports both PROXY protocol version 1 & 2

See https://www.varnish-software.com/developers/tutorials/terminate-tls-varnish-hitch/ for more information about Hitch and Varnish.

@convenient
Copy link

@peterjaap Here's the notes I added for my team, with pwa studio references for usage


Seems magento 2.4.4 and above, and latest PWA studio have improved cacheability for GQL requests
https://devdocs.magento.com/guides/v2.4/graphql/caching.html#customers

Magento generates a x-cache-id variation - https://github.com/magento/magento2/blob/192b28038dac2e993c65b49fb8b5af10cb520945/app/code/Magento/PageCache/etc/varnish6.vcl#L116-L148

PWA studio constantly grabs it from the response, and updates it to attach to the next requests so that when you log in etc you change customer groups / get cacheability
magento/pwa-studio@626ea1f#diff-b638977b4ea6fd3f29b668736551ed752c5b3915805df1af2f1a7579a006aacbR27

https://github.com/magento/pwa-studio/blob/626ea1f1c384654703501783b219bc7c4efa672d/packages/peregrine/lib/Apollo/links/gqlCacheLink.js#L41

@IvanChepurnyi
Copy link

IvanChepurnyi commented Nov 29, 2022

@peterjaap The Varnish6.vcl file below you diff has the following code:

sub process_graphql_headers {
    if (req.http.X-Magento-Cache-Id) {
        hash_data(req.http.X-Magento-Cache-Id);

        # When the frontend stops sending the auth token, make sure users stop getting results cached for logged-in users
        if (req.http.Authorization ~ "^Bearer") {
            hash_data("Authorized");
        }
    }

    hash_data(req.http.Store);

    hash_data(req.http.Content-Currency);
}

This code implies that authorized /graphql calls can be cached in Magento. Is that the desired behavior? I was under the impression that authorized /graphql calls should bypass the cache.

Please clarify.

This specific example implies that caching happens only when X-Magento-Cache-Id is set then, it additionally may add Authorization to it. Although, by default, GraphQL API allows doing queries without Authorization for stuff like catalog, so definitely looks strange.

Also, Authorization makes the cache user-specific, which removes any benefit of caching it in the Varnish server side, as if you have a spike of 1000 users, each of which will generate 1000 variations of the same cache.
I would probably remove Authorization header from the request in vcl_recv if X-Magento-Cache-Id is specified to prevent caching of customer-sensitive data in the first place. As a side effect, it should increase the cache hit ratio, as I imagine Authorization is added automatically if the request is sent when the user gets logged in. But that is implementation specific of the frontend that uses GraphQL, which should always separate customer-specific queries form cacheable ones.

@JeroenBoersma
Copy link

@JeroenBoersma But that is if you use Nginx as a TLS proxy. I actually advise using Hitch as a TLS proxy:

  • It's developed by Varnish Software
  • It's open source
  • It's a pure TLS proxy that has no HTTP awareness
  • It supports both PROXY protocol version 1 & 2

See https://www.varnish-software.com/developers/tutorials/terminate-tls-varnish-hitch/ for more information about Hitch and Varnish.

@ThijsFeryn If it would be just SSL termination than that's a true point, in this case it's a combined effort for file serving and (generated) content you get a performance gain by serving the files directly from the server and using Varnish for the generated content. There is no need to cache these static files on the same server in Varnish.

@JeroenBoersma
Copy link

rewrite /pub/health_check.php /health_check.php;

@JeroenBoersma
Copy link

A customer notified us with a list of more marketing pixels....

I think we can include these in the list of parameters to...
https://maxchadwick.xyz/tracking-query-params-registry/ props to @mpchadwick

Source which links to the above list: https://www.rumvision.com/blog/make-sure-to-check-your-caching-rules/

@ThijsFeryn
Copy link

A customer notified us with a list of more marketing pixels....

I think we can include these in the list of parameters to... https://maxchadwick.xyz/tracking-query-params-registry/ props to @mpchadwick

Source which links to the above list: https://www.rumvision.com/blog/make-sure-to-check-your-caching-rules/

@JeroenBoersma: here's the updated VCL:

    if (req.url ~ "(\?|&)(_branch_match_id|_bta_[a-z]+|campid|customid|_ga|gclid|gclsrc|gdf[a-z]+|cx|dm_i|ef_id|epik|ie|igshid|cof|hsa_[a-z]+|_ke|mk[a-z]{3}|msclkid|(mtm|matomo)_[a-z]+|pcrid|p(iwi)?k_[a-z]+|redirect(_log)?_mongo_id|siteurl|s_kwcid|sb_referer_host|si|trk_[a-z]+|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
        set req.url = regsuball(req.url, "(_branch_match_id|_bta_[a-z]+|campid|customid|_ga|gclid|gclsrc|cx|dm_i|ef_id|epik|ie|igshid|cof|hsa_[a-z]+|_ke|mk[a-z]{3}|msclkid|(mtm|matomo)_[a-z]+|pcrid|p(iwi)?k_[a-z]+|redirect(_log)?_mongo_id|siteurl|s_kwcid|sb_referer_host|si|trk_[a-z]+|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
        set req.url = regsub(req.url, "[?|&]+$", "");
    }

@damienwebdev
Copy link

@peterjaap and @ThijsFeryn magento/magento2#37524

These marketing pixels should be ignored when hitting graphql otherwise you'll endup regsub way more than you expect. Sometimes, likely unexpectedly, there's a relative URL (with query params) hidden inside the URL.

@chrisastley
Copy link

You have an error on line 44, the close bracket before the || needs removing.

@peterjaap
Copy link
Author

@chrisastley thanks!

@peterjaap
Copy link
Author

@glo11372
Copy link

glo11372 commented Feb 27, 2024

sub process_graphql_headers {
if (req.http.X-Magento-Cache-Id) {
hash_data(req.http.X-Magento-Cache-Id);

    # When the frontend stops sending the auth token, make sure users stop getting results cached for logged-in users
    if (req.http.Authorization ~ "^Bearer") {
        hash_data("Authorized");
    }
}

hash_data(req.http.Store);

hash_data(req.http.Content-Currency);

}
Can we remove Authorization token from frontend as ‘X-Magento-Cache-Id’ already there which provide Authorization so no need of bearer token?

@eneskirca
Copy link

eneskirca commented Jul 12, 2024

Hello @peterjaap

Could you add nb_klid in marketing parameters ?
klaviyo is adding like below;
?utm_source=Klaviyo&utm_medium=email&utm_campaign=Flash%20Sale%20%7C%20BOGO50%20%7C%20Panther%20Bracelets&nb_klid=01GYYXF9WQJE9K5KMWHXCCJ2EJ&_kx=149hMbYs3n64hbonnZsQJb9Bbn2cWv9qxmrHmgLSqLA.YwSEB3

And I wonder can GA4 follow links even after removing UTM and marketing tags by varnish.vcl?

@peterjaap
Copy link
Author

@eneskirca I've added nb_klid to the list.

The VCL only strips off these parameters for internal usage. This is done so Varnish can calculate the hash correctly, thereby increasing the hit rate. The actual parameter stays in the GET URL, so Javascript based tools like GA4 can still read out the parameter from the GET querystring.

@codedge
Copy link

codedge commented Aug 16, 2024

@peterjaap

  • Can I use this file for Varnish 7 as well?
  • These placeholder, f. ex. {{ host }}, do I need to replace them manually or can I somehow insert the proper values?

@peterjaap
Copy link
Author

@codedge

  • I'm not sure, but if it compiles it should work
  • You need to generate the VCL from the Magento backend

@ThijsFeryn
Copy link

@codedge

  • I'm not sure, but if it compiles it should work
  • You need to generate the VCL from the Magento backend

@codedge @peterjaap Compatibility shouldn't be a problem at all.

The Varnish version doesn't really matter that much difference, it's the VCL version you're using that is important. And vcl 4.1; is the right version marker to stay compatible.

@Melleschepers
Copy link

Can we add the "gbraid" parameter? :)
Source: https://support.google.com/analytics/answer/11367152?hl=en

@peterjaap
Copy link
Author

@peterjaap
Copy link
Author

@peterjaap
Copy link
Author

Notable differences

  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. 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