configuration-templates – Diff between revs 2 and 16

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 2 Rev 16
1 vcl 4.0; 1 vcl 4.0;
-   2 ###########################################################################
2 # Optimized Varnish VCL for load balancing and caching. 3 ## Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 ##
3 # original: https://github.com/mattiasgeniar/varnish-4.0-configuration-templates/blob/master/default.vcl 4 ## Please see: http://www.gnu.org/licenses/gpl.html for legal details, ##
-   5 ## rights of fair usage, the disclaimer and warranty conditions. ##
-   6 ###########################################################################
4 # modified: Wizardry and Steamworks (http://grimore.org) 7 ## Derived from the original by Mattias Geniar as a starting template. ##
-   8 ###########################################################################
5   9  
6 import std; 10 import std;
7 import directors; 11 import directors;
8   12  
9 backend server1 { # Define one backend 13 backend server1 { # Define one backend
10 .host = "192.168.0.10"; # IP or Hostname of backend 14 .host = "192.168.0.10"; # IP or Hostname of backend
11 .port = "80"; # Port Apache or whatever is listening 15 .port = "80"; # Port Apache or whatever is listening
12 .max_connections = 300; # Number of allowed connections 16 .max_connections = 300; # Number of allowed connections
13   17  
14 .probe = { 18 .probe = {
15 #.url = "/"; # short easy way (GET /) 19 #.url = "/"; # short easy way (GET /)
16 # We prefer to only do a HEAD / 20 # We prefer to only do a HEAD /
17 .request = 21 .request =
18 "HEAD / HTTP/1.1" 22 "HEAD / HTTP/1.1"
19 "Host: grimore.org" 23 "Host: grimore.org"
20 "Connection: close" 24 "Connection: close"
21 "User-Agent: Varnish Health Probe"; 25 "User-Agent: Varnish Health Probe";
22   26  
23 .interval = 5s; # check the health of each backend every 5 seconds 27 .interval = 5s; # check the health of each backend every 5 seconds
24 .timeout = 1s; # timing out after 1 second. 28 .timeout = 1s; # timing out after 1 second.
25 .window = 5; # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick 29 .window = 5; # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick
26 .threshold = 3; 30 .threshold = 3;
27 } 31 }
28   32  
29 .first_byte_timeout = 300s; # How long to wait before we receive a first byte from our backend? 33 .first_byte_timeout = 300s; # How long to wait before we receive a first byte from our backend?
30 .connect_timeout = 5s; # How long to wait for a backend connection? 34 .connect_timeout = 5s; # How long to wait for a backend connection?
31 .between_bytes_timeout = 2s; # How long to wait between bytes received from our backend? 35 .between_bytes_timeout = 2s; # How long to wait between bytes received from our backend?
32 } 36 }
33   37  
34 acl purge { 38 acl purge {
35 # ACL we'll use later to allow purges 39 # ACL we'll use later to allow purges
36 "localhost"; 40 "localhost";
37 "127.0.0.1"; 41 "127.0.0.1";
38 /* "::1"; */ 42 /* "::1"; */
39 } 43 }
40   44  
41 /* 45 /*
42 acl editors { 46 acl editors {
43 # ACL to honor the "Cache-Control: no-cache" header to force a refresh but only from selected IPs 47 # ACL to honor the "Cache-Control: no-cache" header to force a refresh but only from selected IPs
44 "localhost"; 48 "localhost";
45 "127.0.0.1"; 49 "127.0.0.1";
46 "::1"; 50 "::1";
47 } 51 }
48 */ 52 */
49   53  
50 sub vcl_init { 54 sub vcl_init {
51 # Called when VCL is loaded, before any requests pass through it. 55 # Called when VCL is loaded, before any requests pass through it.
52 # Typically used to initialize VMODs. 56 # Typically used to initialize VMODs.
53   57  
54 new vdir = directors.round_robin(); 58 new vdir = directors.round_robin();
55 vdir.add_backend(server1); 59 vdir.add_backend(server1);
56 # vdir.add_backend(server...); 60 # vdir.add_backend(server...);
57 # vdir.add_backend(servern); 61 # vdir.add_backend(servern);
58 } 62 }
59   63  
60 sub vcl_recv { 64 sub vcl_recv {
61 # Called at the beginning of a request, after the complete request has been received and parsed. 65 # Called at the beginning of a request, after the complete request has been received and parsed.
62 # Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, 66 # Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable,
63 # which backend to use. 67 # which backend to use.
64 # also used to modify the request 68 # also used to modify the request
65   69  
66 set req.backend_hint = vdir.backend(); # send all traffic to the vdir director 70 set req.backend_hint = vdir.backend(); # send all traffic to the vdir director
67   71  
68 # When CloudFlare is in front of varnish, send the real IP address through X-Forwarded-For 72 # When CloudFlare is in front of varnish, send the real IP address through X-Forwarded-For
69 # otherwise if CloudFlare is not involved, set the X-Forwarded-For to the client IP address. 73 # otherwise if CloudFlare is not involved, set the X-Forwarded-For to the client IP address.
70 unset req.http.X-Forwarded-For; 74 unset req.http.X-Forwarded-For;
71 if (req.http.cf-connecting-ip) { 75 if (req.http.cf-connecting-ip) {
72 set req.http.X-Forwarded-For = req.http.cf-connecting-ip; 76 set req.http.X-Forwarded-For = req.http.cf-connecting-ip;
73 } else { 77 } else {
74 set req.http.X-Forwarded-For = client.ip; 78 set req.http.X-Forwarded-For = client.ip;
75 } 79 }
76   80  
77 # Normalize the header, remove the port (in case you're testing this on various TCP ports) 81 # Normalize the header, remove the port (in case you're testing this on various TCP ports)
78 set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); 82 set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
79   83  
80 # Remove the proxy header (see https://httpoxy.org/#mitigate-varnish) 84 # Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
81 unset req.http.proxy; 85 unset req.http.proxy;
82   86  
83 # Normalize the query arguments 87 # Normalize the query arguments
84 set req.url = std.querysort(req.url); 88 set req.url = std.querysort(req.url);
85   89  
86 # Allow purging 90 # Allow purging
87 if (req.method == "PURGE") { 91 if (req.method == "PURGE") {
88 if (!client.ip ~ purge) { # purge is the ACL defined at the begining 92 if (!client.ip ~ purge) { # purge is the ACL defined at the begining
89 # Not from an allowed IP? Then die with an error. 93 # Not from an allowed IP? Then die with an error.
90 return (synth(405, "This IP is not allowed to send PURGE requests.")); 94 return (synth(405, "This IP is not allowed to send PURGE requests."));
91 } 95 }
92 # If you got this stage (and didn't error out above), purge the cached result 96 # If you got this stage (and didn't error out above), purge the cached result
93 return (purge); 97 return (purge);
94 } 98 }
95   99  
96 # Only deal with "normal" types 100 # Only deal with "normal" types
97 if (req.method != "GET" && 101 if (req.method != "GET" &&
98 req.method != "HEAD" && 102 req.method != "HEAD" &&
99 req.method != "PUT" && 103 req.method != "PUT" &&
100 req.method != "POST" && 104 req.method != "POST" &&
101 req.method != "TRACE" && 105 req.method != "TRACE" &&
102 req.method != "OPTIONS" && 106 req.method != "OPTIONS" &&
103 req.method != "PATCH" && 107 req.method != "PATCH" &&
104 req.method != "DELETE") { 108 req.method != "DELETE" &&
-   109 req.method != "PROPFIND" &&
-   110 req.method != "REPORT") {
105 /* Non-RFC2616 or CONNECT which is weird. */ 111 /* Non-RFC2616 or CONNECT which is weird. */
106 return (pipe); 112 return (pipe);
107 } 113 }
108   114  
109 # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html) 115 # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
110 if (req.http.Upgrade ~ "(?i)websocket") { 116 if (req.http.Upgrade ~ "(?i)websocket") {
111 return (pipe); 117 return (pipe);
112 } 118 }
113   119  
114 # Only cache GET or HEAD requests. This makes sure the POST requests are always passed. 120 # Only cache GET or HEAD requests. This makes sure the POST requests are always passed.
115 if (req.method != "GET" && req.method != "HEAD") { 121 if (req.method != "GET" && req.method != "HEAD") {
116 return (pass); 122 return (pass);
117 } 123 }
118   124  
119 # Some generic URL manipulation, useful for all templates that follow 125 # Some generic URL manipulation, useful for all templates that follow
120 # First remove the Google Analytics added parameters, useless for our backend 126 # First remove the Google Analytics added parameters, useless for our backend
121 if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") { 127 if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
122 set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", ""); 128 set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
123 set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?"); 129 set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
124 set req.url = regsub(req.url, "\?&", "?"); 130 set req.url = regsub(req.url, "\?&", "?");
125 set req.url = regsub(req.url, "\?$", ""); 131 set req.url = regsub(req.url, "\?$", "");
126 } 132 }
127   133  
128 # Strip hash, server doesn't need it. 134 # Strip hash, server doesn't need it.
129 if (req.url ~ "\#") { 135 if (req.url ~ "\#") {
130 set req.url = regsub(req.url, "\#.*$", ""); 136 set req.url = regsub(req.url, "\#.*$", "");
131 } 137 }
132   138  
133 # Strip a trailing ? if it exists 139 # Strip a trailing ? if it exists
134 if (req.url ~ "\?$") { 140 if (req.url ~ "\?$") {
135 set req.url = regsub(req.url, "\?$", ""); 141 set req.url = regsub(req.url, "\?$", "");
136 } 142 }
137   143  
138 # Some generic cookie manipulation, useful for all templates that follow 144 # Some generic cookie manipulation, useful for all templates that follow
139 # Remove the "has_js" cookie 145 # Remove the "has_js" cookie
140 set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", ""); 146 set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
-   147  
-   148 # Remove any CloudFlare cookies
-   149 set req.http.Cookie = regsuball(req.http.Cookie, "cf_.=[^;]+(; )?", "");
141   150  
142 # Remove any Google Analytics based cookies 151 # Remove any Google Analytics based cookies
143 set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", ""); 152 set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");
144 set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", ""); 153 set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", "");
145 set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?", ""); 154 set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?", "");
146 set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", ""); 155 set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", "");
147 set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", ""); 156 set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
148 set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", ""); 157 set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");
149   158  
150 # Remove DoubleClick offensive cookies 159 # Remove DoubleClick offensive cookies
151 set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", ""); 160 set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
152   161  
153 # Remove the Quant Capital cookies (added by some plugin, all __qca) 162 # Remove the Quant Capital cookies (added by some plugin, all __qca)
154 set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", ""); 163 set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
155   164  
156 # Remove the AddThis cookies 165 # Remove the AddThis cookies
157 set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", ""); 166 set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
158   167  
159 # Remove a ";" prefix in the cookie if present 168 # Remove a ";" prefix in the cookie if present
160 set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", ""); 169 set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
161   170  
162 # Are there cookies left with only spaces or that are empty? 171 # Are there cookies left with only spaces or that are empty?
163 if (req.http.cookie ~ "^\s*$") { 172 if (req.http.cookie ~ "^\s*$") {
164 unset req.http.cookie; 173 unset req.http.cookie;
165 } 174 }
166   175  
167 if (req.http.Cache-Control ~ "(?i)no-cache") { 176 if (req.http.Cache-Control ~ "(?i)no-cache") {
168 #if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ editors) { # create the acl editors if you want to restrict the Ctrl-F5 177 #if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ editors) { # create the acl editors if you want to restrict the Ctrl-F5
169 # http://varnish.projects.linpro.no/wiki/VCLExampleEnableForceRefresh 178 # http://varnish.projects.linpro.no/wiki/VCLExampleEnableForceRefresh
170 # Ignore requests via proxy caches and badly behaved crawlers 179 # Ignore requests via proxy caches and badly behaved crawlers
171 # like msnbot that send no-cache with every request. 180 # like msnbot that send no-cache with every request.
172 if (! (req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) { 181 if (! (req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) {
173 #set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache 182 #set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache
174 return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops 183 return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops
175 } 184 }
176 } 185 }
177   186  
178 # Large static files are delivered directly to the end-user without 187 # Large static files are delivered directly to the end-user without
179 # waiting for Varnish to fully read the file first. 188 # waiting for Varnish to fully read the file first.
180 # Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response() 189 # Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response()
181 if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") { 190 if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
182 unset req.http.Cookie; 191 unset req.http.Cookie;
183 return (hash); 192 return (hash);
184 } 193 }
185   194  
186 # Remove all cookies for static files 195 # Remove all cookies for static files
187 # A valid discussion could be held on this line: do you really need to cache static files that don't cause load? Only if you have memory left. 196 # A valid discussion could be held on this line: do you really need to cache static files that don't cause load? Only if you have memory left.
188 # Sure, there's disk I/O, but chances are your OS will already have these files in their buffers (thus memory). 197 # Sure, there's disk I/O, but chances are your OS will already have these files in their buffers (thus memory).
189 # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/ 198 # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
190 # if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { 199 if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
191 # unset req.http.Cookie; 200 unset req.http.Cookie;
192 # return (hash); 201 return (hash);
193 # } 202 }
194   203  
195 # Send Surrogate-Capability headers to announce ESI support to backend 204 # Send Surrogate-Capability headers to announce ESI support to backend
196 set req.http.Surrogate-Capability = "key=ESI/1.0"; 205 set req.http.Surrogate-Capability = "key=ESI/1.0";
197   206  
198 if (req.http.Authorization) { 207 if (req.http.Authorization) {
199 # Not cacheable by default 208 # Not cacheable by default
200 return (pass); 209 return (pass);
201 } 210 }
202   211  
203 return (hash); 212 return (hash);
204 } 213 }
205   214  
206   215  
207 sub vcl_pipe { 216 sub vcl_pipe {
208 # Called upon entering pipe mode. 217 # Called upon entering pipe mode.
209 # In this mode, the request is passed on to the backend, and any further data from both the client 218 # In this mode, the request is passed on to the backend, and any further data from both the client
210 # and backend is passed on unaltered until either end closes the connection. Basically, Varnish will 219 # and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
211 # degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode, 220 # degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
212 # no other VCL subroutine will ever get called after vcl_pipe. 221 # no other VCL subroutine will ever get called after vcl_pipe.
213   222  
214 # Note that only the first request to the backend will have 223 # Note that only the first request to the backend will have
215 # X-Forwarded-For set. If you use X-Forwarded-For and want to 224 # X-Forwarded-For set. If you use X-Forwarded-For and want to
216 # have it set for all requests, make sure to have: 225 # have it set for all requests, make sure to have:
217 # set bereq.http.connection = "close"; 226 # set bereq.http.connection = "close";
218 # here. It is not set by default as it might break some broken web 227 # here. It is not set by default as it might break some broken web
219 # applications, like IIS with NTLM authentication. 228 # applications, like IIS with NTLM authentication.
220   229  
221 # set bereq.http.Connection = "Close"; 230 # set bereq.http.Connection = "Close";
222   231  
223 # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html) 232 # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
224 if (req.http.upgrade) { 233 if (req.http.upgrade) {
225 set bereq.http.upgrade = req.http.upgrade; 234 set bereq.http.upgrade = req.http.upgrade;
226 } 235 }
227   236  
228 return (pipe); 237 return (pipe);
229 } 238 }
230   239  
231 sub vcl_pass { 240 sub vcl_pass {
232 # Called upon entering pass mode. In this mode, the request is passed on to the backend, and the 241 # Called upon entering pass mode. In this mode, the request is passed on to the backend, and the
233 # backend's response is passed on to the client, but is not entered into the cache. Subsequent 242 # backend's response is passed on to the client, but is not entered into the cache. Subsequent
234 # requests submitted over the same client connection are handled normally. 243 # requests submitted over the same client connection are handled normally.
235   244  
236 # return (pass); 245 # return (pass);
237 } 246 }
238   247  
239 # The data on which the hashing will take place 248 # The data on which the hashing will take place
240 sub vcl_hash { 249 sub vcl_hash {
241 # Called after vcl_recv to create a hash value for the request. This is used as a key 250 # Called after vcl_recv to create a hash value for the request. This is used as a key
242 # to look up the object in Varnish. 251 # to look up the object in Varnish.
243   252  
244 hash_data(req.url); 253 hash_data(req.url);
245   254  
246 if (req.http.host) { 255 if (req.http.host) {
247 hash_data(req.http.host); 256 hash_data(req.http.host);
248 } else { 257 } else {
249 hash_data(server.ip); 258 hash_data(server.ip);
250 } 259 }
251   260  
252 # hash cookies for requests that have them 261 # hash cookies for requests that have them
253 if (req.http.Cookie) { 262 if (req.http.Cookie) {
254 hash_data(req.http.Cookie); 263 hash_data(req.http.Cookie);
255 } 264 }
256 } 265 }
257   266  
258 sub vcl_hit { 267 sub vcl_hit {
259 # Called when a cache lookup is successful. 268 # Called when a cache lookup is successful.
260   269  
261 if (obj.ttl >= 0s) { 270 if (obj.ttl >= 0s) {
262 # A pure unadultered hit, deliver it 271 # A pure unadultered hit, deliver it
263 return (deliver); 272 return (deliver);
264 } 273 }
265   274  
266 # https://www.varnish-cache.org/docs/trunk/users-guide/vcl-grace.html 275 # https://www.varnish-cache.org/docs/trunk/users-guide/vcl-grace.html
267 # When several clients are requesting the same page Varnish will send one request to the backend and place the others on hold while fetching one copy from the backend. In some products this is called request coalescing and Varnish does this automatically. 276 # When several clients are requesting the same page Varnish will send one request to the backend and place the others on hold while fetching one copy from the backend. In some products this is called request coalescing and Varnish does this automatically.
268 # If you are serving thousands of hits per second the queue of waiting requests can get huge. There are two potential problems - one is a thundering herd problem - suddenly releasing a thousand threads to serve content might send the load sky high. Secondly - nobody likes to wait. To deal with this we can instruct Varnish to keep the objects in cache beyond their TTL and to serve the waiting requests somewhat stale content. 277 # If you are serving thousands of hits per second the queue of waiting requests can get huge. There are two potential problems - one is a thundering herd problem - suddenly releasing a thousand threads to serve content might send the load sky high. Secondly - nobody likes to wait. To deal with this we can instruct Varnish to keep the objects in cache beyond their TTL and to serve the waiting requests somewhat stale content.
269   -  
270 # if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) { 278 # if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
271 # return (deliver); 279 # return (deliver);
272 # } else { 280 # } else {
273 # return (fetch); 281 # return (fetch);
274 # } 282 # }
275   283  
276 # We have no fresh fish. Lets look at the stale ones. 284 # We have no fresh fish. Lets look at the stale ones.
277 if (std.healthy(req.backend_hint)) { 285 if (std.healthy(req.backend_hint)) {
278 # Backend is healthy. Limit age to 10s. 286 # Backend is healthy. Limit age to 10s.
279 if (obj.ttl + 10s > 0s) { 287 if (obj.ttl + 10s > 0s) {
280 #set req.http.grace = "normal(limited)"; 288 #set req.http.grace = "normal(limited)";
281 return (deliver); 289 return (deliver);
282 } else { 290 } else {
283 # No candidate for grace. Fetch a fresh object. 291 # No candidate for grace. Fetch a fresh object.
284 return(fetch); 292 return(fetch);
285 } 293 }
286 } else { 294 } else {
287 # backend is sick - use full grace 295 # backend is sick - use full grace
288 if (obj.ttl + obj.grace > 0s) { 296 if (obj.ttl + obj.grace > 0s) {
289 #set req.http.grace = "full"; 297 #set req.http.grace = "full";
290 return (deliver); 298 return (deliver);
291 } else { 299 } else {
292 # no graced object. 300 # no graced object.
293 return (fetch); 301 return (fetch);
294 } 302 }
295 } 303 }
296   304  
297 # fetch & deliver once we get the result 305 # fetch & deliver once we get the result
298 return (fetch); # Dead code, keep as a safeguard 306 return (fetch); # Dead code, keep as a safeguard
299 } 307 }
300   308  
301 sub vcl_miss { 309 sub vcl_miss {
302 # Called after a cache lookup if the requested document was not found in the cache. Its purpose 310 # Called after a cache lookup if the requested document was not found in the cache. Its purpose
303 # is to decide whether or not to attempt to retrieve the document from the backend, and which 311 # is to decide whether or not to attempt to retrieve the document from the backend, and which
304 # backend to use. 312 # backend to use.
305   313  
306 return (fetch); 314 return (fetch);
307 } 315 }
308   316  
309 # Handle the HTTP request coming from our backend 317 # Handle the HTTP request coming from our backend
310 sub vcl_backend_response { 318 sub vcl_backend_response {
311 # Called after the response headers has been successfully retrieved from the backend. 319 # Called after the response headers has been successfully retrieved from the backend.
312   320  
313 # Pause ESI request and remove Surrogate-Control header 321 # Pause ESI request and remove Surrogate-Control header
314 if (beresp.http.Surrogate-Control ~ "ESI/1.0") { 322 if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
315 unset beresp.http.Surrogate-Control; 323 unset beresp.http.Surrogate-Control;
316 set beresp.do_esi = true; 324 set beresp.do_esi = true;
-   325 set beresp.ttl = 24h; # Set 24h ESI
317 } 326 }
-   327  
-   328 ### Set content expiration.
-   329 ## You may want to disable any expiration on the backend (ie: for Apache, disable mod_expires).
-   330 # 1 Year
-   331 if(beresp.http.content-type ~ "(?i)(application/(javascript|x\-javascript))|(text/(javascript|css))|(application/(atom\+xml|rdf\+xml|rss\+xml))") {
-   332 set beresp.http.Expires = "" + (now + 1y);
-   333 }
-   334 # 1 Month
-   335 if(beresp.http.content-type ~ "(?i)(application/(vnd\.ms\-fontobject|font\-woff|x\-font\-(ttf|woff)))|(audio/ogg)|(font/(eot|opentype|woff))|(image/(bmp|gif|jp2|jpeg|png|svg\+xmlwebp))|(video/(mp4|ogg|webm))") {
-   336 set beresp.http.Expires = "" + (now + 24w);
-   337 }
-   338 # 1 Week
-   339 if(beresp.http.content-type ~ "(?i)(image/(vnd\.microsoft\.icon|x\-icon))|(application/manifest\+json)|(text/x\-cross\-domain\-policy)") {
-   340 set beresp.http.Expires = "" + (now + 1w);
-   341 }
-   342 # Immediately
-   343 # Not exactly "immediately" since we do not want to have to recache on fast reloads - ideally, set this to average page log time.
-   344 if(beresp.http.content-type ~ "(?i)(application/(json|ld\+json|schema\+json|vnd\.geo\+jsonxml|x\-web\-app\-manifest\+json))|(text/(xml|cache\-manifest|html))") {
-   345 set beresp.http.Expires = "" + (now + 3s);
-   346 }
-   347  
-   348 ### GZip content if not already compressed.
318   349 ## You may want to disable any compression on the backend (ie: for Apache, disable mod_deflate).
-   350 if(beresp.http.content-type ~ "(?i)(application/(atom\+xml|javascript|json|ld\+json|manifest\+json|rdf\+xml|rss\+xml|schema\+json|vnd\.geo\+json|vnd\.ms\-fontobject|x\-(font\-ttf|javascript|web\-app\-manifest\+json)|xhtml\+xml|xml)|font/(eot|opentype))|(image/(bmp|svg\+xml|vnd\.microsoft\.icon|x\-icon))|(text/(cache\-manifest|css|html|javascript|plain|vcard|vnd\.rim\.location\.xloc|vcalendar|vtt|x\-component|x\-cross\-domain\-policy|xml))") {
-   351 # Compress object for sending.
-   352 set beresp.do_gzip = true;
-   353 }
-   354  
319 # Enable cache for all static files 355 ### Enable cache for all static files
320 # The same argument as the static caches from above: monitor your cache size, if you get data nuked out of it, consider giving up the static file cache. 356 ## The same argument as the static caches from above: monitor your cache size, if you get data nuked out of it, consider giving up the static file cache.
321 # Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/ 357 ## Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
322 if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { 358 if(beresp.http.content-type ~ "(?i)(application/(java\-vm|javascript|json|msword|pdf|postscript|rtf|vnd\.ms\-(excel|fontobject|powerpoint)|vnd\.oasis\.opendocument\.text|vnd\.openxmlformats\-officedocument\.(presentationml\.presentation|spreadsheetml\.sheet|wordprocessingml\.document)|x\-(7z\-compressed|bzip2|gzip|rar\-compressed|shockwave\-flash|tar)|x\-font\-(bdf|ghostscript|linux\-psf|otf|pcf|snf|ttf|type1|woff)|xz|xml|zip))|(audio/((mpeg|ogg)|(x\-(flac|matroska|ms\-wma|wav))))|(image/((bmp|gif|jp2|jpeg|png|svg\+xml|vnd\.wap\.wbmp|webp|x\-(icon|pict))))|(text/((css|csv|javascript|plain)))|(video/((mp4|quicktime|webm|x\-(flv|matroska|ms\-wmv|msvideo))))") {
323 unset beresp.http.set-cookie; 359 unset beresp.http.set-cookie;
324 } 360 }
325   361  
326 # Large static files are delivered directly to the end-user without 362 # Large static files are delivered directly to the end-user without
327 # waiting for Varnish to fully read the file first. 363 # waiting for Varnish to fully read the file first.
328 # Varnish 4 fully supports Streaming, so use streaming here to avoid locking. 364 # Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
329 if (bereq.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") { 365 if (bereq.url ~ "^[^?]*\.(7z|ace|avi|bin|bz2|flac|flv|gz|iso|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|wma|wmv|xz|zip)(\?.*)?$") {
330 unset beresp.http.set-cookie; 366 unset beresp.http.set-cookie;
331 set beresp.do_stream = true; # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects 367 set beresp.do_stream = true; # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
332 } 368 }
333   369  
334 # Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along. 370 # Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along.
335 # This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box. 371 # This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box.
336 # A redirect can then often redirect the end-user to a URL on :8080, where it should be :80. 372 # A redirect can then often redirect the end-user to a URL on :8080, where it should be :80.
337 # This may need finetuning on your setup. 373 # This may need finetuning on your setup.
338 # 374 #
339 # To prevent accidental replace, we only filter the 301/302 redirects for now. 375 # To prevent accidental replace, we only filter the 301/302 redirects for now.
340 if (beresp.status == 301 || beresp.status == 302) { 376 if (beresp.status == 301 || beresp.status == 302) {
341 set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", ""); 377 set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", "");
342 } 378 }
343   379  
344 # Set 2min cache if unset for static files 380 # Set 2min cache if unset for static files
345 if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") { 381 if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
346 set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend 382 set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
347 set beresp.uncacheable = true; 383 set beresp.uncacheable = true;
348 return (deliver); 384 return (deliver);
349 } 385 }
350   386  
351 # Don't cache 50x responses 387 # Don't cache 50x responses
352 if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) { 388 if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
353 return (abandon); 389 return (abandon);
354 } 390 }
355   391  
356 # Allow stale content, in case the backend goes down. 392 # Allow stale content, in case the backend goes down.
357 # make Varnish keep all objects for 6 hours beyond their TTL 393 # make Varnish keep all objects for 6 hours beyond their TTL
358 set beresp.grace = 6h; 394 set beresp.grace = 6h;
359   395  
360 return (deliver); 396 return (deliver);
361 } 397 }
362   398  
363 # The routine when we deliver the HTTP request to the user 399 # The routine when we deliver the HTTP request to the user
364 # Last chance to modify headers that are sent to the client 400 # Last chance to modify headers that are sent to the client
365 sub vcl_deliver { 401 sub vcl_deliver {
366 # Called before a cached object is delivered to the client. 402 # Called before a cached object is delivered to the client.
367   403  
368 if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed 404 if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
369 set resp.http.X-Cache = "HIT"; 405 set resp.http.X-Cache = "HIT";
370 } else { 406 } else {
371 set resp.http.X-Cache = "MISS"; 407 set resp.http.X-Cache = "MISS";
372 } 408 }
373   409  
374 # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object 410 # Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
375 # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details. 411 # and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
376 # So take hits with a grain of salt 412 # So take hits with a grain of salt
377 set resp.http.X-Cache-Hits = obj.hits; 413 set resp.http.X-Cache-Hits = obj.hits;
378   414  
379 # Remove some headers: PHP version 415 # Remove some headers: PHP version
380 unset resp.http.X-Powered-By; 416 unset resp.http.X-Powered-By;
381   417  
382 # Remove some headers: Apache version & OS 418 # Remove some headers: Apache version & OS
383 unset resp.http.Server; 419 unset resp.http.Server;
384 unset resp.http.X-Drupal-Cache; 420 unset resp.http.X-Drupal-Cache;
385 unset resp.http.X-Varnish; 421 unset resp.http.X-Varnish;
386 unset resp.http.Via; 422 unset resp.http.Via;
387 unset resp.http.Link; 423 unset resp.http.Link;
388 unset resp.http.X-Generator; 424 unset resp.http.X-Generator;
389   425  
390 return (deliver); 426 return (deliver);
391 } 427 }
392   428  
393 sub vcl_purge { 429 sub vcl_purge {
394 # Only handle actual PURGE HTTP methods, everything else is discarded 430 # Only handle actual PURGE HTTP methods, everything else is discarded
395 if (req.method != "PURGE") { 431 if (req.method != "PURGE") {
396 # restart request 432 # restart request
397 set req.http.X-Purge = "Yes"; 433 set req.http.X-Purge = "Yes";
398 return(restart); 434 return(restart);
399 } 435 }
400 } 436 }
401   437  
402 sub vcl_synth { 438 sub vcl_synth {
403 if (resp.status == 720) { 439 if (resp.status == 720) {
404 # We use this special error status 720 to force redirects with 301 (permanent) redirects 440 # We use this special error status 720 to force redirects with 301 (permanent) redirects
405 # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html")); 441 # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
406 set resp.http.Location = resp.reason; 442 set resp.http.Location = resp.reason;
407 set resp.status = 301; 443 set resp.status = 301;
408 return (deliver); 444 return (deliver);
409 } elseif (resp.status == 721) { 445 } elseif (resp.status == 721) {
410 # And we use error status 721 to force redirects with a 302 (temporary) redirect 446 # And we use error status 721 to force redirects with a 302 (temporary) redirect
411 # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html")); 447 # To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
412 set resp.http.Location = resp.reason; 448 set resp.http.Location = resp.reason;
413 set resp.status = 302; 449 set resp.status = 302;
414 return (deliver); 450 return (deliver);
415 } 451 }
416   452  
417 return (deliver); 453 return (deliver);
418 } 454 }
419   455  
420   456  
421 sub vcl_fini { 457 sub vcl_fini {
422 # Called when VCL is discarded only after all requests have exited the VCL. 458 # Called when VCL is discarded only after all requests have exited the VCL.
423 # Typically used to clean up VMODs. 459 # Typically used to clean up VMODs.
424   460  
425 return (ok); 461 return (ok);
426 } 462 }
427   463  
428 sub vcl_backend_error { 464 sub vcl_backend_error {
429 # Called when the backend cannot be reached. 465 # Called when the backend cannot be reached.
430 # Display an HTML file located at /etc/varnish/500.html 466 # Display an HTML file located at /etc/varnish/500.html
431 set beresp.http.Content-Type = "text/html; charset=utf-8"; 467 set beresp.http.Content-Type = "text/html; charset=utf-8";
432 synthetic(std.fileread("/etc/varnish/500.html")); 468 synthetic(std.fileread("/etc/varnish/500.html"));
433 return (deliver); 469 return (deliver);
434 } 470 }
435   471