Varnish Configuration Language: pezzi di VCL

Se siete finiti su questa pagina, probabilemente e’ perche’ siete alla ricerca di VCL da copiare ed incollare nella vostra configurazione.
Probabilmente avete gia’ provato altri pezzi di VCL, ma non hanno funzionato come vi aspettavate. Se questo e’ il caso, allora questo blog e’ per voi.
Le linee di VCL qui sotto riportate sono state tutte testate ripetutamente, ergo sono pronte per essere usate da voi.

  1. ACL and Purge

    # Who is allowed to purge
    acl local {
      “Localhost”;
      “192.168.1.0”/24; /* and everyone on the local network */
      ! “192.168.1.23”; /* except for the dialin router */
    }
        
    sub vcl_recv {
      if (req.method == “PURGE”) {
        if (client.ip ~ local) {
          return(purge);
        } else {
          return(synth(403, “Access  denied”));
        }
      } 
    }

  2. Authentication

    sub vcl_recv {
      if (req.http.authstatus) {
        unset req.http.authstatus;
      }
    
      if (req.http.signature) {
        set req.http.sig-verf = digest.hmac_sha256("key", req.http.host);
          if (req.http.sig-verf == req.http.signature) {
            set req.http.authstatus = "ok";
          }
      }
    
      if (req.http.authstatus == "ok") {
        # implement your logic for authenticated users
        return(synth(200, "ok"));
      } else {
        # implement your logic for unauthenticated users
        return(synth(401, "not ok"));
      }
    }

  3. Stale-while-revalidate

    sub vcl_hit {
      if (obj.ttl >= 0s) {
        # normal hit
        return (deliver);
      }
      # 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 {
          # No candidate for grace. Fetch a fresh object.
          return(fetch);
         }
      } else {
        # backend is sick - use full grace
        if (obj.ttl + obj.grace > 0s) {
          set req.http.grace = "full";
          return (deliver);
        } else {
          # no graced object.
          return (fetch);
        }
      }
    }

  4. Stale-if-error

    sub try_stale_if_error {
      if (obj.ttl < 0s && obj.ttl + obj.grace > 0s) {
        if (req.restarts == 0) {
          set req.http.sie-enabled = true;
          return (fetch);
        } else {
          set req.http.sie-abandon = true;
          return (deliver);
        }
      }
    }
    
    sub vcl_backend_fetch {
      if (bereq.http.sie-abandon) {
        return (abandon);
      }
    }
    
    sub vcl_backend_response {
      if (beresp.status > 400 && bereq.http.sie-enabled) {
        return (abandon);
      }
    }
    
    sub vcl_backend_error {
      if (bereq.http.sie-enabled) {
        return (abandon);
      }
    }
    
    sub vcl_synth {
      if (resp.status == 503 && req.http.sie-enabled) {
        unset req.http.sie-enabled;
        return (restart);
      }
    }
    
    sub vcl_hit {
      call try_stale_if_error;
    }

  5. Redirect to a permanent or temporary location

    sub vcl_recv {
      unset req.http.location;
    
      if (req.url ~ "/permanent") {
        set req.http.location = "https://new.example.com" + req.url;
        return(synth(301));
      }
    
      if (req.url ~ "/temporary") {
        set req.http.location = "https://temporary.example.com" + req.url;
        return(synth(302));
      }
    }
    
    sub vcl_synth {
      # Permanent redirect
      if (resp.status == 301) {
        set resp.http.Location = req.http.location;
        return (deliver);
      }
    
      # Temporary redirect
      if (resp.status == 302) {
        set resp.http.Location = req.http.location;
        return (deliver);
       }
    }

Questo blog post e’ stato originariamente scritto qui: https://info.varnish-software.com/blog/varnish-configuration-language-vcl-snippets

Annunci

VCL per saintmode e grace-Varnish Cache 4.1

Allora, senza troppi fronzoli perche’ immagino che chi sia arrivato qui abbia bisogno di un pezzo di VCL da copiare ed incollare nel proprio VCL file…ecco qui:

vcl4.0;
import directors;
sub vcl_init {

 # we create two saint-mode backends
new sm1 = saintmode.saintmode(server1, 5);
new sm2 = saintmode.saintmode(server2, 5);
#we group the backends in the same cluster
new fb = directors.fallback();
fb.add_backend(sm1.backend());
fb.add_backend(sm2.backend());
}

