nginx

Mon réseau

Ça faisait un petit moment que je devais refaire ma homepage. C'est chose faite (rechargez la page si vous avez encore l'ancienne en cache, c'est full statique avec un trèèèès long ttl).

J'y décris un peu ce qui se passe dans les trois serveurs que j'administre, pour moi, pour les amis, pour des logiciels libres comme wmfs et pour les causes que je défends avec une association, le cerf de grésigne et un miroir wikileaks.

En modifiant ma map nagios j'ai réussi à faire quelque chose de pas mal pour mieux visualiser la chose :

network

Ça fait maintenant deux ans que l'aventure a commencée, objectif auto-hébergement et auto-formation à l'administration systèmes. Je dois dire que ça a plutôt bien marché puisque l'infrastructure et mes connaissances n'ont cessés de progresser.

  • Fin 2008 Pendant les 3 premiers mois philpep.org n'existait que sur mon portable (sous gentoo, allumé 24h/24), c'était un serveur git pour partager mon code.
  • Début 2009 j'ai récupéré un vieux pentium III gracieusement donné par une association Toulousaine sur lequel j'ai installé FreeBSD (7.0 puis 7.1) qui a commencé à faire du mail.
  • Mai 2009 je récupère un pentium 4 avec plus de RAM.
  • Fin 2009 je m'achète une alix2d3
  • Début 2010 je prends une machine virtuelle chez lost-oasis (sous FreeBSD puis Debian) pour fournir un MX et DNS secondaire.
  • Juillet 2010 je m'achète une nouvelle machine avec plus de RAM et qui consomme moins
  • Fin 2010, la machine virtuelle est maintenant chez Hetzner, et sous FreeBSD 8.1 avec un vpn entre mes deux locations.

Faire son CDN perso avec nginx

date
15 / 10 / 2010
comments
0

Dans ce billet je vais expliquer comment j'ai mis en place un petit CDN (Content Delivery Network) pour servir du contenu statique (images/css/javascript).

Le problème :

  • Avec une connexion 800kbs envoyer des images ça peut prendre du temps.
  • Sur les sites dynamiques, l'application web envoie souvent des cookies valides pour le domaine en question. Du coup le client envoie son cookie quand il demande le contenu statique du site dynamique, c'est une perte de temps.

La solution :

  • Mettre le contenu statique sur un domaine propre.
  • Plusieurs serveurs peuvent servir ce contenu statique, ainsi le client peut faire des requêtes sur plusieurs serveurs à la fois.

Les moyens que j'ai :

  • Un serveur à Toulouse qui contient les applications dynamiques et le contenu statique (la source), servi par de multiples jails FreeBSD avec un nginx en reverse proxy. aldo.philpep.org
  • Un serveur chez lost-oasis à Marseille, qui fait uniquement du MX et DNS secondaire. d.philpep.org

L'idée

L'idée est dont de servir le contenu statique des sites suivant par mes deux serveurs, sur un domaine sans cookie :

Step one: static.philpep.org

J'ai configuré le domaine avec nginx, pour qu'il serve le contenu statique sur static.philpep.org/$host/$uri

Par exemple http://static.philpep.org/blog.philpep.org/static/ouverta/style.css doit servir http://blog.philpep.org/static/ouverta/style.css.

Pour ça je me suis pas cassé la tête, dans /usr/local/data j'ai des liens symboliques vers le virtual root de chaque virtual host (les dossier étant des points de montage pour les jails FreeBSD qui servent le contenu dynamique)

