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);
}
}
}
Related
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.
I am trying to save the HTTP_REFERER to a $_SESSION[] variable and only updating it if the referring page does not match the current page. This way if I reload the page through a PHP script it does not save the current page I'm on as the referrer.
First I am getting the REFERER and comparing it to the current URL:
$referer = $_SERVER["HTTP_REFERER"];
preg_match('/^(.*?\:\/\/)/', $referer, $start);
$url = $start[0].$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
Then I have an IF statement that says if they DONT match to update Session:
if($url != $referer){
$_SESSION['referer'] = $_SERVER["HTTP_REFERER"];
}
Then I check the output:
echo $_SESSION['referer'];
The issue is that it updates the session no matter what!
I have tried to do the same with cookies instead of the session variable. With cookies, I can see it changing in the consol. It won't update, and then a second later it updates. Almost as if the page is loading twice.
When I set this code
setcookie('test', $_SERVER["HTTP_REFERER"]);
When I go to a new page, it will correctly display the correct refer, and then after a second, it switches to the current page.
My current setup uses .htaccess so that I don't have to type the file names of the pages. I have all requests of any subfolders go to /index.php
So http://example.com/home or http://example.com/coolpage will all go back to http://example.com/index.php
Then with PHP I look for the file named the same as that subfolder and then "include" it in my index.php file as a sort of simple templating system.
Are these .htaccess redirects messing with the $_SERVER["HTTP_REFERER"]? If I just use the $_SERVER["HTTP_REFERER"] directly within my code it works fine (it's not updating). It's only when I try to save it to another variable that things go wonky.
Is there a better way to have a back button that sends the user back to where they came from without taking into account multiple page loads of the same URI?
I found a workaround that seems a bit odd, but it achieves the effect I want.
I wrap the whole thing in an if statement only executing if the $uri != favicon.ico
if($uri != 'favicon.ico'){
$referer = $_SERVER["HTTP_REFERER"];
preg_match('/^(.*?\:\/\/)/', $referer, $start);
$url = $start[0].$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
if($url != $referer){
$_SESSION['referer'] = $_SERVER["HTTP_REFERER"];
}
$backButton = $_SESSION['referer'];
}
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
I have a random bug in my JSF app that strips all my HTTP parameters. It happens randomly and I can't get any error messages (even when following BalusC's advice here and here).
I can't pinpoint the cause and fix it so I'm wondering if another solution is possile: forcing the request to be resent if all my parameters are empty. Is there a way to make the browser resend its request? For example, through a JSF or HTTP error code.
EDIT: Cleaned up unnecessary code.
In the end, I followed #Xtreme Biker's advice and instead built a filter. It checks if parameters are present, otherwise it sends a redirect response (HTTP error code 307). Then the browser send back the same request which proceeds through.
Something like:
String formWebContainerWidth = httpRequest.getParameter("myParam");
if(formWebContainerWidth == null){
// SC_TEMPORARY_REDIRECT = 307
httpResponse.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
httpResponse.setHeader("Location", httpRequest.getRequestURI());
} else {
chain.doFilter(request, response);
}
EDIT: Added the location, otherwise the browser sometimes displays a "page cannot be reached" error message.
I have setup varnish on a server that runs two sites on two different domains, varnish works perfect without www in front of the two domains, I have attached the vcl file in this pastebin, I guess it's a basic misconfiguration somewhere, but I can't figure out where - does anyone know of a solution?
http://pastebin.com/CF37isis
To me the configuration looks fine and you should not get any troubles with/without www. Are you sure the DNS is pointing to your varnish server for the www? Of course there's also the possibility that your application acts differently and sets extra cookies/headers on the www request.
Further you should really redirect one of the www/non-www to the other so that only one is always used but both works (can also easily be done with varnish, or also probably in your DNS providers settings).
A redirect in varnish could look something like this (do not this needs to be added in your current vcl_recv/vlc_error and you should not add new blocks):
sub vcl_recv {
if (req.http.host == "www.somedomain.com") {
set req.http.x-Redir-Url = "http://somedomain.com" + req.url;
error 750 req.http.x-Redir-Url;
}
if (req.http.host == "www.someotherdomain.com") {
set req.http.x-Redir-Url = "http://someotherdomain.com" + req.url;
error 750 req.http.x-Redir-Url;
}
}
sub vcl_error {
if (obj.status == 750) {
set obj.http.Location = obj.response;
set obj.status = 301;
return (deliver);
}
}