Error 503 backend fetch failed while i am trying to download - varnish

I have a haproxy-varnish setup for my ASPNET Core Web application and my application sending request via haproxy.conf file to the varnish. I can download all downloadable files except one url /Payroll/Export/EmployeeAllDataExport?.... File format is .xlsx. Tranfer-encoding header added manually by someone else so maybe that change refers the problem but i couldn't resolve until now.
I am sharing varnishlog -g request -q "RespStatus == 503" output, default.vcl file and releated lines in haproxy.cfg
P.S: If i disable varnish request from haproxy i can download the file but i need to do it with varnish and there is a problem for only one url not in an entire application.
varnishlog output:
* << Request >> 1384717
- Begin req 1384716 rxreq
- Timestamp Start: 1658919403.185251 0.000000 0.000000
- Timestamp Req: 1658919403.185251 0.000000 0.000000
- VCL_use boot
- ReqStart $IP1 43974 a0
- ReqMethod GET
- ReqURL /Payroll/Report/EmployeeAllDataExport?1658919403106
- ReqProtocol HTTP/1.1
- ReqHeader Host: $URL1
- ReqHeader sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"
- ReqHeader sec-ch-ua-mobile: ?0
- ReqHeader sec-ch-ua-platform: "Windows"
- ReqHeader Upgrade-Insecure-Requests: 1
- ReqHeader User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
- ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
- ReqHeader Sec-Fetch-Site: same-origin
- ReqHeader Sec-Fetch-Mode: navigate
- ReqHeader Sec-Fetch-User: ?1
- ReqHeader Sec-Fetch-Dest: document
- ReqHeader Referer: https://$URL1/Payroll/Report/EmployeeAllData?sitemap=63f8e1f5-a873-4cb5-8a5c-16b79863da33
- ReqHeader Accept-Encoding: gzip, deflate, br
- ReqHeader Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader X-Forwarded-Proto: https
- ReqHeader X-Forwarded-Port: 443
- ReqHeader X-Forwarded-Proto: https
- ReqHeader X-Forwarded-For: $IP2
- ReqHeader Connection: close
- ReqUnset X-Forwarded-For: $IP2
- ReqHeader X-Forwarded-For: $IP2, $IP1
- VCL_call RECV
- ReqUnset Host: $URL1
- ReqHeader Host: $URL1
- ReqURL /Payroll/Report/EmployeeAllDataExport?1658919403106
- ReqUnset Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqUnset Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqUnset Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqUnset Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqUnset Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
- ReqHeader Surrogate-Capability: key=ESI/1.0
- VCL_return hash
- ReqUnset Accept-Encoding: gzip, deflate, br
- ReqHeader Accept-Encoding: gzip
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 1384718 fetch
- Timestamp Fetch: 1658919404.932211 1.746959 1.746959
- RespProtocol HTTP/1.1
- RespStatus 503
- RespReason Backend fetch failed
- RespHeader Date: Wed, 27 Jul 2022 10:56:44 GMT
- RespHeader Server: Varnish
- RespHeader Content-Type: text/html; charset=utf-8
- RespHeader Retry-After: 5
- RespHeader X-Varnish: 1384717
- RespHeader Age: 0
- RespHeader Via: 1.1 varnish (Varnish/6.2)
- VCL_call DELIVER
- RespHeader X-Cache: MISS
- RespHeader X-Cache-Hits: 0
- RespUnset Server: Varnish
- RespUnset X-Varnish: 1384717
- RespUnset Via: 1.1 varnish (Varnish/6.2)
- VCL_return deliver
- Timestamp Process: 1658919404.932258 1.747006 0.000047
- Filters
- RespHeader Content-Length: 284
- RespHeader Connection: close
- Timestamp Resp: 1658919404.932344 1.747092 0.000086
- ReqAcct 5695 0 5695 210 284 494
- End
** << BeReq >> 1384718
-- Begin bereq 1384717 fetch
-- VCL_use boot
-- Timestamp Start: 1658919403.185407 0.000000 0.000000
-- BereqMethod GET
-- BereqURL /Payroll/Report/EmployeeAllDataExport?1658919403106
-- BereqProtocol HTTP/1.1
-- BereqHeader sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"
-- BereqHeader sec-ch-ua-mobile: ?0
-- BereqHeader sec-ch-ua-platform: "Windows"
-- BereqHeader Upgrade-Insecure-Requests: 1
-- BereqHeader User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
-- BereqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
-- BereqHeader Sec-Fetch-Site: same-origin
-- BereqHeader Sec-Fetch-Mode: navigate
-- BereqHeader Sec-Fetch-User: ?1
-- BereqHeader Sec-Fetch-Dest: document
-- BereqHeader Referer: https://$URL1/Payroll/Report/EmployeeAllData?sitemap=63f8e1f5-a873-4cb5-8a5c-16b79863da33
-- BereqHeader Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
-- BereqHeader X-Forwarded-Proto: https
-- BereqHeader X-Forwarded-Port: 443
-- BereqHeader X-Forwarded-Proto: https
-- BereqHeader X-Forwarded-For: $IP1, $IP2
-- BereqHeader Host: $URL1
-- BereqHeader Cookie: CurrentLanguage=tr; .AspNetCore.Antiforgery.9TtSrW0hzOs=CfDJ8E7lWAHTLKBOsOUJGWpm85n139G92-PEfuGVynC-Lh4dd-5XOYoILAhHGAD6DW-my0vgWvin4bBKCLT-GFQonAQCvkTZV8EuOB8s6RPOunsRFPpgucKPwKQSmF7Syx0tg8TubZs_Xw6qTxh9gVq03lo; Hcm=CfDJ8E7lWAHTLKBOsOUJGWpm85lmo
-- BereqHeader Surrogate-Capability: key=ESI/1.0
-- BereqHeader Accept-Encoding: gzip
-- BereqHeader X-Varnish: 1384718
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- BackendOpen 31 haproxy $IP1 8585 $IP3 52722
-- BackendStart $IP1 8585
-- Timestamp Bereq: 1658919403.185494 0.000087 0.000087
-- Timestamp Beresp: 1658919404.931989 1.746582 1.746495
-- BerespProtocol HTTP/1.1
-- BerespStatus 200
-- BerespReason OK
-- BerespHeader Connection: close
-- BerespHeader Date: Wed, 27 Jul 2022 10:56:44 GMT
-- BerespHeader Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
-- BerespHeader Server: Kestrel
-- BerespHeader Transfer-Encoding: identity
-- BerespHeader Strict-Transport-Security: max-age=2592000
-- BerespHeader content-disposition: attachment; filename="$Filename.xlsx"
-- BackendClose 31 haproxy
-- Error Body cannot be fetched
-- Timestamp Error: 1658919404.932043 1.746636 0.000054
-- BerespProtocol HTTP/1.1
-- BerespStatus 503
-- BerespReason Service Unavailable
-- BerespReason Backend fetch failed
-- BerespHeader Date: Wed, 27 Jul 2022 10:56:44 GMT
-- BerespHeader Server: Varnish
-- VCL_call BACKEND_ERROR
-- BerespHeader Content-Type: text/html; charset=utf-8
-- BerespHeader Retry-After: 5
-- VCL_return deliver
-- Storage malloc Transient
-- Length 284
-- BereqAcct 5731 0 5731 327 0 327
-- End
default.vcl
vcl 4.1;
# Based on: https://github.com/mattiasgeniar/varnish-6.0-configuration-templates/blob/master/default.vcl
import std;
import directors;
backend haproxy { # Define one backend
.host = "10.10.0.117"; # IP or Hostname of backend
.port = "8585"; # Port Apache or whatever is listening
.max_connections = 300; # That's it
.first_byte_timeout = 300s; # How long to wait before we receive a first byte from our backend?
.connect_timeout = 300s; # How long to wait for a backend connection?
.between_bytes_timeout = 300s; # How long to wait between bytes received from our backend?
}
acl purge {
"localhost";
"127.0.0.1";
"::1";
}
sub vcl_init {
new vdir = directors.round_robin();
vdir.add_backend(haproxy);
}
sub vcl_recv {
#if (req.url ~ "^/Payroll/Report") {
# return(pipe);
#}
set req.backend_hint = vdir.backend(); # send all traffic to the vdir director
if (req.http.Host) {
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
}
unset req.http.proxy;
set req.url = std.querysort(req.url);
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "This IP is not allowed to send PURGE requests."));
}
return (purge);
}
# Only deal with "normal" types
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "PATCH" &&
req.method != "DELETE" ){
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
if (req.http.Upgrade ~ "(?i)websocket") {
return (pipe);
}
# Only cache GET or HEAD requests. This makes sure the POST requests are always passed.
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
set req.url = regsub(req.url, "\?&", "?");
set req.url = regsub(req.url, "\?$", "");
}
# Strip hash, server doesn't need it.
if (req.url ~ "\#") {
set req.url = regsub(req.url, "\#.*$", "");
}
# Strip a trailing ? if it exists
if (req.url ~ "\?$") {
set req.url = regsub(req.url, "\?$", "");
}
set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
if (req.http.cookie ~ "^\s*$") {
unset req.http.cookie;
}
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)(\?.*)?$") {
unset req.http.Cookie;
return (hash);
}
# Remove all cookies for static files
# 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.
# Sure, there's disk I/O, but chances are your OS will already have these files in their buffers (thus memory).
# Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
if (req.url ~ "^[^?]*\.(7z|apng|webp|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)(\?.*)?$") {
unset req.http.Cookie;
return (hash);
}
#if (req.url ~ "^/Payroll/Report") {
# unset req.http.Cookie;
# return (hash);
#}
# Send Surrogate-Capability headers to announce ESI support to backend
set req.http.Surrogate-Capability = "key=ESI/1.0";
if (req.http.Authorization) {
# Not cacheable by default
return (pass);
}
if (req.url ~ "(jpg|jpeg|png|gif|tiff|bmp|apng|webp)$") {
return (pipe);
}
return (hash);
}
sub vcl_pipe {
# Called upon entering pipe mode.
# In this mode, the request is passed on to the backend, and any further data from both the client
# and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
# degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
# no other VCL subroutine will ever get called after vcl_pipe.
# Note that only the first request to the backend will have
# X-Forwarded-For set. If you use X-Forwarded-For and want to
# have it set for all requests, make sure to have:
# set bereq.http.connection = "close";
# here. It is not set by default as it might break some broken web
# applications, like IIS with NTLM authentication.
# set bereq.http.Connection = "Close";
# Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
}
return (pipe);
}
sub vcl_pass {
# Called upon entering pass mode. In this mode, the request is passed on to the backend, and the
# backend's response is passed on to the client, but is not entered into the cache. Subsequent
# requests submitted over the same client connection are handled normally.
# return (pass);
}
# The data on which the hashing will take place
sub vcl_hash {
# Called after vcl_recv to create a hash value for the request. This is used as a key
# to look up the object in Varnish.
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
# hash cookies for requests that have them
if (req.http.Cookie) {
hash_data(req.http.Cookie);
}
# Cache the HTTP vs HTTPs separately
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
}
sub vcl_hit {
# Called when a cache lookup is successful.
if (obj.ttl >= 0s) {
# A pure unadultered hit, deliver it
return (deliver);
}
# https://www.varnish-cache.org/docs/trunk/users-guide/vcl-grace.html
# 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.
# 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.
# if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
# return (deliver);
# } else {
# return (miss);
# }
# We have no fresh fish. Lets look at the stale ones.
if (std.healthy(req.backend_hint)) {
# Backend is healthy. Limit age to 10s.
if (obj.ttl + 10s > 0s) {
#set req.http.grace = "normal(limited)";
return (deliver);
}
} else {
# backend is sick - use full grace
if (obj.ttl + obj.grace > 0s) {
#set req.http.grace = "full";
return (deliver);
}
}
}
sub vcl_miss {
# Called after a cache lookup if the requested document was not found in the cache. Its purpose
# is to decide whether or not to attempt to retrieve the document from the backend, and which
# backend to use.
return (fetch);
}
# Handle the HTTP request coming from our backend
sub vcl_backend_response {
# Called after the response headers has been successfully retrieved from the backend.
# Pause ESI request and remove Surrogate-Control header
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
# Enable cache for all static files
# 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.
# Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
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)(\?.*)?$") {
unset beresp.http.set-cookie;
}
#if (bereq.url ~ "^/Payroll/Report") {
# unset beresp.http.set-cookie;
#}
# Large static files are delivered directly to the end-user without
# waiting for Varnish to fully read the file first.
# Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
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)(\?.*)?$") {
unset beresp.http.set-cookie;
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
}
# Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along.
# This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box.
# A redirect can then often redirect the end-user to a URL on :8080, where it should be :80.
# This may need finetuning on your setup.
#
# To prevent accidental replace, we only filter the 301/302 redirects for now.
if (beresp.status == 301 || beresp.status == 302) {
set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", "");
}
# Set 2min cache if unset for static files
if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
set beresp.uncacheable = true;
return (deliver);
}
# Don't cache 50x responses
if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
return (abandon);
}
# Allow stale content, in case the backend goes down.
# make Varnish keep all objects for 6 hours beyond their TTL
set beresp.grace = 6h;
return (deliver);
}
# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
# Called before a cached object is delivered to the client.
if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
# Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object
# and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for details.
# So take hits with a grain of salt
set resp.http.X-Cache-Hits = obj.hits;
# Remove some headers: PHP version
unset resp.http.X-Powered-By;
# Remove some headers: Apache version & OS
unset resp.http.Server;
unset resp.http.X-Drupal-Cache;
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.Link;
unset resp.http.X-Generator;
return (deliver);
}
sub vcl_purge {
# Only handle actual PURGE HTTP methods, everything else is discarded
if (req.method == "PURGE") {
# restart request
set req.http.X-Purge = "Yes";
return(restart);
}
}
sub vcl_synth {
if (resp.status == 720) {
# We use this special error status 720 to force redirects with 301 (permanent) redirects
# To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
set resp.http.Location = resp.reason;
set resp.status = 301;
return (deliver);
} elseif (resp.status == 721) {
# And we use error status 721 to force redirects with a 302 (temporary) redirect
# To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
set resp.http.Location = resp.reason;
set resp.status = 302;
return (deliver);
}
return (deliver);
}
sub vcl_fini {
# Called when VCL is discarded only after all requests have exited the VCL.
# Typically used to clean up VMODs.
return (ok);
}
P.S: please consider i tried if(req.url ~ $URL){return (pass);} or pipe and if(bereq.url ~ $URL){unset beresp.http.set-cookie;}. Those lines which i tried now command line at the default.vcl file.
haproxy.cfg
frontend HTTP
bind *:80
redirect scheme https if { hdr(Host) -i $URL1 } !{ ssl_fc }
frontend returning-varnish # returning traffic from varnish
bind :8585
#acl $Backend1 hdr(host) -i $URL1
#use_backend $Backend1 if $Backend1
frontend HTTPS
bind *:443 ssl crt $Directory1 crt $Directory2
# http-request lua.cors
# http-response lua.cors "GET,PUT,POST" "localhost:1907"
# http-response lua.cors "GET,PUT,POST" "*"
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
rspadd Content-Security-Policy:\ upgrade-insecure-requests
reqadd X-Forwarded-Proto:\ https
#rspadd Strict-Transport-Security:\ max-age=31536000
http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; always;"
maxconn 100000
redirect prefix https://$URL2 if { hdr(host) -i $URL4 }
redirect prefix https://$URL3 if { hdr(host) -i $URL4 }
#use_backend Varnish if $Backend1
use_backend $Backend1 if $Backend1
backend Varnish
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
server varnish1 $IP2:6081 check
backend $Backend1
mode http
balance leastconn
server $Server $Application_Ip:31717 check inter 1s rise 2 fall 2
P.S: Because of the varnish is not working while I want to download file, I made those lines as a command line at haproxy.cfg file as well.