sub vcl_backend_fetch {
set bereq.backend = fb.backend();
}

sub vcl_backend_response {
#we set both TTL and grace values which will be used by the default vcl_hit subroutine
set beresp.ttl = 1s;
set beresp.grace = 10s;
if (beresp.status > 500) {
#the failing backend is blacklisted and we try to fetch content from another server
saintmode.blacklist(5s);
return (retry);
}
}

Per chi fosse interessato ad approfondire un po’ l’argomento, ecco qui un riassunto veloce:
Una delle capacita’ di Varnish Cache e’ sempre stata quella di gestire al meglio dei backend servers che si comportano maluccio e che non sono completamente affidabili.
La soluzione usata da sempre e’ combianare Saint Mode e Grace mode.

Saint mode:

Saint mode permette di gestire al meglio backend servers che “falliscono” per specifiche richieste. Il concetto e’ facile: esiste una blacklist per ogni backend, il backend viene segnato come “sick” per le richieste che non riesce a gestire per un determinato periodo di tempo. Varnish, di tutta risposta, cerca di servire contenuto un prendendolo da un altro web server oppure po’ piu’ vecchio(stale content).

Grace mode:

Grace mode ordina a Varnish di servire del contenuto anche se il suo TTL e’ espirato, questa modalita’ e’ indispensabile quando i backends non sono considerati “healthy” e non sono in grado di servire contenuto nuovo e fresco.

In Varnish 3.0 saint mode era una core feature, la stessa non e’ stata presente in Varnish 4.0, ma ha fatto il suo ritorno(a grande richiesta) in Varnish 4.1.

Come sempre, scusate per lo scarso italiano e se avete domande scrivete pure :))

5 cose da considerare quando si migra da Varnish 3 a Varnish 4

Varnish Cache 3.0 (il progetto open source) e´ stato rilasciato nel 2011 mentre Varnish Cache 4.0 e` arrivato nel 2014. Dopodiche´ e` arrivato Varnish Cache 4.1.x ed ora anche Varnish Cache 5.0.

Varnish Cache 3.0 e´ arrivato alla sua EOL, quindi non e´piu´ aggiornato/mantenuto. Questo significa che se state ancora utilizzando la versione 3.0 dovete decisamente aggiornarvi e questo blog post e´per voi.

Il motivo per cui spiego i cambiamenti fra Varnish 3.0 e 4.0 e´perche´ fra queste due versioni sono avvenuti cambiamenti molto importanti che hanno visto un totale rifacimento dell’architettura di Varnish Cache. Se capite cose e´successo fra la versione 3.0 e la versione 4.0, allora sarete anche in grado di capire tutte le versioni piu´giovani della 4.0.

  • Threading model:  in Varnish Cache 3.0 vi era un unico thread per ogni client, il thread in questione si occupava di prendere il contenuto dalla cache o dai server e di consegnarlo al client.
    In Varnish 4.0 ci sono due threads: uno per il client e uno per il backend/server. Questo cambiamento ha portato ad un’enorme guadagno dal punto di vista della performance dando la possibilita’ di servire del contenuto un po’ “vecchio” al cliente mentre il contenuto piu’ nuove viene preso da un “background fetch”.
  • VCL: come risultato importante del nuovo threading model, a partire da Varnish Cache 4.0 nel VCL workflow ci sono routines che sono strettamente riferite al backend thread:
    • vcl_backend_fetch
    • vcl_backend_response
    • vcl_backend_error
  • Grace behaviour:  prima di Varnish 4.0 tutti i backends dovevano essere considerati “sick” prima che Varnish potesse usare un oggetto “stale”(raffermo) per completare una richiesta da un client. A partire da Varnish 4.0 e’ presente il supporto nativo per implementare il concetto di stale-while-revalidate che significa che Varnish, se non trova contenuto “fresco”, allora servira´contenuto un po’ stale(raffermo).
    Ecco il VCL:
    sub vcl_hit {
    if (obj.ttl >= 0s) {
    # fresh object present in cache
    # normal hit
    return (deliver);
    }
    # We have no fresh objects. Let’s look at the stale ones
    if (std.healthy(req.backend_hint)) {
    # Backend is healthy. Limit age to 10s
    # A background fetch is triggered to fetch a fresh object.
    if (obj.ttl + 10s > 0s) {
    set req.http.grace = “normal(limited)”;
    return (deliver);
    } else {
    # No candidate for grace. Fetch a fresh object.
    return(fetch);
    }
    } else {
    # backend is sick – use full grace
    # a background fetch is triggered to try to fetch fresh content
    if (obj.ttl + obj.grace > 0s) {
    set req.http.grace = “full”;
    return (deliver);
    } else {
    # no graced object.
    return (fetch);
    }
    }
    }
  • Directors: In Varnish Cache 3.0 una “director” non era altro che un gruppo di backends da cui Varnish poteva scegliere per prendere il contenuto da inserire in cache.
    A partire da Varnish 4.0, per rendere tutta la logica intorno al modo di selezionare backend piu´semplice,  il concetto di director e´stato spostato in un VMOD(Varnish Module) cosi´puoi avere la liberta´di sviluppare la tua personale logica in base a cui Varnish scegliera´i backend.
  • Purge: In Varnish 3.0 vi era la parola chiave “purge” per eliminare contenuto in cache. Ora, a partire da Varnish 4.0 la parola purge e´stata ritirata, ma e´invece possibile invalidare elementi cache via VCL:
    sub vcl_recv {

    if (req.method == “PURGE”) {
    return(purge);
    }
    }
    Piu´informazioni:https://www.varnish-software.com/plus/varnish-cache-plus/

