Sep 162014
 

Par défaut, si vous utilisez la configuration en malloc sans option, varnish crée un espace de stockage nommé s0 en ram.
Mais vous pouvez utiliser plusieurs stockages en ram ou sur disque pour garantir des performances en fonction de votre besoin.
Par exemple, pour qu’un site ne remplisse par le cache et impacte sur un autre :
– Dans le fichier /etc/default/varnish

DAEMON_OPTS="
...
-s default=malloc,64m \
-s foo=malloc,128M \
-s bar=malloc,128M \
..."

– Dans vcl_backend_response (4.0) :

if (bereq.http.host ~ "foo") {
       set beresp.storage_hint = "foo";
} else if (bereq.http.host ~ "bar") {
       set beresp.storage_hint = "bar";
} else {
       set beresp.storage_hint = "default";
}

ou vcl_fetch (3.0) :

if (req.http.host ~ "foo") {
       set beresp.storage = "foo";
} else if (req.http.host ~ "bar") {
       set beresp.storage = "bar";
} else {
       set beresp.storage = "default";
}

Par exemple, en fonction du TTL :
– Dans le fichier /etc/default/varnish

DAEMON_OPTS="
...
-s ram=malloc,1G \
-s disk=file,/space/varnish/storage,10G \
..."

– Dans vcl_backend_response (4.0) ou vcl_fetch (3.0) :

sub vcl_backend_response {
       # default storage
       set beresp.storage = "ram";
...
       if (beresp.ttl > 86400s) {
              set beresp.storage = "disk";
       }
}
Avr 102014
 

Nouvelle version majeur de varnish :
https://www.varnish-cache.org/content/varnish-cache-400

Pour l’installer :

curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add -
echo 'deb http://repo.varnish-cache.org/debian/ wheezy varnish-4.0' >> /etc/apt/sources.list.d/varnish.list
apt-get update
apt-get install varnish

Un fichier de configuration pour débuter :

# Varnish 4
vcl 4.0;
# Backend par defaut
backend default {
        .host = "127.0.0.1";
        .port = "81";
        .connect_timeout = 1s;
        .first_byte_timeout = 30s;
        .probe = {
                .url = "/";  # ou .request = "GET / HTTP/1.1" "Host: blog.jeremm.fr" "Connection: close";
                .timeout  = 15s;
                .interval = 15s;
                .window    = 5;
                .threshold = 2;
        }
}
sub vcl_recv {
        # Defini le backend
        set req.backend_hint = default ;
        # Pipe directement au backend pour les requetes non HTTP
        if (req.method != "GET" &&
                req.method != "HEAD" &&
                req.method != "PUT" &&
                req.method != "POST" &&
                req.method != "TRACE" &&
                req.method != "OPTIONS" &&
                req.method != "DELETE") {
                return (pipe);
        }
        # Ne pas cacher pour les requetes HTTP qui ne sont pas des simples demandes GET 
        if (req.method != "GET" && req.method != "HEAD") {
                return (pass);
        }
        # Enleve les cookies sur les medias pour que le hash match tous les clients
        if (req.url ~ "\.(jpeg|jpg|png|gif|ico|swf|js|css|gz|rar|txt|bzip|pdf)(\?.*|)$" && req.url !~ "^/index.php?") {
                unset req.http.Cookie;
                return (hash);
        }
        # Ne pas cacher pour les parties avec authentification
        if (req.http.Authorization) {
                return (pass);
        }
        return (hash);
}
sub vcl_hash {
        hash_data(req.url);
        if (req.http.host) {
                hash_data(req.http.host);
        } else {
                hash_data(server.ip);
        }
        if (req.http.Cookie) {
                hash_data(req.http.Cookie);
        }
        return(lookup);
}
sub vcl_pass {
        set req.http.X-marker = "pass" ;
}
sub vcl_backend_response {
        # Gzip tous les objets
        if ( ! beresp.http.Content-Encoding ~ "gzip" ) {
                set beresp.do_gzip = true;
        }
        # Efface le set-cookie sur les medias
        if (bereq.url ~ "\.(jpeg|jpg|png|gif|ico|swf|js|css|gz|rar|txt|bzip|pdf)(\?.*|)$" && bereq.url !~ "^/index.php?") {
                unset beresp.http.set-cookie;
        }
        # Cache les redirections et ne cache pas les 404
        if (beresp.ttl > 0s ) {
                if (beresp.status >= 300 && beresp.status <= 399) {
                        set beresp.ttl = 10m;
                }
                if (beresp.status >= 399) {
                        set beresp.ttl = 0s;
                }
        }
        # Efface le set-cookie sur les 404 & Cie
        if (beresp.status >= 399) {
                unset beresp.http.set-cookie;
        }
        # Maximum 24h de cache
        if (beresp.ttl > 86400s) {
                set beresp.ttl = 86400s;
        }
        # Marqueur pour l'entete HTTP de la reponse
        if (bereq.http.X-marker == "pass" ) {
                unset bereq.http.X-marker;
                set beresp.http.X-marker = "pass";
                set beresp.ttl = 0s ;
        }
        # Ne pas cacher si il y a encore un set-cookie
        if (beresp.ttl > 0s && beresp.http.set-cookie) {
                set beresp.ttl = 0s ;
        }
}
sub vcl_deliver {
        # Ajout et nettoyage de l'entete HTTP de la reponse
        if (obj.hits > 0){
                set resp.http.X-Varnish-Cache = "HIT";
        } else {
                set resp.http.X-Varnish-Cache = "MISS";
        }
        if (resp.http.X-marker == "pass" ) {
                unset resp.http.X-marker;
                set resp.http.X-Varnish-Cache = "PASS";
        }
        unset resp.http.Via;
        unset resp.http.X-Varnish;
        unset resp.http.Server;
        unset resp.http.X-Powered-By;
}
sub vcl_synth {
        if (resp.status >= 500 && req.restarts < 4) {
                return (restart);
        }
}