Based on the logs I'm assuming the response headers of your backend response are not properly formatted.
The VSL error is the following:
-- Error Body cannot be fetched
Your backend response doesn't include a Content-Length header, which is fine. But if you don't return a buffered response, Varnish looks at the Transfer-Encoding header to see whether or not you'r using Chunked Transfer Encoding.
This is the header your application is returning:
-- BerespHeader Transfer-Encoding: identity
When we take a look at the code, specifically this line https://github.com/varnishcache/varnish-cache/blob/55753f98b1b392766bd4baed7eb684c006225f57/bin/varnishd/http1/cache_http1_proto.c#L319, you can see that Varnish throws the error because it doesn't recognize the transfer encoding.
Please set a Transfer-Encoding: chunked header and Varnish will have no issue with this response and will stream the content through based on how your backend flushes the various chunks of content.

Related

Varnish Xkey softpurge

I'm trying to manage a Xkey soft-purge on objects stored from different hosts, using Xkey as a sort of tag to purge all objects that match the Xkey tag disregarding the hashing.
First of all, is it possible? Or is hashing in the loop in any case?
In vcl_recv I manually set a Xkey key with set req.http.xkey = req.url;
Then during PURGE call I use set req.http.x-purges = xkey.purge(req.url); to find objects, here non objects are found.
Full VCL:
vcl 4.0;
import std;
import directors;
import purge;
import xkey;
backend server1 {
.host = "ecommerce-node1-prod";
.port = "80";
.probe = {
.url = "/admin";
.timeout = 1s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
}
backend server2 {
.host = "ecommerce-node2-prod";
.port = "80";
.probe = {
.url = "/admin";
.timeout = 1s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
}
sub vcl_init {
new bar = directors.round_robin();
bar.add_backend(server1);
bar.add_backend(server2);
}
# ACL for purgers IP. (This needs to contain app server ips)
acl purgers {
"127.0.0.1";
"localhost";
"::1";
"ecommerce-node1-prod";
"ecommerce-node2-prod";
}
sub vcl_recv {
# Mitigate httpoxy application vulnerability, see: https://httpoxy.org/
unset req.http.Proxy;
set req.http.xkey = req.url;
# Strip query strings only needed by browser javascript. Customize to used tags.
if (req.url ~ "(\?|&)(pk_campaign|piwik_campaign|pk_kwd|piwik_kwd|pk_keyword|pixelId|kwid|kw|adid|chl|dv|nk|pa|camid|adgid|cx|ie|cof|siteurl|utm_[a-z]+|_ga|gclid)=") {
# see rfc3986#section-2.3 "Unreserved Characters" for regex
set req.url = regsuball(req.url, "(pk_campaign|piwik_campaign|pk_kwd|piwik_kwd|pk_keyword|pixelId|kwid|kw|adid|chl|dv|nk|pa|camid|adgid|cx|ie|cof|siteurl|utm_[a-z]+|_ga|gclid)=[A-Za-z0-9\-\_\.\~]+&?", "");
}
set req.url = regsub(req.url, "(\?|\?&|&)$", "");
# Normalize query arguments
set req.url = std.querysort(req.url);
# Normalize Accept-Encoding header
# straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
# No point in compressing these
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
# unkown algorithm
unset req.http.Accept-Encoding;
}
}
# Handle PURGE
if (req.method == "PURGE") {
if (!client.ip ~ purgers) {
return (synth(405, "Method not allowed"));
}
#set req.http.n-gone = xkey.softpurge(req.http.xkey);
set req.http.x-purges = xkey.purge(req.url);
return (synth(200, "Invalidated "+ req.http.x-purges +" objects"));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "PATCH" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# We only deal with GET and HEAD by default
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
#pass media to backend (already cached by CloudFront)
if (req.url ~ "^\/(media|bundles|css|fonts|js|theme|thumbnail)(\/.*)?$") {
return (pass);
}
# Don't cache Authenticate & Authorization
if (req.http.Authenticate || req.http.Authorization) {
return (pass);
}
# Always pass these paths directly to php without caching
# Note: virtual URLs might bypass this rule (e.g. /en/checkout)
if (req.url ~ "^/(checkout|account|admin|api)(/.*)?$") {
return (pass);
}
return (hash);
}
sub vcl_hash {
# Consider Shopware http cache cookies
if (req.http.cookie ~ "sw-cache-hash=") {
hash_data("+context=" + regsub(req.http.cookie, "^.*?sw-cache-hash=([^;]*);*.*$", "\1"));
} elseif (req.http.cookie ~ "sw-currency=") {
hash_data("+currency=" + regsub(req.http.cookie, "^.*?sw-currency=([^;]*);*.*$", "\1"));
}
#return(lookup);
}
sub vcl_hit {
# Consider client states for response headers
if (req.http.cookie ~ "sw-states=") {
set req.http.states = regsub(req.http.cookie, "^.*?sw-states=([^;]*);*.*$", "\1");
if (req.http.states ~ "logged-in" && obj.http.sw-invalidation-states ~ "logged-in" ) {
return (pass);
}
if (req.http.states ~ "cart-filled" && obj.http.sw-invalidation-states ~ "cart-filled" ) {
return (pass);
}
}
}
sub vcl_backend_response {
# Fix Vary Header in some cases
if (beresp.http.Vary ~ "User-Agent") {
set beresp.http.Vary = regsub(beresp.http.Vary, ",? *User-Agent *", "");
set beresp.http.Vary = regsub(beresp.http.Vary, "^, *", "");
if (beresp.http.Vary == "") {
unset beresp.http.Vary;
}
}
# Respect the Cache-Control=private header from the backend
if (
beresp.http.Pragma ~ "no-cache" ||
beresp.http.Cache-Control ~ "no-cache" ||
beresp.http.Cache-Control ~ "private"
) {
set beresp.ttl = 0s;
set beresp.http.X-Cacheable = "NO:Cache-Control=private";
set beresp.uncacheable = true;
return (deliver);
}
# strip the cookie before the image is inserted into cache.
if (bereq.url ~ "\.(png|gif|jpg|swf|css|js|webp)$") {
unset beresp.http.set-cookie;
}
# Allow items to be stale if needed.
set beresp.grace = 60s;
# Save the bereq.url so purges work efficiently
set beresp.http.x-url = bereq.url;
set beresp.http.X-Cacheable = "YES";
# Remove the exact PHP Version from the response for more security
unset beresp.http.x-powered-by;
return (deliver);
}
sub vcl_deliver {
## we don't want the client to cache
set resp.http.Cache-Control = "max-age=0, private";
# remove link header, if session is already started to save client resources
if (req.http.cookie ~ "session-") {
unset resp.http.Link;
}
# Set a cache header to allow us to inspect the response headers during testing
if (obj.hits > 0) {
unset resp.http.set-cookie;
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
# Remove the exact PHP Version from the response for more security (e.g. 404 pages)
unset resp.http.x-powered-by;
# invalidation headers are only for internal use
unset resp.http.sw-invalidation-states;
set resp.http.X-Cache-Hits = obj.hits;
}
Request where xkey is added
* << Request >> 32796
- Begin req 32795 rxreq
- Timestamp Start: 1664372821.615382 0.000000 0.000000
- Timestamp Req: 1664372821.615382 0.000000 0.000000
- VCL_use boot
- ReqStart 172.16.0.80 20244 a0
- ReqMethod GET
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqProtocol HTTP/1.1
- ReqHeader X-Forwarded-For: 84.247.245.84, 130.176.89.143
- ReqHeader X-Forwarded-Proto: https
- ReqHeader X-Forwarded-Port: 443
- ReqHeader Host: test-prod.luminalpark.com
- ReqHeader X-Amzn-Trace-Id: Root=1-63345055-76f876fd27d8613e28b7c9db
- ReqHeader User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.53
- ReqHeader X-Amz-Cf-Id: JA7XrQuv5k-jhdhb3uKmlf88YjlJVvcDcw6udobH5vL-YkSMDT2flw==
- ReqHeader Via: 2.0 6c61cea6f371b1744d3b5315a0029062.cloudfront.net (CloudFront)
- ReqHeader Cookie: _dc_gtm_UA-830149-18=1; _ga=GA1.1.1015042543.1664369859; _ga_499EG6CXZD=GS1.1.1664371930.2.1.1664372814.0.0.0; _gcl_au=1.1.1616057317.1664369858; _gid=GA1.2.1284203691.1664369859; lp-platform=it-it; lp-state=IT; newUser=1; poll_manager=1; session
- ReqHeader Accept-Language: it,it-IT;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,fr;q=0.5
- ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
- ReqHeader Accept-Encoding: gzip, deflate, br
- ReqHeader cache-control: max-age=0
- ReqHeader sec-ch-ua: "Microsoft Edge";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
- ReqHeader sec-ch-ua-mobile: ?0
- ReqHeader sec-ch-ua-platform: "Windows"
- ReqHeader dnt: 1
- ReqHeader upgrade-insecure-requests: 1
- ReqHeader sec-fetch-site: none
- ReqHeader sec-fetch-mode: navigate
- ReqHeader sec-fetch-user: ?1
- ReqHeader sec-fetch-dest: document
- ReqHeader CloudFront-Viewer-HTTP-Version: 2.0
- ReqHeader CloudFront-Forwarded-Proto: https
- ReqHeader CloudFront-Viewer-Address: 84.247.245.84:59146
- ReqHeader CloudFront-Viewer-TLS: TLSv1.3:TLS_AES_128_GCM_SHA256:connectionReused
- ReqHeader X-Cloudfront-Origin: VC5ZNQ588QNE3S
- ReqUnset X-Forwarded-For: 84.247.245.84, 130.176.89.143
- ReqHeader X-Forwarded-For: 84.247.245.84, 130.176.89.143, 172.16.0.80
- ReqUnset Via: 2.0 6c61cea6f371b1744d3b5315a0029062.cloudfront.net (CloudFront)
- ReqHeader Via: 2.0 6c61cea6f371b1744d3b5315a0029062.cloudfront.net (CloudFront), 1.1 ip-172-16-3-107 (Varnish/trunk)
- VCL_call RECV
- ReqHeader xkey: /it-it/prodotti/catene/catene-di-luci/
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqUnset Accept-Encoding: gzip, deflate, br
- ReqHeader Accept-Encoding: gzip
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- Hit 32771 7190.679091 60.000000 0.000000
- VCL_call HIT
- VCL_return deliver
- RespProtocol HTTP/1.1
- RespStatus 200
- RespReason OK
- RespHeader Server: nginx/1.18.0 (Ubuntu)
- RespHeader Content-Type: text/html; charset=UTF-8
- RespHeader Cache-Control: must-revalidate, public, s-maxage=7200
- RespHeader Date: Wed, 28 Sep 2022 13:46:52 GMT
- RespHeader Strict-Transport-Security: max-age=31536000; includeSubDomains
- RespHeader X-Frame-Options: deny
- RespHeader X-Content-Type-Options: nosniff
- RespHeader Referrer-Policy: strict-origin-when-cross-origin
- RespHeader sw-invalidation-states:
- RespHeader Set-Cookie: sw-states=deleted; expires=Tue, 28-Sep-2021 13:46:51 GMT; Max-Age=0; path=/; secure; httponly; samesite=lax
- RespHeader Set-Cookie: sw-cache-hash=deleted; expires=Tue, 28-Sep-2021 13:46:51 GMT; Max-Age=0; path=/; httponly
- RespHeader Content-Encoding: gzip
- RespHeader Vary: Accept-Encoding
- RespHeader x-url: /it-it/prodotti/catene/catene-di-luci/
- RespHeader X-Cacheable: YES
- RespHeader X-Varnish: 32796 32771
- RespHeader Age: 9
- RespHeader Via: 1.1 ip-172-16-3-107 (Varnish/trunk)
- RespHeader Accept-Ranges: bytes
- VCL_call DELIVER
- RespUnset Cache-Control: must-revalidate, public, s-maxage=7200
- RespHeader Cache-Control: max-age=0, private
- RespUnset Set-Cookie: sw-states=deleted; expires=Tue, 28-Sep-2021 13:46:51 GMT; Max-Age=0; path=/; secure; httponly; samesite=lax
- RespUnset Set-Cookie: sw-cache-hash=deleted; expires=Tue, 28-Sep-2021 13:46:51 GMT; Max-Age=0; path=/; httponly
- RespHeader X-Cache: HIT
- RespUnset sw-invalidation-states:
- RespHeader X-Cache-Hits: 1
- VCL_return deliver
- Timestamp Process: 1664372821.615457 0.000074 0.000074
- Filters
- RespHeader Content-Length: 110820
- RespHeader Connection: keep-alive
- Timestamp Resp: 1664372821.615548 0.000166 0.000091
- ReqAcct 1598 0 1598 619 110820 111439
- End
Purge request log, showing no objects found:
* << Request >> 1277962
- Begin req 1277960 rxreq
- Timestamp Start: 1664372901.809064 0.000000 0.000000
- Timestamp Req: 1664372901.809064 0.000000 0.000000
- VCL_use boot
- ReqStart 172.16.2.136 51214 a0
- ReqMethod PURGE
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqProtocol HTTP/1.1
- ReqHeader Host: 172.16.3.107
- ReqHeader User-Agent: GuzzleHttp/7
- ReqHeader X-Forwarded-For: 172.16.2.136
- ReqHeader Via: 1.1 ip-172-16-3-107 (Varnish/trunk)
- VCL_call RECV
- ReqHeader xkey: /it-it/prodotti/catene/catene-di-luci/
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqURL /it-it/prodotti/catene/catene-di-luci/
- ReqHeader x-purges: 0
- VCL_return synth
- VCL_call HASH
- VCL_Log hashing for BAN request
- VCL_return lookup
- RespProtocol HTTP/1.1
- RespStatus 200
- RespReason Invalidated 0 objects
- RespHeader Date: Wed, 28 Sep 2022 13:48:21 GMT
- RespHeader Server: Varnish
- RespHeader X-Varnish: 1277962
- VCL_call SYNTH
- RespHeader Content-Type: text/html; charset=utf-8
- RespHeader Retry-After: 5
- VCL_return deliver
- Timestamp Process: 1664372901.809126 0.000061 0.000061
- RespHeader Content-Length: 287
- Storage malloc Transient
- Filters
- RespHeader Connection: keep-alive
- Timestamp Resp: 1664372901.809155 0.000090 0.000029
- ReqAcct 101 0 101 213 287 500
- End
It's perfectly possible, but you need to add the header to beresp object (in vcl_backend_response) to have the objects properly tagged
Setting keys
vmod_xkey doesn't offer you a lot of flexibility when it comes to setting keys. The only way to do this is by adding one or more xkey headers to your response containing the tags you want to assign to this object:
Here's an example where we set 3 tags:
HTTP/1.1 200 OK
xkey: 8155054
xkey: 166412
xkey: 234323
It's also possible to set multiple keys in a single xkey header as illustrated below:
HTTP/1.1 200 OK
xkey: 8155054 166412 234323
Unlike Varnish Enterprise's vmod_ykey, vmod_xkey doesn't allow you to set tags in vcl_backend_response. vmod_ykey also allows you to choose the header you want to use to tag content. vmod_xkey only allows the xkey header.
Invalidating keys
Once you have tagged the content, you can remove content based on those tags. Here's a quick example of a tag that was passed to Varnish through the xkey request header:
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purgers) {
return (synth(403, "Forbidden"));
}
if (req.http.xkey) {
set req.http.n-gone = xkey.softpurge(req.http.xkey)
return (synth(200, "Invalidated "+req.http.n-gone+" objects"));
} else {
return (purge);
}
}
}
The purgers ACL isn't included in the VCL example, but should be defined in your VCL code and contain the allowed IP addresses, hostnames or subnets.
Here's an example of how you would execute the PURGE using cURL :
curl -XPURGE -H "xkey: 8155054" http://test-prod.luminalpark.com/

