A scan revealed that trace is enabled on some of my varnish servers. But I thought that trace was only disabled on apache servers. How can this be disabled in varnish?
You may try this in order to return 405 - Method not allowed when varnish receives TRACE or TRACK:
...
sub vcl_recv {
...
if (req.method == "TRACE" || req.method == "TRACK") {
return (synth(405));
}
...
}
...
Related
Super new to varnish. As the title states. I want to redirect anything under example.com/* to just https://example.com/
so far I've tried
if (client.ip != "127.0.0.1" && req.http.host == "example.com") {
set req.http.x-redir = "https://example.com";
error 850 "Moved Permanently";
}
Any thoughts on how I can do this?
Have a look at this specific section of a tutorial I wrote: https://www.varnish-software.com/developers/tutorials/redirect/#http-to-https-redirections.
Here's the code I would use for that:
vcl 4.1;
import proxy;
backend default {
.host = "127.0.0.1";
.port = 8080;
}
sub vcl_recv {
if ((req.http.X-Forwarded-Proto && req.http.X-Forwarded-Proto != "https") ||
(req.http.Scheme && req.http.Scheme != "https")) {
return (synth(750));
} elseif (!req.http.X-Forwarded-Proto && !req.http.Scheme && !proxy.is_ssl()) {
return (synth(750));
}
}
sub vcl_synth {
if (resp.status == 750) {
set resp.status = 301;
set resp.http.location = "https://" + req.http.Host + req.url;
set resp.reason = "Moved";
return (deliver);
}
}
This tutorial checks 3 things:
Whether or not the URL scheme of the request is sent via the X-Forwarded-Proto header
Whether or not the URL scheme of the request is sent via the X-Scheme header which is part of HTTP/2
Whether or not the PROXY protocol was used and the PROXY TLV attributes contains the scheme
When either of these checks concludes that plain HTTP is used, the return(synth(750)) return statement is used to return a synthetic response.
In the vcl_synth subroutine, status code 750 is caught and results in a 301 redirect to the HTTPS version of that request.
The X-Forwarded-Proto header should be set by your TLS PROXY if you're connecting to Varnish using regular HTTP.
If instead you're using the PROXY protocol to connect to Varnish, you should have a look at the following tutorial: https://www.varnish-software.com/developers/tutorials/proxy-protocol-varnish/
Situation::
Varnish needs to cache even in the presence of cookies on the request.
The request may contain N arbitrary cookies of which certain known cookies must not form part of the cache key. The arbitrary cookies don't contain any user sensitive data, eg. they are cosmetic helpers like is_authenticated=1.
The actual backend must receive the original set of cookies unmolested in the case of a cache miss.
I don't want to check for URL patterns in the VCL because that assumes too much knowledge of the backend.
This is surprisingly hard to solve. All solutions I've found so far assumes a whitelist for (2) whereas I need a blacklist. And most solutions delete cookies which are supposed to go through to the backend.
So how about (untested):
# We use builtin.vcl logic and 'return' from our vcl_recv in order
# to prevent default Varnish behaviour of not caching with cookies present
sub vcl_recv {
# your vcl_recv starts here
# ...
# your vcl_recv ends here
if (req.method == "PRI") {
/* We do not support SPDY or HTTP/2.0 */
return (synth(405));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.method != "GET" && req.method != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
if (req.http.Authorization) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
sub vcl_hash {
set req.http.X-Cookie-Hash = regsub(req.http.cookie, "KNOWN1=[^;]+;", "");
set req.http.X-Cookie-Hash = regsub(req.http.X-Cookie-Hash, "KNOWN2=[^;]+;", "");
hash_data(req.http.X-Cookie-Hash);
}
Which removes each known cookie and hashes on the remainders :) Not ideal, because it can't guarantee the order of cookies in the header, but other from that should work.
I've already asked and received an awesome answer about how to get an error from the backend to force serving from stale cache (grace) found here: varnish 4: serve graced object if beresp.status is an error?
but now that logic needs an extra step: i include the following code currently
sub vcl_backend_fetch {
if (bereq.retries == 0) {
unset bereq.http.X-Varnish-Backend-5xx;
unset bereq.http.X-Varnish-Backend-206;
} else {
if (bereq.http.X-Varnish-Backend-5xx) {
return (abandon);
}
if (bereq.http.X-Varnish-Backend-206) {
return (abandon);
}
}
}
sub vcl_synth {
if (resp.status == 503 &&
req.method != "POST" &&
!req.http.X-Varnish-Restarted-5xx) {
set req.http.X-Varnish-Restarted-5xx = "1";
return (restart);
}
if (resp.status == 503 &&
req.method != "POST" &&
!req.http.X-Varnish-Restarted-206) {
set req.http.X-Varnish-Restarted-206 = "1";
return (restart);
}
}
obviously the second if statement in the vcl_synth is virtually identical to the first one, with the exception of the header it's looking for. I need to differentiate the 206 to restart with a different request header, but I am not sure how. the issue is that, if the backend returns a 206, the rest of the logic abandons the backend fetch (which hands off to vcl_synth with a 503), and vcl_synth restarts the request to force serving graced cached objects. however, if there's no graced cache object to return to the user, then the user sees a 503 instead of a 206.
Before realizing that this line of thinking was not possible, i tried to have vcl_backend_fetch return a synth(206), so that vcl_synth could use resp.status to differentiate, and add a different request header before restarting the request. then i would be able to look for that header in vcl_miss, and if it's there, i could restart the whole request a second time, and force it to serve the 206 from the usual backend.
TL;DR: how do I differentiate two different cases in a vcl_backend_fetch abandon, to get vcl_synth to restart the request with two different headers?
I'm pretty sure it's not possible to do anything in vcl_backend_fetch in order to abandon the request and transfer some kind of flag to vcl_synth.
I'm not sure if I've completely understood your use case, but it seems that would need something like:
sub vcl_synth {
if (resp.status == 503 &&
req.method != "POST" &&
!req.http.X-Varnish-Restarted-5xx) {
# Let's restart the request for the first time and try to
# serve grace content. This could select an always-sick
# backend during vcl_recv.
set req.http.X-Varnish-Restarted-5xx = "1";
return (restart);
}
if (resp.status == 503 &&
req.method != "POST" &&
req.http.X-Varnish-Restarted-5xx &&
!req.http.X-Varnish-Restarted-206) {
# Grace content was not available after the first restart. Let's
# restart again the request and try to serve content using some
# other backend.
set req.http.X-Varnish-Restarted-206 = "1";
return (restart);
}
}
Right, I'm going to be honest, I don't know varnish vcl, I can work out some basic stuff but I don't know it very well which is obviously why I'm having issue's.
I'm trying to set up cache banning via a http request, however the request can't come in via the DNS but rather through the IP address of the varnish box otherwise I can't be sure that every varnish box cache will have the target flushed; this is because we have several varnish boxes all behind an ELB so you can't guarantee that a ban request will not go to the same box twice, hence doing this via IPs.
I'm using this to insure that only the allowed IP's are allowed to ban but this isn't working:
sub vcl_hit {
if (req.request == "BAN") {
ban("req.url ==" + req.url);
error 200 "Purged";
}
}
I don't really know what to do to get this working and I've looked but most of the tutorials I've found seem to be for full URLS rather than just ip + pattern_to_purge
from your config example i expect you use varnish 3
you can add a list of ips that is allowed to do the purge as followed
acl ban_allowed_ip {
"127.0.0.1";
"127.0.0.2";
}
inside your if(req.request =="BAN") add the following
if (!client.ip ~ ban_allowed_ip) {
error 405 "Not allowed.";
}
The answer is to use:
if (req.request == "BAN") {
if (req.http.X-Debug != "True") {
error 405 "Not allowed.";
}
ban("obj.http.x-url ~ " + req.url);
error 200 "ban added";
}
Whilst this will return 200 regardless if the item in the cache exists or not, it does add the ban.
Can I configure Varnish in such a way it shows the original page from the backend when the backend throws a 500 error page?
It's the default. I have some if (beresp.status == 500) in it :s
I assume you want to show the original 500 error only in some environments, like development.
If so, then you can assign Varnish an identity:
$ varnishd -i development
And then check that identity in your VCL:
sub vcl_fetch {
if (server.identity ~ "^development") {
return (deliver);
}
if (beresp.status == 500) {
# ...
}
}