Different Varnish VCL based on URL - varnish

I have Magento installation in a subfolder and a WordPress site. How can I use the same Varnish installation for two different CMS?
I have prepared the following default.vcl file code example, but not sure if I am moving in the right direction. Thanks
vcl 4.0;
if (req.url ~ "^/path/to/magento/") {
include "magento.vcl";
} elseif (req.url ~ "^/path/to/wordpress/") {
include "wordpress.vcl";
}
P.S. My Varnish version is 4.0

Before I continue, please be ware of the fact that Varnish 4 is end-of-life. Any bug or error you encounter will not be fixed and can result in unexpected behavior. The best way forward is by upgrading to Varnish 6.
That being said, you are definitely moving in the right direction. But please make sure the included logic is put inside a subroutine.
Your example code will typically live inside sub vcl_recv {}. If you have logic that belongs in other subroutines (like sub vcl_backend_response {} for example), please make sure you include that logic as well.

Related

Varnish clear cached items based on status code

We're caching 404 for images as sometimes our app would be released ahead of the actual images and would like to be able to clear them based on status code rather than ALL the images or specific images one by one.
However I am new to Varnish an unsure whether that is doable as I couldn't find any specific documentation on clearing based on status code.
you can either PURGE and image or BAN it.
Purging: it deletes a specific object from cache and to do so you will need to know the host and the URL of the specific object you want to purge.
Banning: to ban you can use regex and for your use case something among those lines should work.
In vcl_recv:
if (req.method == "BAN") {
ban("req.status == "404");
}
It seems that purge method is just an overlay on vcl's ban.
Using varnishadmn to test I've found to purge specific status, code only obj.status is accepted.
varnishadm ban obj.status == 404
verify with:
varnishadm ban.list

How to display the age of an nginx cached file in headers

I've set up a caching server for a site through nginx 1.6.3 on CentOS 7, and it's configured to add http headers to served files to show if said files came from the caching server (HIT, MISS, or BYPASS) like so:
add_header X-Cached $upstream_cache_status;
However, i'd like to see if there's a way to add a header to display the age of the cached file, as my solution has proxy_cache_valid 200 60m; set, and i'd like to check that it's respecting that setting.
So what i'm looking for would be something like:
add_header Cache-Age $upstream_cache_age;
I'm unable to find anything of the sort though, can you help?
Thanks
The nginx documentation is quite exhaustive — there's no variable with the direct relative age of the cached file.
The best way would be to use the $upstream_http_ variable class to get the absolute age of the resource by picking up its Date header through $upsteam_http_date.
add_header X-Cache-Date $upstream_http_date;
For the semantic meaning of the Date header field in HTTP/1.1, refer to rfc7231#section-7.1.1.2, which describes it as the time of the HTTP response generation, so, basically, this should accomplish exactly what you want (especially if the backend runs with the same timecounter).
I spent some time attempting to solve this with the Nginx Perl module, which does not seem to have access to $upstream_http_NAME headers that would allow you to successfully calculate the current time from a timestamp header that your proxied application created during render time.
Alternatively, you could use a different caching layer architecture like Varnish Cache, which does indeed provide the Age HTTP response header:
http://book.varnish-software.com/3.0/HTTP.html#age
I made a solution that works for this, with the Lua module, in this question: Nginx: Add “Age” header, with Lua. Is this a good solution?
I'm going to post here the code, for any suggestion it would be better to discuss it in the other link, where I explain it in more detail.
map $upstream_http_Date $mapdate {
default $upstream_http_Date;
'' 'Sat, 21 Dec 2019 00:00:00 GMT';
}
Inside location:
header_filter_by_lua_block {
ngx.header["Age"] = ngx.time() - ngx.parse_http_time(ngx.var.mapdate);
}

symfony2 get firewall name on login page

I'd want to use a login page to access different firewalls, so I need to get information about the firewall I'm logging in.
In my controller I'd use
$this->container->get('security.context')->getToken()->getProviderKey()
but as an anonymous user I don't have access to getProviderKey method.
I could also parse
_security.xxx.target_path
to get xxx firewall but I'm looking for a more general solution if it exists at all.
Any idea?
As of symfony 3.2, you can now get the current firewall configuration using the following:
public function indexAction(Request $request)
{
$firewall = $this->container
->get('security.firewall.map')
->getFirewallConfig($request)
->getName();
}
Ref: http://symfony.com/blog/new-in-symfony-3-2-firewall-config-class-and-profiler
For Symfony 3.4 I wrote this to avoid referencing the non-public "security.firewall.map" service:
$firewallName = null;
if (($firewallContext = trim($request->attributes->get("_firewall_context", null))) && (false !== ($firewallContextNameSplit = strrpos($firewallContext, ".")))) {
$firewallName = substr($firewallContext, $firewallContextNameSplit + 1);
}
(Referencing "security.firewall.map" on 3.4 will throw an exception.)
Edit: This will not work in a custom exception controller function.
I was doing a little research on this myself recently so that I could send this information in an XACML request as part of the environment.
As far as I can tell from GitHub issues like this one:
https://github.com/symfony/symfony/issues/14435
There is currently no way to reliably get the information out of Symfony except the dirty compiler pass hack suggested on the linked issue. It does appear from the conversation on these issues, they are working on making this available, however, the status is still open, so we will have to be patient and wait for it to be provided.
#Adambean's answer is pretty elegant, but I'd write it as a one-liner:
$firewallName = array_slice(explode('.', trim($request->attributes->get('_firewall_context'))), -1)[0];
The difference is that $firewallName will always be a string (which may be empty).
Also, please note that this answer (like #Adambean's) doesn't work for a firewall with a dot in its name.

Infinite redirection loop in varnish cache

we recently have put Varnish in front of our Drupal because the server was suffering heavy load and we are very pleased in general.
The only problem remaining is that we sometimes have an infinite redirection loop in the cached data. We have found this through our HTTP-Monitoring. We check the front page every minute. The page in the cache sometimes contains the full front page, but with a Location header set, that sends the user to the front page again.
We are not quite sure what could cause this, but also have no clue on how could track this down. Of course, the best way to handle this would be on the drupal side, but we can't really tell why this does happen.
Is there a way to log the cases when this happens? Or is it possible to detect this in varnish and mark the current cache content as invalid?
Of course, we don't want to always pass intentional redirects to the origin server, but the ones that would cause an infinite loop.
I hope to hear some ideas how we can further track this down. Many thank in advance for all kinds of hints.
I have found a workaround for this:
sub vcl_fetch {
// Fix a strange problem: HTTP 301 redirects to the same page sometimes go in$
if (beresp.http.Location == "http://" + req.http.host + req.url) {
if (req.restarts > 2) {
unset beresp.http.Location;
#set beresp.http.X-Restarts = req.restarts;
} else {
return (restart);
}
}
}
I give the backend a second (and thirhd) chance to return a proper page. If that fails as well, the Location header is removed. This works, because the proper page is served with just an additional invalid Location header.
The accepted answer by #philip updated for Varnish 4:
sub vcl_backend_response {
#Fix a strange problem: HTTP 301 redirects to the same page sometimes go in$
if (beresp.http.Location == "http://" + bereq.http.host + bereq.url) {
if (bereq.retries > 2) {
unset beresp.http.Location;
#set beresp.http.X-Restarts = bereq.retries;
} else {
return (retry);
}
}
}

how to get request body in varnish

I am currently working on a project based on varnish..
we write vcl and vmod. But the project needs to check the request body.
How can I get the post request body in VCL or vmod with a C function?
You can do almost everything you want with VCL/VMOD.
You should try to call a VMOD subroutine in vcl_recv, and then in C code, write something like below :
Use VRT_GetHdr(rec->s, HDR_REQ, "\017Content-Length:"); to read the body length
Use HTC_Read(rec->s->htc, body, bodylen);
And enjoy !
You should take a look at existing vmods https://www.varnish-cache.org/vmods, and be free to look into the varnish API sources.
I'm not sure you can.
Varnish generally only deals with Req/Resp headers.
The bodies are passed along without (much) modification.
I you do find a solution please let me know as I'm interested in this as well.

Resources