Why does 301 error occur when varnish and wordpress are linked?

I would like to use varnish as a reverse proxy to provide wordpress service.
However, even if you set the default.vcl setting, installing Proxy Cache Purge, and so on, you can follow the instructions
When accessing through varnish port, 301 Redirect occurs and it is connected to the backend origin server.
The same phenomenon occurs even if a new wordpress server is installed and a separate plug-in/theme is not installed.
Why is this happening and how can it be solved?
varnish default.vcl settings
varnish default.vcl
vcl 4.1;
import std;
backend default {
.host = "172.16.21.222";
.port = "8000"; }
acl purge {
"localhost";
"127.0.0.1";
"172.16.21.222";
"::1"; }
sub vcl_recv {
if (req.url ~ "\?$") {
set req.url = regsub(req.url, "\?$", "");
}
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
set req.url = std.querysort(req.url);
unset req.http.proxy;
if(req.method == "PURGE") {
if(!client.ip ~ purge) {
return(synth(405,"PURGE not allowed for this IP address"));
}
if (req.http.X-Purge-Method == "regex") {
ban("obj.http.x-url ~ " + req.url + " && obj.http.x-host == " + req.http.host);
return(synth(200, "Purged"));
}
ban("obj.http.x-url == " + req.url + " && obj.http.x-host == " + req.http.host);
return(synth(200, "Purged"));
}
if (
req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "PATCH" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE"
) {
return (pipe);
}
if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
set req.url = regsub(req.url, "\?&", "?");
set req.url = regsub(req.url, "\?$", "");
}
if (req.method != "GET" && req.method != "HEAD") {
set req.http.X-Cacheable = "NO:REQUEST-METHOD";
return(pass);
}
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|ogg|ogm|opus|otf|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)(\?.*)?$") {
set req.http.X-Static-File = "true";
unset req.http.Cookie;
return(hash);
}
if (
req.http.Cookie ~ "wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordpress_logged_in_|comment_author|PHPSESSID" ||
req.http.Authorization ||
req.url ~ "add_to_cart" ||
req.url ~ "edd_action" ||
req.url ~ "nocache" ||
req.url ~ "^/addons" ||
req.url ~ "^/bb-admin" ||
req.url ~ "^/bb-login.php" ||
req.url ~ "^/bb-reset-password.php" ||
req.url ~ "^/cart" ||
req.url ~ "^/checkout" ||
req.url ~ "^/control.php" ||
req.url ~ "^/login" ||
req.url ~ "^/logout" ||
req.url ~ "^/lost-password" ||
req.url ~ "^/my-account" ||
req.url ~ "^/product" ||
req.url ~ "^/register" ||
req.url ~ "^/register.php" ||
req.url ~ "^/server-status" ||
req.url ~ "^/signin" ||
req.url ~ "^/signup" ||
req.url ~ "^/stats" ||
req.url ~ "^/wc-api" ||
req.url ~ "^/wp-admin" ||
req.url ~ "^/wp-comments-post.php" ||
req.url ~ "^/wp-cron.php" ||
req.url ~ "^/wp-login.php" ||
req.url ~ "^/wp-activate.php" ||
req.url ~ "^/wp-mail.php" ||
req.url ~ "^/wp-login.php" ||
req.url ~ "^\?add-to-cart=" ||
req.url ~ "^\?wc-api=" ||
req.url ~ "^/preview=" ||
req.url ~ "^/\.well-known/acme-challenge/"
) {
set req.http.X-Cacheable = "NO:Logged in/Got Sessions";
if(req.http.X-Requested-With == "XMLHttpRequest") {
set req.http.X-Cacheable = "NO:Ajax";
}
return(pass);
}
unset req.http.Cookie;
return(hash); }
sub vcl_hash {
if(req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
} }
sub vcl_backend_response {
set beresp.http.x-url = bereq.url;
set beresp.http.x-host = bereq.http.host;
if (!beresp.http.Cache-Control) {
set beresp.ttl = 1h;
set beresp.http.X-Cacheable = "YES:Forced";
}
if (bereq.http.X-Static-File == "true") {
unset beresp.http.Set-Cookie;
set beresp.http.X-Cacheable = "YES:Forced";
set beresp.ttl = 1d;
}
if (beresp.http.Set-Cookie ~ "wfvt_|wordfence_verifiedHuman") {
unset beresp.http.Set-Cookie; }
if (beresp.http.Set-Cookie) {
set beresp.http.X-Cacheable = "NO:Got Cookies";
} elseif(beresp.http.Cache-Control ~ "private") {
set beresp.http.X-Cacheable = "NO:Cache-Control=private";
} }
sub vcl_deliver {
if(req.http.X-Cacheable) {
set resp.http.X-Cacheable = req.http.X-Cacheable;
} elseif(obj.uncacheable) {
if(!resp.http.X-Cacheable) {
set resp.http.X-Cacheable = "NO:UNCACHEABLE";
}
} elseif(!resp.http.X-Cacheable) {
set resp.http.X-Cacheable = "YES";
}
unset resp.http.x-url;
unset resp.http.x-host; }
apache /etc/httpd/conf.d/wordpress.co.kr.conf
<VirtualHost *:8000>
ServerName 172.16.21.222
DocumentRoot /var/www/html/wordpress
ErrorLog /var/log/httpd/mywordpress-error-log
CustomLog /var/log/httpd/mywordpress-acces-log combined
<Directory /var/www/html/wordpress>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
varnishlog -g request -q "ReqUrl eq '/'"
* << Request >> 7
- Begin req 6 rxreq
- Timestamp Start: 1658301976.240571 0.000000 0.000000
- Timestamp Req: 1658301976.240571 0.000000 0.000000
- ReqStart 172.16.39.62 4667 a0
- ReqMethod GET
- ReqURL /
- ReqProtocol HTTP/1.1
- ReqHeader Host: 172.16.21.222
- ReqHeader Connection: keep-alive
- ReqHeader Upgrade-Insecure-Requests: 1
- ReqHeader User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
- ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
- ReqHeader Accept-Encoding: gzip, deflate
- ReqHeader Accept-Language: ko
- ReqHeader X-Forwarded-For: 172.16.39.62
- VCL_call RECV
- ReqUnset Host: 172.16.21.222
- ReqHeader Host: 172.16.21.222
- ReqURL /
- VCL_return hash
- ReqUnset Accept-Encoding: gzip, deflate
- ReqHeader Accept-Encoding: gzip
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 8 fetch
- Timestamp Fetch: 1658301976.348547 0.107975 0.107975
- RespProtocol HTTP/1.1
- RespStatus 301
- RespReason Moved Permanently
- RespHeader Date: Wed, 20 Jul 2022 07:26:16 GMT
- RespHeader Server: Apache/2.4.37 (rocky)
- RespHeader X-Powered-By: PHP/7.2.24
- RespHeader X-Redirect-By: WordPress
- RespHeader Location: http://172.16.21.222:8000/
- RespHeader Content-Length: 0
- RespHeader Content-Type: text/html; charset=UTF-8
- RespHeader x-url: /
- RespHeader x-host: 172.16.21.222
- RespHeader X-Cacheable: YES:Forced
- RespHeader X-Varnish: 7
- RespHeader Age: 0
- RespHeader Via: 1.1 varnish (Varnish/6.0)
- VCL_call DELIVER
- RespUnset x-url: /
- RespUnset x-host: 172.16.21.222
- VCL_return deliver
- Timestamp Process: 1658301976.348631 0.108059 0.000084
- RespHeader Connection: keep-alive
- Timestamp Resp: 1658301976.348669 0.108098 0.000038
- ReqAcct 416 0 416 354 0 354
- End
** << BeReq >> 8
-- Begin bereq 7 fetch
-- VCL_use boot
-- Timestamp Start: 1658301976.240807 0.000000 0.000000
-- BereqMethod GET
-- BereqURL /
-- BereqProtocol HTTP/1.1
-- BereqHeader Upgrade-Insecure-Requests: 1
-- BereqHeader User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
-- BereqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
-- BereqHeader Accept-Language: ko
-- BereqHeader X-Forwarded-For: 172.16.39.62
-- BereqHeader Host: 172.16.21.222
-- BereqHeader Accept-Encoding: gzip
-- BereqHeader X-Varnish: 8
-- VCL_call BACKEND_FETCH
-- VCL_return fetch
-- BackendOpen 30 boot.default 172.16.21.222 8000 172.16.21.222 11024
-- BackendStart 172.16.21.222 8000
-- Timestamp Bereq: 1658301976.241097 0.000290 0.000290
-- Timestamp Beresp: 1658301976.348336 0.107528 0.107239
-- BerespProtocol HTTP/1.1
-- BerespStatus 301
-- BerespReason Moved Permanently
-- BerespHeader Date: Wed, 20 Jul 2022 07:26:16 GMT
-- BerespHeader Server: Apache/2.4.37 (rocky)
-- BerespHeader X-Powered-By: PHP/7.2.24
-- BerespHeader X-Redirect-By: WordPress
-- BerespHeader Location: http://172.16.21.222:8000/
-- BerespHeader Content-Length: 0
-- BerespHeader Content-Type: text/html; charset=UTF-8
-- TTL RFC 120 10 0 1658301976 1658301976 1658301976 0 0 cacheable
-- VCL_call BACKEND_RESPONSE
-- BerespHeader x-url: /
-- BerespHeader x-host: 172.16.21.222
-- TTL VCL 3600 10 0 1658301976 cacheable
-- BerespHeader X-Cacheable: YES:Forced
-- VCL_return deliver
-- Storage malloc s0
-- Fetch_Body 0 none -
-- BackendReuse 30 boot.default
-- Timestamp BerespBody: 1658301976.348518 0.107711 0.000182
-- Length 0
-- BereqAcct 428 0 428 251 0 251
-- End
The issue you're experiencing is related to a Host header mismatch.
Your VSL log shows that you're sending the following Host header:
- ReqHeader Host: 172.16.21.222:6081
This is the result of calling http://172.16.21.222:6081. However, you're WordPress setup doesn't recognize that host and redirects to the host it knows, which is 172.16.21.222:8000.
You can see that it redirects to this host in the following log line:
- RespHeader Location: http://172.16.21.222:8000/
You shouldn't be using port numbers in your Host header. I would advise you to change the default listening port of varnishd from 6081 to 80.
See https://www.varnish-software.com/developers/tutorials/installing-varnish-ubuntu/#4-configure-varnish for more information on how to change the listening port via systemd.
Please also ensure that port 8080 is not included in the WordPress base URL. Just use the IP address or a domain name instead.
For the time being you could bypass the port mismatch by overriding your Host header. Here's an example using cUrl:
curl -H"Host: 172.16.21.222:8000" -I http://172.16.21.222:6081
This command will override the host to 172.16.21.222:8000 while still accessing Varnish over 172.16.21.222:6081.
If this works, change the varnishd port to 80 and updated the WordPress base URL to not include the port.

