Assuming no change of URL or internal cache key, for a full flush the simplest approach would be to restart Varnish, as it maintains its cache in memory.
If doing a quick restart is not acceptable, the BAN suggested by Rastislav is a great approach. It will need to stay active as long your longest TTL, so if you frequently need a full flush, the BAN list will be pretty much permanent as the ban lurker (which sweeps for BANs which no longer are relevant) may always think that your BAN is useful
So in your case, your VCL would be:
# Highly recommend that you set up an ACL for IPs that are allowed
# to make the BAN call
acl acl_ban {
"localhost";
"1.2.3.4"/32;
}
sub vcl_recv {
if (client.ip ~ acl_ban && req.method == "BAN") {
ban("req.http.host == " + req.http.host);
# Throw a synthetic page so the request won't go to the backend.
return(synth(200, "Ban added"));
}
}
However as noted by Carlos in the comments, this will actually create a lazy invalidation (and so only removed at request time). If you want to have the objects actually get purged by the background ban lurker every so often, you can instead do:
# Highly recommend that you set up an ACL for IPs that are allowed
# to make the BAN call
acl acl_ban {
"localhost";
"1.2.3.4"/32;
}
sub vcl_recv {
if (client.ip ~ acl_ban && req.method == "BAN") {
# see below for why this is obj. rather than req.
ban("obj.http.host == " + req.http.host);
# Throw a synthetic page so the request won't go to the backend.
return(synth(200, "Ban added"));
}
}
sub vcl_backend_response {
# add any portions of the request that would want to be able
# to BAN on. Doing it in vcl_backend_response means that it
# will make it into the storage object
set beresp.http.host = bereq.http.host;
}
sub vcl_deliver {
# Unless you want the header to actually show in the response,
# clear them here. So they will be part of the stored object
# but otherwise invisible
unset beresp.http.host;
}
Then to do the flush:
curl -X BAN http://example.com;