(phil@aldo.philpep.org ~) % ls -l /usr/local/data/
total 26
drwxr-xr-x  3 root  wheel  212 Oct 14 16:40 awstats
drwxr-xr-x  5 root  wheel    5 Sep 12 02:33 banach
lrwxr-xr-x  1 root  wheel   23 Oct 14 16:41 blog.philpep.org -> cantor/blog.philpep.org
drwxr-xr-x  7 root  wheel    8 Sep 28 15:00 bolzano
drwxr-xr-x  5 root  wheel    5 Oct 14 16:36 cantor
lrwxr-xr-x  1 root  wheel   25 Oct 14 16:40 cerf-gresigne.org -> bolzano/cerf-gresigne.org
lrwxr-xr-x  1 root  wheel   21 Oct 14 16:40 dl.philpep.org -> banach/dl.philpep.org
lrwxr-xr-x  1 root  wheel   19 Oct 14 16:40 dl.wmfs.info -> banach/dl.wmfs.info
drwxr-xr-x  3 root  wheel    4 Oct 14 16:36 fourier
lrwxr-xr-x  1 root  wheel   19 Oct 14 16:41 oujevipo.fr -> bolzano/oujevipo.fr
lrwxr-xr-x  1 root  wheel   18 Oct 14 16:40 philpep.org -> banach/philpep.org
lrwxr-xr-x  1 root  wheel   22 Oct 14 17:09 projects.philpep.org -> fourier/redmine/public
lrwxr-xr-x  1 root  wheel   21 Oct 14 16:41 sica.vaour.net -> cantor/sica.vaour.net
lrwxr-xr-x  1 root  wheel    7 Oct 14 16:40 stats.philpep.org -> awstats
lrwxr-xr-x  1 root  wheel   27 Oct 14 16:41 webmail.philpep.org -> bolzano/webmail.philpep.org
lrwxr-xr-x  1 root  wheel   22 Oct 14 17:09 wmfs.info -> fourier/redmine/public

Et la conf nginx qui va avec :

server {
    listen 80;
    server_name static.philpep.org;
    location ~* \.(ico|png|jpg|jpeg|gif|css|js)$ {
        root /usr/local/data/;
        expires 10y; # 10 ans
        add_header Cache-Control public;
    }
}

Un petit coup de bind pour créer static.philpep.org et ça marche.

Step two: configurer les applications

C'est la partie la plus difficile. Suivant comment est codée l'application ça peut être très long à faire.

  • Pour le blog c'est fait maison et j'avais prévu le coup.
  • Pour redmine facile aussi grâce à au framework rails : il faut mettre ActionController::Base.asset_host = "static.philpep.org/projects.philpep.org" dans config/environments/production.rb
  • Pour dotclear il y a des options dans about:config, le problème c'est les plugins qui ne l'utilisent pas.
  • Pour joomla c'est l'horreur ! J'ai du mettre un preg_replace avec une regexp horrible pour faire du remplacement sur toute la chaine retournée par php.

Step three: nginx cache sur d.philpep.org

Il faut configurer nginx pour faire du proxy cache de static.philpep.org, en gros si le contenu demandé n'est pas dans le cache nginx demande au serveur source aldo.philpep.org, il met en cache et le renvoie au client.

http {

    proxy_cache_path "/usr/local/www/cache/static" levels=1:1:2 keys_zone=STATIC:1000m inactive=1y max_size=1g;
    # Cache pendant 1 an, avec une taille inférieure à 1G.

    upstream aldo {
        server 82.229.137.130:80;
    }
    server {
        listen 80;
        server_name static.philpep.org;
        location ~* \.(ico|png|jpg|jpeg|gif|css|js)$ {
            proxy_pass http://aldo;
            proxy_set_header Host $host;
            proxy_cache_key "$request_uri";
            proxy_cache STATIC;
        }
    }
}

Step four : DNS

static IN A 82.229.137.130 ; aldo.philpep.org
static IN A 212.85.155.53 ; d.philpep.org

Et après ?

  • Regardez votre cache se remplir, et les sites qui sont plus rapides à charger.
  • Configurez nginx pour qu'il fasse de la compression gzip sur le css et le javascript.
  • Regardez comme la configuration du cache est simple, on peut facilement rajouter un noeud dans le cdn.