Varnish 5, serve cache objects if backend is down

I'm using varnish 5.2.1.
I have configured VCL for grace mode. If TTL expire, object enter in grace mode if backend is down. It's ok.
But, this not work if I ban or purge object.
If I purge or ban, and backend is down, varnish show me the 503 error and not object saved in grace.
Can you help for use grace mode if user ban or purge objects ?
I have implemented grace mode and soft purge in varnish 5.2 with article https://www.getpagespeed.com/server-setup/varnish/varnish-5-2-grace-mode
All works great, but, for example, if I use use wordpress with Varnish HTTP Purge plugin (https://it.wordpress.org/plugins/varnish-http-purge/), when I purge specific url/article, all works, but If I request purge entire cache, not work.
I think the problem is beacuse request is a regex ... for url "/.*"
On varnishlog I see this request:
<< Request >> 163874
Begin req 163873 rxreq
Timestamp Start: 1517991657.640832 0.000000 0.000000
Timestamp Req: 1517991657.640832 0.000000 0.000000
ReqStart 10.0.1.100 37454
ReqMethod PURGE
ReqURL /.*
ReqProtocol HTTP/1.1
ReqHeader host: test.local
ReqHeader User-Agent: WordPress/4.9.4; http://test.local
ReqHeader Accept: /
ReqHeader Accept-Encoding: deflate, gzip
ReqHeader Referer: http://10.0.3.250/.*
ReqHeader X-Purge-Method: regex
ReqHeader Connection: close
ReqHeader X-Forwarded-For: 10.0.1.100
VCL_call RECV
VCL_acl MATCH purge_acl "10.0.1.100"
VCL_return hash
ReqUnset Accept-Encoding: deflate, gzip
ReqHeader Accept-Encoding: gzip
VCL_call HASH
VCL_return lookup
VCL_call MISS
ReqHeader purged: 0
VCL_return synth
Timestamp Process: 1517991657.640916 0.000084 0.000084
RespHeader Date: Wed, 07 Feb 2018 08:20:57 GMT
RespHeader Server: Varnish
RespHeader X-Varnish: 163874
RespProtocol HTTP/1.1
RespStatus 404
RespReason Not Found
RespReason Not Found
VCL_call SYNTH
RespHeader purged: 0
VCL_return deliver
RespHeader Content-Length: 0
Storage malloc Transient
RespHeader Connection: close
Timestamp Resp: 1517991657.641034 0.000201 0.000118
ReqAcct 206 0 206 148 0 148
End
There is no solution for keeping graced objects if you use BAN (since they are freed immediately) but for PURGE you can make use of soft purge functionality (which will keep the object in the cache despite setting TTL to 0).
Varnish 5.2 comes with purge module for that purpose (hard vs soft purges).
So you will need to implement it in your VCL:
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge_acl) {
return (synth(405));
}
return (hash);
}
}
sub my_purge {
set req.http.purged = purge.soft();
if (req.http.purged == "0") {
return (synth(404));
}
else {
return (synth(200));
}
}
sub vcl_hit {
if (req.method == "PURGE") {
call my_purge;
}
}
sub vcl_miss {
if (req.method == "PURGE") {
call my_purge;
}
}
sub vcl_synth {
if (req.method == "PURGE") {
if (req.http.purged) {
set resp.http.purged = req.http.purged;
}
return (deliver);
}
}
More information can be found here: Implementing grace mode in Varnish 5.2.

