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.

Jan 232013
 

Une configuration basique de varnish :

# 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 {
   set req.grace = 300s;
   set req.backend = default ;
   if (req.restarts == 0) {
      if (req.http.x-forwarded-for) {
          set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
      } else {
          set req.http.X-Forwarded-For = client.ip;
      }
   }
   if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
        return (pipe);
   }
   if (req.request != "GET" && req.request != "HEAD") {
       return (pass);
   }
   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 (lookup);
   }
   if (req.http.Authorization) {
       return (pass);
   }
   return (lookup);
}
 
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(hash);
}
sub vcl_pass {
        set req.http.X-marker = "pass" ;
}
sub vcl_fetch {
        if ( ! beresp.http.Content-Encoding ~ "gzip" ) {
                set beresp.do_gzip = true;
        }
        if (req.url ~ "\.(jpeg|jpg|png|gif|ico|swf|js|css|gz|rar|txt|bzip|pdf)$") {
                unset beresp.http.Set-Cookie;
        }
        if (beresp.ttl > 0s ) {
                  if (beresp.status >= 300 && beresp.status <= 399) {
                        set beresp.ttl = 10m;
                  }
                  if (beresp.status >= 399) {
                        set beresp.ttl = 0s;
                  }
        }
        if (beresp.status >= 399) {
                unset beresp.http.Set-Cookie;
        }
        # Maximum 24h de cache
        if (beresp.ttl > 86400s) {
                set beresp.ttl = 86400s;
        }
        if (req.http.X-marker == "pass" ) {
                unset req.http.X-marker;
                set beresp.http.X-marker = "pass";
                set beresp.ttl = 0s ;
        }
        if (beresp.ttl > 0s && beresp.http.Set-Cookie) {
                set beresp.ttl = 0s ;
        }
}
 
sub vcl_deliver {
        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" ) {
                remove resp.http.X-marker;
                set resp.http.X-Varnish-Cache = "PASS";
        }
        remove resp.http.Via;
        remove resp.http.X-Varnish;
        remove resp.http.Server;
        remove resp.http.X-Powered-By;
 }
 
sub vcl_error {
        if (obj.status >= 500 && req.restarts < 4) {
                return (restart);
        }
}

Pour télécharger directement le fichier default.vcl : default.vcl

Pour les options de démarrage : Configuration et optimisation du daemon Varnish

Maj 06/03/12 : ajout du X-marker pass
Maj 16/04/12 : ajout req.grace
Maj 19/08/12 : téléchargement du fichier default.vcl / don’t hash Accept-Encoding
Maj 03/09/12 : unset set-cookie sur media, pas de unset cookie sur media commençant par /index.php?, unset Set-cookie sur 404
Maj 23/01/13 : add set beresp.do_gzip = true ;

Jan 192013
 

Varnish ne supporte pas le https, si vous voulez quand même l’utiliser il faut mettre un autre reverse-proxy devant qui supporte le https.
On peut utiliser pound.
– Installation :

apt-get install pound

– Activation :

sed -i 's/startup=0/startup=1/' /etc/default/pound

– Configuration /etc/pound/pound.cfg :

## see pound(8) for details
 
User            "www-data"
Group           "www-data"
 
LogLevel        0
 
Alive           30
TimeOut 120
ConnTO 5
Grace 120
 
Control "/var/run/pound/poundctl.socket"
 
## listen, redirect and ... to:
ListenHTTPS
        Address 0.0.0.0
        Port    443
        Cert    "/etc/ssl/blog.jeremm.fr.pem"
        xHTTP           0
        AddHeader "X-Forwarded-Proto: https"
        Service
                BackEnd 
                        Address 127.0.0.1
                        Port    80
                End
                Session
                        Type IP
                        TTL 60
                End
        End
End

– Le fichier pem doit contenir dans l’ordre : la clé privée, le certificat, le certificat de l’autorité de certification.
– Au niveau du backend, il faut mettre l’ip et le port où se trouve le varnish.
– Définissez plusieurs blocs Backend pour load-balancer les requêtes sur 2 varnishs.