Téléchargeable ici : http://blog.jeremm.fr/default.4.0.vcl

Maj 25/06/2014 : Ajout de commentaires dans la conf
Maj 22/02/2014 : Retrait des règles X-Forwarded-For natif en version 4

Oct 182013
 

Pour limiter le nombre de requêtes par IP, vous pouvez installer le vmod throttle.
Voici le fichier compilé pour varnish 3.0.4 à placer sous debian dans /usr/lib/varnish/vmods :
libvmod_throttle.so.3.0.4.tar
MAJ : Voici le fichier compilé pour varnish 3.0.5 à placer sous debian dans /usr/lib/varnish/vmods :
libvmod_throttle.so.3.0.5.tar
MAJ : Voici le fichier compilé pour varnish 3.0.3 à placer sous debian dans /usr/lib/varnish/vmods :
libvmod_throttle.so.3.0.3.tar
Il faut ensuite ajouter dans la configuration en premier lieu:

import throttle;

puis dans le vcl_recv :

if(throttle.is_allowed("ip:" + client.ip, "20req/s") > 0s) {
        error 429 "Calm down";
}

Vous pouvez préciser plusieurs ratios entre les guillemets :

20req/s, 200req/30s, 1000req/5m, 2000req/h

Les unités de temps possibles sont : s,m,h,d

Vous pouvez exclure des IPs en utilisant une acl :

acl allowIP {
        "127.0.0.1";
}
 
sub vcl_recv {
        if (!client.ip ~ allowIP) {
                if(throttle.is_allowed("ip:" + client.ip, "20req/s") > 0s) {
                        error 429 "Calm down";
                }
        }
}

Vous pouvez aussi changer comment il applique le ratio, par exemple par user-agent :

if(throttle.is_allowed(req.http.user-agent, "20req/s") > 0s) {

On peut aussi appliquer le ratio que sur les miss par ip par exemple :

sub vcl_miss {
    if(req.url !~ "\.(jpg|jpeg|png|gif|ico|swf|css|js|html|htm)$") {
         if(throttle.is_allowed("miss:" + client.ip, "20req/s") > 0s) {
               error 429 "Calm down";
         }
    }
}

Lien : https://github.com/nand2/libvmod-throttle

Sep 262013
 

Pour modifier le ttl avec un ratio, il faut ajouter un bout de C :
Au début de la configuration :

C{
        #include <string.h>
        #include <stdlib.h>
        void TIM_format(double t, char *p);
        double TIM_real(void);
}C

Dans le vcl_fetch :

if (beresp.ttl > 0s ) {
        C{
                double obj_ttl = VRT_r_beresp_ttl(sp);
                double ratio = 0.9;
                double new_ttl = obj_ttl*ratio;
                VRT_l_beresp_ttl(sp, new_ttl);
        }C
}

Pour vérifier, vous pouvez ajouter la ligne suivante à la fin du vcl_fetch :

set beresp.http.X-Varnish-TTL = beresp.ttl;
Fév 072013
 

L’ESI (Edge Side Includes) est supporté par Varnish. C’est un language de balisage HTML permettant d’assembler une page dynamique.
Cela permet de cacher avec différents temps en cache ou de ne pas cacher, différents bloc d’une page.
Par exemple :
ESI
On peut définir le temps de cache avec le header « Cache-Control : max-age » ou directement dans la configuration varnish.
Voici une page d’exemple :
– index.php :

<?php
        header('Cache-Control: max-age=3600');
?>
<title>Page de test ESI</title>
<html><body>
        Cette page est cach&eacute;e pourtant j'arrive &agrave; afficher l'heure :
        <esi:include src="/dyn/date.php"/>
</body></html>

– date.php :

<?php
        header('Cache-Control: max-age=0');
        echo date('Y-m-d H:i:s');
?>

Il faut activer l’ESI dans la configuration varnish :

sub vcl_fetch {
        set beresp.do_esi = true;

Si vous avez un panier, il faut pouvoir identifier les utilisateurs avec une session php.
Si il y a une session php, elle ne peut pas être définit par la page cachée : il faudra donc la générer autrement :

<script type='text/javascript' src="/dyn/sessions.php"></script>

– sessions.php :

<?php
        session_start();
?>

Pour que tous les utilisateurs reçoivent la page commune cachée et qu’elle reste dynamique en fonction des utilisateurs il faut enlever la session des cookies pour les pages/parties communes et la laisser pour les pages/parties individuelles.
Dans la configuration varnish :

if ( ! req.url ~ "^/dyn" ) {
        set req.http.Cookie = regsuball(req.http.Cookie, "PHPSESSID=[^;]+(; )?", "");
        if (req.http.Cookie ~ "^$") {
            unset req.http.Cookie;
        }

On peut tester avec cette page :
– index.php :

<?php
        header('Cache-Control: max-age=3600');
?>
<title>Page de test ESI</title>
<html><body>
        Cette page est cach&eacute;e pourtant j'arrive &agrave; afficher l'heure :
        <esi:include src="/dyn/date.php"/>
        <br>Ainsi que l'ID de session : <esi:include src="/dyn/phpsess.php"/>
        <script type='text/javascript' src="/dyn/sessions.php"></script>
</body></html>

– phpsess.php :

<?php
        header('Cache-Control: max-age=0');
        echo $_COOKIE["PHPSESSID"];
?>

Le résultat : http://blog.jeremm.fr/esi/
A la première visite vous n’avez pas de session, elle ne sera donc pas affichée.