Redirect HTTP to HTTPS usando Varnish 4.x

Utilizzando Varnich Cache puoi redirigere il traffico HTTP ad HTTPS che utilizza SSL/TLS.
Varnish di default non è in grado di “capire ” richieste HTTPS, quindi avrai bisogno anche un SSL Terminator(Hitch è quello consigliato in quanto si integra perfettamente con Varnish:https://hitch-tls.org/).

Ecco qui il VCL che devi utilizzare:

 

sub vcl_recv {
        if ( (req.http.host ~ "www.example.com" && req.http.X-Forwarded-Proto !~ "https") {
                return (synth(750, "Redirect to HTTPS"));
        }
}

sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.Location = "https://www.example.com" + req.url;
        return(deliver);
    }
}

Installare Varnish su Mac OS X-El capitan

Premessa: sto per scrivere questo post con la tastiera scandinava, ergo niente lettere accentate. Usero´ apostrofi al posto di accenti. L´accademia della Crusca mi perdoni!

Mi e´ arrivato il nuovo giochino: un Mac! Dopo anni di Linux, sto lentamente imparando le shortcut di OS X.
Ad ogni modo, il blog di oggi e´ su come installare Varnish Cache da source su un qualsiasi OS X. Molto probabilmente se siete finiti qui e´ perché gia´ sapete cos´e´ Varnish e come funziona, ma se non lo sapeste: https://www.varnish-cache.org

Bando alle ciance, installare Varnish da source code su OS-X e´  po´challenging, vediamo come si fa.

PREREQUISITI:

  • Installate brew: ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
  • Installate autoconf: brew install autoconf
  • Installate python: brew install python
  • Installate python docutils (per rst2man): pip install python
  • Installate pcre (perl compatible regular expression): brew install pcre
  • Installate pkg-config: brew install pkg-config
  • Installate libtool: brew install libtool

Mi raccomando seguite quest´ordine perche´ ad esempio rst2man (python docutils) puo´ essere installato solo se python e´ gia´ presente.

COMPILARE E INSTALLARE VARNISH:

Innanzitutto bisogna clonare la repo di Varnish-Cache da github:

git clone https://github.com/varnishcache/varnish-cache.git

Ora, dovrete fare un checkout sulla versione che volete installare, per esempio io voglio installare Varnish 4.1, quindi faro´:

git checkout 4.1

Ora, che tutto e´pronto potete pure fare l´installazione vera e propria:

  • ./autogen.sh
  • ./configure
  • make
  • make install

Make potrebbe darvi dei problemi, almeno a me ne ha dati perche´ rst2man lanciava questo errore: “ValueError: unknown locale: UTF-8 in Python”.

La soluzione a questo e´ facile:

  • export LC_ALL=en_US.UTF-8
  • export LANG=en_US.UTF-8

Per convenienza, se dovere reinstallare varnish diverse volte al giorno, potreste aggiungere i due punti sopra nella vostra ~/.bash_profile.

A questo punto avreste varnish installato 🙂
Reach me out se avete domande.

 

Libvmod-rtstatus: metriche, statistiche e vari numeri di Varnish in tempo reale.