Au niveau du varnish, ajoutez dans le vcl_recv :

if (!req.http.x-forwarded-proto) {

et

}

autour du bloc qui ajoute le X-Forwarded-For car il est déjà ajouté par pound.

Ajoutez ensuite dans le vcl_hash :

if (req.http.x-forwarded-proto) {
        hash_data(req.http.x-forwarded-proto);
}

Ensuite au niveau du code il faut que les liens et appels à d’autres objets (images,css,js,…) se fassent en https.
Souvent les codes php le font déjà en détectant le protocole grâce à

$_SERVER['HTTPS'] ou $_SERVER['SERVER_PORT']

Il faut utiliser le

$_SERVER['HTTP_X_FORWARDED_PROTO'])

Ou ajouter sur le vhost apache2 :

SetEnvIf X-Forwarded-Proto https HTTPS on

P.S. (20/01/2013) : La version 2.5 de pound fournie par les dépôts squeeze semble avoir une fuite mémoire. Préférez la version 2.6 qu’il faudra compiler http://www.apsis.ch/pound/Pound-2.6.tgz

Jan 132013
 

Si vos sites ne sont pas parcourus régulièrement, les pages ne seront plus dans votre cache varnish, vous pourriez augmenter le ttl de vos pages mais si vous mettez à jour régulièrement vos sites cela peut être embêtant.
La solution, créer un cron qui parcours votre site avec ce script :

#!/bin/bash
 
Sitemap='www.exemple.com/sitemap.xml'
Site='www.exemple.com'
wget='/usr/bin/wget'
grep='/bin/grep'
awk='/usr/bin/awk'
find='/usr/bin/find'
mount='/bin/mount'
umount='/bin/umount'
sed='/bin/sed'
wc='/usr/bin/wc'
cut='/usr/bin/cut'
 
if [ `$mount -l | $grep /tmp/wget | $wc -l` -gt 0 ] ; then exit 1 ; fi
 
touch /tmp/cookies.txt
$wget -q -O /dev/null "URL pour régénérer le sitemap"
 
if [ ! -d /tmp/wget ] ; then
   mkdir /tmp/wget
fi
 
$mount -t tmpfs -o size=25M tmpfs /tmp/wget
cd /tmp/wget
 
for site in $Sitemap ; do
   for url in `$wget -q -O - "http://$site" | $grep '<loc>'  | $awk -F'<loc>' '{print $2}' | $awk -F'</loc>' '{print $1}'` ; do
      $wget -q -p --save-cookies /tmp/cookies.txt --load-cookies /tmp/cookies.txt "$url"
      for index in `$find . -type f | $sed 's:^./::' | $grep index.html` ; do
            for href in `$grep href "$index" | $cut -d"'" -f2 | $cut -d'"' -f2 | $grep http | $grep "$Site"` ; do
                  $wget -q -p --save-cookies /tmp/cookies.txt --load-cookies /tmp/cookies.txt --header='Accept-Encoding: gzip, deflate' "$href"
                  $wget -q -p --header='Accept-Encoding: gzip, deflate' "$href"
            done
      done
      for file in `$find . -type f | $sed 's:^./::' | $grep -v index.html` ; do
          $wget -q -O /dev/null  --save-cookies /tmp/cookies.txt --load-cookies /tmp/cookies.txt --header='Accept-Encoding: gzip, deflate' "http://$file"
          $wget -q -O /dev/null  --header='Accept-Encoding: gzip, deflate' "http://$file"
      done
      for file in `$find . -type f | $sed 's:^./::' | $grep index.html | $sed 's:index.html::'` ; do
          $wget -q -O /dev/null  --save-cookies /tmp/cookies.txt --load-cookies /tmp/cookies.txt --header='Accept-Encoding: gzip, deflate' "http://$file"
          $wget -q -O /dev/null  --header='Accept-Encoding: gzip, deflate' "http://$file"
      done
      rm -rf /tmp/wget/*
   done
done
rm /tmp/cookies.txt
cd /tmp/ ; $umount /tmp/wget ; rm -rf /tmp/wget

Maj 13/01/12 : Ajout href