Get varnish to proxy and not redirect

I want to use Varnish as a "smart" proxy and it almost works. The idea is that some requests should be passed through Varnish, hit the backend and return, all other requests should return a "synt" message that the specific response contains no result.
This works apart from the fact that Varnish returns a 301 redirect to the backend instead of just the response from the actual backend.
Backend and Cache are not located on the same host (or not even on the same network in this case).
Backend is ALSO running a separate Varnish instance and this request is always passed through that.
// VCL.SHOW 0 1820 input
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.
# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;
### Here starts my part of the VCL
# Default backend definition. Set this to point to your content server.
backend default {
.host = "myhost.mydomain";
.port = "80";
}
sub vcl_recv {
# Happens before we check if we have this in cache already.
#
# Typically you clean up the request here, removing cookies you don't need,
# rewriting the request, etc.
if (req.url ~ "^\/cgi-bin\/wspd_cgi\.sh/apiFlightSearch.p\?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27")
{
return (hash);
}
return (synth(750));
}
sub vcl_synth {
if (resp.status == 750) {
# Set a status the client will understand
set resp.status = 200;
# Create our synthetic response
set resp.http.content-type = "text/xml";
synthetic("<flights xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><status><status>No flights</status></status></flights>");
return(deliver);
}
}
sub vcl_backend_response {
# Happens after we have read the response headers from the backend.
#
# Here you clean the response headers, removing silly Set-Cookie headers
# and other mistakes your backend does.
set beresp.ttl = 10 s;
}
sub vcl_deliver {
# Happens when we have all the pieces we need, and are about to send the
# response to the client.
#
# You can do accounting or modifying the final object here.
}
### Here ends my part of the VCL. The rest I guess is built in.
// VCL.SHOW 1 5479 Builtin
/*-
* Copyright (c) 2006 Verdens Gang AS
* Copyright (c) 2006-2014 Varnish Software AS
* All rights reserved.
*
* Author: Poul-Henning Kamp <phk#phk.freebsd.dk>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* The built-in (previously called default) VCL code.
*
* NB! You do NOT need to copy & paste all of these functions into your
* own vcl code, if you do not provide a definition of one of these
* functions, the compiler will automatically fall back to the default
* code from this file.
*
* This code will be prefixed with a backend declaration built from the
* -b argument.
*/
vcl 4.0;
#######################################################################
# Client side
sub vcl_recv {
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 || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
return (hash);
}
sub vcl_pipe {
# By default Connection: close is set on all piped requests, to stop
# connection reuse from sending future requests directly to the
# (potentially) wrong backend. If you do want this to happen, you can undo
# it here.
# unset bereq.http.connection;
return (pipe);
}
sub vcl_pass {
return (fetch);
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (lookup);
}
sub vcl_purge {
return (synth(200, "Purged"));
}
sub vcl_hit {
if (obj.ttl >= 0s) {
// A pure unadultered hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
// Object is in grace, deliver it
// Automatically triggers a background fetch
return (deliver);
}
// fetch & deliver once we get the result
return (fetch);
}
sub vcl_miss {
return (fetch);
}
sub vcl_deliver {
return (deliver);
}
/*
* We can come here "invisibly" with the following errors: 413, 417 & 503
*/
sub vcl_synth {
set resp.http.Content-Type = "text/html; charset=utf-8";
set resp.http.Retry-After = "5";
synthetic( {"<!DOCTYPE html>
<html>
<head>
<title>"} + resp.status + " " + resp.reason + {"</title>
</head>
<body>
<h1>Error "} + resp.status + " " + resp.reason + {"</h1>
<p>"} + resp.reason + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"} );
return (deliver);
}
#######################################################################
# Backend Fetch
sub vcl_backend_fetch {
return (fetch);
}
sub vcl_backend_response {
if (beresp.ttl <= 0s ||
beresp.http.Set-Cookie ||
beresp.http.Surrogate-control ~ "no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store|private") ||
beresp.http.Vary == "*") {
/*
* Mark as "Hit-For-Pass" for the next 2 minutes
*/
set beresp.ttl = 120s;
set beresp.uncacheable = true;
}
return (deliver);
}
sub vcl_backend_error {
set beresp.http.Content-Type = "text/html; charset=utf-8";
set beresp.http.Retry-After = "5";
synthetic( {"<!DOCTYPE html>
<html>
<head>
<title>"} + beresp.status + " " + beresp.reason + {"</title>
</head>
<body>
<h1>Error "} + beresp.status + " " + beresp.reason + {"</h1>
<p>"} + beresp.reason + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + bereq.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"} );
return (deliver);
}
#######################################################################
# Housekeeping
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
Output from curl:
$ curl "thisandthatip.compute.amazonaws.com/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0" -i
HTTP/1.1 301 Moved Permanently
Date: Wed, 15 Mar 2017 07:14:11 GMT
Server: Apache/2.2.15 (Red Hat)
Location: http://myserver.mydomain/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
Content-Length: 514
Content-Type: text/html; charset=iso-8859-1
X-Varnish: 529144137
Via: 1.1 varnish-v4
X-Varnish: 98309 11
Age: 2
Via: 1.1 varnish-v4
Connection: keep-alive
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved here.</p>
<hr>
<address>Apache/2.2.15 (Red Hat) Server at thisandthatip.eu-central-1.compute.amazonaws.com Port 80</address>
</body></html>
Backend apache access log
127.0.0.1 - - [15/Mar/2017:08:09:49 +0100] "GET /cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=arn&to=aok&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0 HTTP/1.1" 200 994 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
Sending the request from the AWS instance to the backend renders no 301 redirection:
$ curl "myserver.mydomain/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=arn&to=aok&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0" -i
HTTP/1.1 200 OK
Date: Wed, 15 Mar 2017 08:54:14 GMT
Server: Apache/2.2.15 (Red Hat)
Cache-Control: max-age=1
Expires: Wed, 15 Mar 2017 08:54:15 GMT
Content-Type: text/xml
X-Varnish: 527559784
Age: 0
Via: 1.1 varnish-v4
Transfer-Encoding: chunked
Connection: keep-alive
Accept-Ranges: bytes
... Response body here ...
Complete varnishlog output of a single request
* << BeReq >> 98314
- Begin bereq 98313 fetch
- Timestamp Start: 1489568144.701450 0.000000 0.000000
- BereqMethod GET
- BereqURL /cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
- BereqProtocol HTTP/1.1
- BereqHeader Host: thisandthatip.compute.amazonaws.com
- BereqHeader Upgrade-Insecure-Requests: 1
- BereqHeader User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
- BereqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- BereqHeader Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4
- BereqHeader X-Forwarded-For: ip.ip.ip.ip
- BereqHeader Accept-Encoding: gzip
- BereqHeader X-Varnish: 98314
- VCL_call BACKEND_FETCH
- VCL_return fetch
- BackendClose 17 default(ip.ip.ip.ip,,80) toolate
- BackendOpen 17 default(ip.ip.ip.ip,,80) 172.31.31.195 42868
- Backend 17 default default(ip.ip.ip.ip,,80)
- Timestamp Bereq: 1489568144.730329 0.028878 0.028878
- Timestamp Beresp: 1489568144.759773 0.058322 0.029444
- BerespProtocol HTTP/1.1
- BerespStatus 301
- BerespReason Moved Permanently
- BerespHeader Date: Wed, 15 Mar 2017 08:55:44 GMT
- BerespHeader Server: Apache/2.2.15 (Red Hat)
- BerespHeader Location: http://myserver.mydomain/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
- BerespHeader Content-Length: 514
- BerespHeader Content-Type: text/html; charset=iso-8859-1
- BerespHeader X-Varnish: 526644873
- BerespHeader Age: 0
- BerespHeader Via: 1.1 varnish-v4
- BerespHeader Connection: keep-alive
- TTL RFC 120 -1 -1 1489568145 1489568145 1489568144 0 0
- VCL_call BACKEND_RESPONSE
- TTL VCL 10 10 0 1489568145
- VCL_return deliver
- Storage malloc s0
- ObjProtocol HTTP/1.1
- ObjStatus 301
- ObjReason Moved Permanently
- ObjHeader Date: Wed, 15 Mar 2017 08:55:44 GMT
- ObjHeader Server: Apache/2.2.15 (Red Hat)
- ObjHeader Location: http://myserver.mydomain/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
- ObjHeader Content-Length: 514
- ObjHeader Content-Type: text/html; charset=iso-8859-1
- ObjHeader X-Varnish: 526644873
- ObjHeader Via: 1.1 varnish-v4
- Fetch_Body 3 length stream
- BackendReuse 17 default(ip.ip.ip.ip,,80)
- Timestamp BerespBody: 1489568144.759849 0.058398 0.000076
- Length 514
- BereqAcct 578 0 578 415 514 929
- End
* << Request >> 98313
- Begin req 98312 rxreq
- Timestamp Start: 1489568144.701372 0.000000 0.000000
- Timestamp Req: 1489568144.701372 0.000000 0.000000
- ReqStart ip.ip.ip.ip 63485
- ReqMethod GET
- ReqURL /cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
- ReqProtocol HTTP/1.1
- ReqHeader Host: thisandthatip.compute.amazonaws.com
- ReqHeader Connection: keep-alive
- ReqHeader Upgrade-Insecure-Requests: 1
- ReqHeader User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
- ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- ReqHeader Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4
- ReqHeader X-Forwarded-For: ip.ip.ip.ip
- VCL_call RECV
- VCL_return hash
- ReqUnset Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Encoding: gzip
- VCL_call HASH
- VCL_return lookup
- Debug "XXXX MISS"
- VCL_call MISS
- VCL_return fetch
- Link bereq 98314 fetch
- Timestamp Fetch: 1489568144.759883 0.058511 0.058511
- RespProtocol HTTP/1.1
- RespStatus 301
- RespReason Moved Permanently
- RespHeader Date: Wed, 15 Mar 2017 08:55:44 GMT
- RespHeader Server: Apache/2.2.15 (Red Hat)
- RespHeader Location: http://myserver.mydomain/cgi-bin/wspd_cgi.sh/apiFlightSearch.p?from=ARN&to=AOK&date=2017-05-20&homedate=2017-05-27&adults=2&triptype=return&children=0&infants=0
- RespHeader Content-Length: 514
- RespHeader Content-Type: text/html; charset=iso-8859-1
- RespHeader X-Varnish: 526644873
- RespHeader Via: 1.1 varnish-v4
- RespHeader X-Varnish: 98313
- RespHeader Age: 0
- RespHeader Via: 1.1 varnish-v4
- VCL_call DELIVER
- VCL_return deliver
- Timestamp Process: 1489568144.759907 0.058535 0.000024
- Debug "RES_MODE 2"
- RespHeader Connection: keep-alive
- Timestamp Resp: 1489568144.759933 0.058561 0.000026
- Debug "XXX REF 2"
- ReqAcct 566 0 566 454 514 968
- End
Varnish 4.0.4 running on AWS Amazon Linux.
The 301 redirect is not done by your varnish. It is done by an apache server probably your backend. It can be seen by the X-Server header in your curl.
What varnish does is proxify the request and forward it to the backend you declare myhost.mydomain. In fact Varnish will resolve the dns at startup and forward the request to the ip it got.
I see two things to check here :
ban your request from your varnish cache (it may result in a 301 at some time during your test and still be cached, that does not serm to be the case but better start from fresh cache)
Make a curl to your backend to see if you get a 301 or a 200.
If that does not work I would restart your varnish service to refresh the dns resolution.
The Host header entry sent to the backend matched that of the AWS instance. That triggered a redirect in the backend, not in the Varnish cache.
Overriding the http.resp.host value in Varnish solved the problem:
sub vcl_recv {
# Happens before we check if we have this in cache already.
#
# Typically you clean up the request here, removing cookies you don't need,
# rewriting the request, etc.
# Set req.http.host (Host header) to www.airtours.se otherwise a redirect will be triggered
set req.http.host = "myserver.mydomain";
... More setting goes here
}