Sono felice di introdurre un nuovo VMOD che colleziona counters e statistiche di Varnish in un JSON file e mostra questi dati tramite un’ user interface. Se vuoi sapere in tempo reale come Varnish e backends stanno lavorando, allora questo e’ il VMOD che devi usare. Questo VMOD ti permette di avere un’overview di alcuni counters di Varnish dedicando particolare attenzione a quelli relativi ai backends e alle statistiche per backend. Trovo che tutto cio’ sia assolutamente fantastico soprattutto se usi Varnish come load balancer e vuoi sapere che transazione stanno avvenendo e come Varnish sta performando.

Il VMOD si trova qui: https://github.com/varnish/libvmod-rtstatus.

Il VMOD ha due funzioni:

  • rtstatus(REAL delta): questa e la funzione responsabile della creazione del JSON file contente counters, statistiche ed altri numeri. Il parametro delta viene utilizzato per calcolare hitrate e request load, questi sono valutati su basi differenziali.

json

  • html(): il JSON file creato dalla sopracitata funzione viene passato a questa funzione che lo utilizza per creare una UI.

frontend

Riguardo quest’ultima funzione vorrei aggiungere che si tratta di un c-wrapper per un’applicazione HTML/Javascript. Questa applicazione viene presentata a Varnish come una grande stringa che poi viene utilizzata per generare un synthetic object in vcl_synth. La UI proposta nel VMOD e’ quella di default, ma puo’ essere modificata a secondo delle esigenze.
Per utilizzare il VMOD dovresti scrivere nel tuo VCL qualcosa del genere:

import rtstatus;

sub vcl_recv {
        if (req.url ~ "/rtstatus.json") {
                return(synth(700, "OK"));               }
        if (req.url ~ "/rtstatus") {
                return(synth(800, "OK"));
        }
}
sub vcl_synth {
        if (resp.status == 700){
                set resp.status = 200;
                set resp.http.Content-Type = "text/plain; charset=utf-8";
                synthetic(rtstatus.rtstatus(5));
                return (deliver);
        }
        if (resp.status == 800) {
                set resp.status = 200;
                set resp.http.Content-Type = "text/html; charset=utf-8";
                synthetic(rtstatus.html());
                return (deliver);
                }
}

Varnish come load balancer e sessioni “sticky”.

Versione originale di questo blog post (in inglese): https://www.varnish-software.com/blog/proper-sticky-session-load-balancing-varnish – scritto da Per Buer.

Assumiamo che state usando varnish come load balancer e che la vostra web application abbia necessità di mantenere determinati “dati”(ad es. un cookie_hdr)finchè la sessione è attiva. Ora, per evitare che uno user acceda a dati destinati ad un altro user, bisogna che Varnish sappia cosa sta succedendo e che una determinata sessione è relativa ad un determinato user. In pratica vogliamo che un visitatore che torna abbia tutte le volte lo stesso application server.

La soluzione è facile: basta generare una random string prima che al client(aka user che ha fatto la richiesta) venga assegnato un backend. Dopodichè bisogna rendere “persistente” la stringa generate, usando un cookie, e assicurarsi che venga ri-letta da uno user che “ritorna” sulla pagina.

Ecco il VCL d’esempio:

vcl 4.0;
import std;
import directors;
import cookie;
import header;

backend s1 {
        .host = "127.0.0.1";
        .port = "8080";
}
backend s2 {
        .host = "127.0.0.1";
        .port = "9090";

}

sub vcl_init {
    new cdir = directors.hash();
    cdir.add_backend(s1,1);
    cdir.add_backend(s2,1);
}

sub vcl_recv {
    cookie.parse(req.http.cookie);
    if (cookie.get("sticky")) {
        set req.http.sticky = cookie.get("sticky");
    } else {
        # The cookies will have floats in them. 
        # Whatever, ehh, floats your boat can be used.
        set req.http.sticky = std.random(1, 100);
    }
    # use to be client.identity in V3
    set req.backend_hint = cdir.backend(req.http.sticky);
}

sub vcl_deliver {
    # persist the cookie
    # we need to use the header vmod as there might be a set-cookie 
    # header on the object already and
    # we don't want to mess with it
    if (req.http.sticky) {
        header.append(resp.http.Set-Cookie,"sticky=bar" + req.http.sticky + "; Expires=" + cookie.format_rfc1123(now, 60m));
    }
}