Varnish request missing cache despite being in

I have this request in the Varnish cache:
ReqMethod GET
ReqURL /organisation/xyz/proposal_0000000/comments/comment_0000001/
Some PURGE requests are then send to Varnish, resulting in this list of bans:
ban.list
200 2108
Present bans:
1458150360.937187 16 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/team0000000$
1458150360.929092 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz$
1458150360.926030 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/pitch0000000$
1458150360.923491 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/practicalrelevance0000000$
1458150360.921025 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/plan0000000$
1458150360.918480 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/target0000000$
1458150360.915931 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/duration0000000$
1458150360.913486 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/difference0000000$
1458150360.910710 0 - req.http.host == localhost:8088 && req.url ~ /$
1458150360.908150 0 - req.http.host == localhost:8088 && req.url ~ /organisation$
1458150360.906249 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/extrainfo0000000$
1458150360.904289 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/connectioncohesion0000000$
1458150360.901930 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/challenge0000000$
1458150360.899287 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/goal0000000$
1458150360.896989 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/partners0000000$
1458150360.894324 0 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000$
1458150360.891701 0 C
1458150348.035639 1 C
The same GET request is then executed again but with a MISS:
* << Request >> 32790
- Begin req 32789 rxreq
- Timestamp Start: 1458150371.759282 0.000000 0.000000
- Timestamp Req: 1458150371.759282 0.000000 0.000000
- ReqStart 127.0.0.1 43526
- ReqMethod GET
- ReqURL /organisation/xyz/proposal_0000000/comments/comment_0000001/
- ReqProtocol HTTP/1.1
- ReqHeader Host: localhost:8088
- ReqHeader Connection: keep-alive
- ReqHeader Pragma: no-cache
- ReqHeader Cache-Control: no-cache
- ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
- ReqHeader Upgrade-Insecure-Requests: 1
- ReqHeader Referer: http://localhost:8088/organisation/xyz/proposal_0000000/comments/?elements=paths
- ReqHeader Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
- ReqHeader X-Forwarded-For: 127.0.0.1
- VCL_call RECV
- VCL_return hash
- ReqUnset Accept-Encoding: gzip, deflate, sdch
- ReqHeader Accept-Encoding: gzip
- VCL_call HASH
- VCL_return lookup
- ExpBan 3 banned lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 32791 fetch
- Timestamp Fetch: 1458150371.779571 0.020289 0.020289
- RespProtocol HTTP/1.1
- RespStatus 200
- RespReason OK
- RespHeader Server: gunicorn/19.2.1
- RespHeader Date: Wed, 16 Mar 2016 17:46:11 GMT
- RespHeader X-Caching-Mode: with_proxy_cache
- RespHeader X-Caching-Strategy: HTTPCacheStrategyWeakAdapter
- RespHeader Cache-Control: max-age=0, proxy-revalidate, s-maxage=31104000
- RespHeader Vary: Accept-Encoding, X-User-Path, X-User-Token
- RespHeader Content-Type: application/json; charset=UTF-8
- RespHeader Access-Control-Allow-Origin: *
- RespHeader Access-Control-Allow-Methods: POST,GET,DELETE,PUT,OPTIONS
- RespHeader Access-Control-Allow-Headers: Origin, Content-Type, Accept, X-User-Path, X-User-Token
- RespHeader ETag: W/"0|1|2016-03-16 13:44:05.887212+00:00|None|None"
- RespHeader Content-Encoding: gzip
- RespHeader X-Varnish: 32790
- RespHeader Age: 0
- RespHeader Via: 1.1 varnish-v4
- VCL_call DELIVER
- VCL_return deliver
- Timestamp Process: 1458150371.779598 0.020317 0.000028
- RespHeader Accept-Ranges: bytes
- RespHeader Content-Length: 426
- Debug "RES_MODE 2"
- RespHeader Connection: keep-alive
- Timestamp Resp: 1458150371.779641 0.020359 0.000042
- ReqAcct 598 0 598 699 426 1125
- End
The ban list ist then:
ban.list
200 147
Present bans:
1458150360.937187 17 - req.http.host == localhost:8088 && req.url ~ /organisation/xyz/proposal_0000000/team0000000$
I know regular expressions. How can /organisation/xyz/proposal_0000000/comments/comment_0000001/ matches any of the pattern in the ban.list? It does not make sense.
I'm using Varnish 4.1.1
The rule that matches your URL is:
1458150360.910710 0 - req.http.host == localhost:8088 && req.url ~ /$
regex req.url ~ /$ will match your URL and any other that ends with a slash; use req.url ~ ^/$.
A few observations:
you should use "==" direct comparasion since you know the full URL https://www.varnish-cache.org/docs/3.0/reference/varnish-cli.html#ban-expressions
use varnishtest to debug complex situations
try to be lurker-friendly
About lurker-friendly ban expressions
read more here
Lurker-friendly ban expressions are those that use only obj., but not req. variables. Since lurker-friendly ban expressions lack of req., you might need to copy some of the req. contents into the obj structure. In fact, this copy operation is a mechanism to preserve the context of client request in the cached object. For example, you may want to copy useful parts of the client context such as the requested URL from req to obj.
The following snippet shows an example on how to preserve the context of a client request in the cached object:
sub vcl_backend_response {
set beresp.http.x-url = bereq.url;
}
sub vcl_deliver {
# The X-Url header is for internal use only
unset resp.http.x-url;
}
Varnish test example for regex:
You can run it with: varnishtest test_regex.vtc
test_regex.vtc content:
# act like a backend server
server s1 {
rxreq
txresp
expect req.url == "/organisation/xyz/proposal_0000000/comments/comment_0000001/"
expect req.http.Test == "dosent_match"
} -start
# define & start a varnish instance
varnish v1 -vcl {
backend default {
.host = "${s1_addr}";
.port = "${s1_port}";
}
sub vcl_recv {
if ( req.url ~ "/$" ) {
set req.http.Test="match";
} else {
set req.http.Test="dosent_match";
}
}
} -start
# make a client request
client c1 {
txreq -url "/organisation/xyz/proposal_0000000/comments/comment_0000001/"
rxresp
} -run
varnish v1 -expect client_req == 1

Resources