Catégories
Blog Open-source Systeme vitualisation

Varnish, NGinx et PHP-FPM sous Docker

Suite au précédent article d’introduction sur Docker (que je vous conseille de lire avant de dévorer cet article), je me suis penché sur le problème suivant: comment créer et maintenir une « stack web » de compétition (Varnish + Nginx + PHP-FPM) basée sur cette technologie de virtualisation par conteneurs.

Quel est l’objectif ?

Nous allons donc, dans ce billet, détailler l’installation et la mise à jour d’une infrastructure, basée sur Docker, qui pourra servir à l’hébergement d’un site personnel, d’un blog ou bien du site d’une PME:

  • la base de donnée sera portée par l’implémentation libre de MySQL, c’est à dire MariaDB (nous aborderons cette partie dans un deuxième billet)
  • pour le moteur PHP, j’utilise PHP-FPM
  • pour le serveur Web, je ne jure que par Nginx (léger, bien documenté)
  • afin pour tenir la charge (notamment si vous utilisé un moteur de blog de type WordPress, j’utilise le système de cache Varnish)LEMP (Docker)

Dans le reste de de l’article, on appellera machine hôte, la machine qui hébergera Docker (lire ce billet pour la procédure d’installation de Docker).

Cette dernière peut être un PC portable ou bien un serveur dédié. C’est un des avantages de la virtualisation par conteneurs. Une fois validé sur une machine , on est sûr que le conteneur fonctionnera de manière identique sur une autre installation de Docker. Ainsi pour la rédaction de ce billet, j’ai utiisé mon PC portable sous Ubuntu 14.04 et un (superbe) VPS mis à disposition par les amis de Web4All sous Debian 7 (merci Aurélien !).

Pour respecter la philosophie de la virtualisation par conteneur, chaque brique sera mise dans un conteneur dédié. On aura ainsi 4 conteneurs sur une machine hôte.

Chaque conteneur communiquera avec les autres selon le schéma ci-dessus.

Les données (data base DB, page statique du site et cache) seront stockées sur la machine hôte.

Création des conteneurs

Il y a deux méthodes pour choisie les images qui seront à la base de nos conteneurs.

La première, la plus noble mais la plus longue à mettre en œuvre, est d’écrire soit même les DockersFiles permettant l’installation et l’exécution des logiciels. On garde ainsi le contrôle de notre infrastructure et la possibilité de configurer finement les applications (notamment au niveau des options de compilation). Dans ce cas, et pour respecter les « best practices » de Docker, il faudra, pour chaque conteneur, repartir d’une image de base de type Debian sur laquelle on viendra installer les briques logicielles de notre LEMP.

La seconde, que j’ai choisi dans ce billet (pas parce-que je suis un gros fainéant mais par manque de temps), est de partir des images disponibles sur la registry officielle de Docker. On gagne ainsi en rapidité de mise en place.  Les composants de notre web stack étant très populaires, on trouve des images supportées et maintenues par la communauté Docker (notamment NGinx). Cependant, on constatera une trop grande diversité dans les systèmes de bases (Ubuntu, CentOS…).

Avant de commencer, nous allons créer un répertoire sur la machine hôte qui hébergera les fichiers utiles à notre infrastructure:

mkdir -p $HOME/data/webstack/conf $HOME/data/webstack/www

Le conteneur NGinx

Pierre angulaire de notre « web stack« , le serveur NGinx est très présent sur la « registry » officielle de Docker (plus de 900 images disponibles au moment de l’écriture de ce billet). J’ai choisi d’utiliser l’image officielle proposé par Docker (elle est conçue à partir de cete DockerFile).

On commence par télécharger les images NGinx officielle:

docker pull nginx

Puis on vérifie que les images sont visibles sur notre machine hôte (NGinx version 1.7.5 au moment de l’écriture de cet article):

$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
nginx 1.7.5 d2d79aebd368 7 days ago 100.2 MB
nginx latest d2d79aebd368 7 days ago 100.2 MB
nginx 1 d2d79aebd368 7 days ago 100.2 MB
nginx 1.7 d2d79aebd368 7 days ago 100.2 MB

On lance le conteneur:

$ docker run --name webstack_nginx_1 -v $HOME/data/webstack/www:/usr/share/nginx/html:ro -p 8080:80 -d nginx
f7baa81cebdc8799947327e6470a74ae73fe73bb0eb644ecfb2951847c40154b

Notre conteneur a le doux nom de webstack_nginx_1, il redirige le port TCP/8080 de notre hôte vers le port TCP/80 du conteneur (port par défaut de NGinx) et il assigne, en lecture seule, le volume /usr/share/nginx/html au répertoire hôte $HOME/data/www (à adapter à votre configuration). Pour résumer, toutes les pages HTML disponible dans le répertoire /home/nicolargo/data/www, seront accessible via le port HTTP/8080 de votre machine locale.

On ajoute une page HTML statique de test et une autre pour le test PHP que l’on utilisera dans le chapitre suivant:

echo "My first page" > $HOME/data/webstack/www/index.html
echo "<?php phpinfo(); ?>" > $HOME/data/webstack/www/phpinfo.php

Puis on valide que le serveur NGinx est bien opérationnel:

$ curl http://localhost:8080
My first page

Ou directement depuis votre navigateur Web préféré:

Sélection_245L’image NGinx utilisée redirige les fichiers de log (access.log et error.log vert la sortie standard). Il est donc possible de visualiser les accès à son serveur Web en « attachant » le terminal de notre hôte à la sortie standard du conteneur:

$ docker attach --sig-proxy=false webstack_nginx_1
2014/10/08 13:47:59 [error] 9#0: *1 open() "/usr/share/nginx/html/inconnu.html" failed (2: No such file or directory), client: 172.17.0.103, server: localhost, request: "GET /inconnu.html HTTP/1.1", host: "localhost"
172.17.0.103 - - [08/Oct/2014:13:47:59 +0000] "GET /inconnu.html HTTP/1.1" 404 168 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:32.0) Gecko/20100101 Firefox/32.0" "172.17.42.1"

Note: bien penser à mettre l’option –sig-proxy=true sous peine de stopper le conteneur lors de l’appuie sur ^C. Je vous conseille  de créer un alias dans votre shell.

Le conteneur PHP-FPM

Pour le moteur PHP, il n’existe pas d’image officielle. Mon choix s’est donc porté vers l’utilisation du repository de Jprjr basée sur une installation de PHP-FPM sous ArchLinux avec pas mal d’extensions par défaut (voir la liste dans le DockerFile).

On télécharge la dernière version des images avec:

docker pull jprjr/php-fpm

On obtient bien:

$ docker images | grep jprjr
jprjr/php-fpm          latest                 d40698b35f83        6 weeks ago         347.8 MB

On lance le conteneur:

docker run --name webstack_php_01 -p 9000:9000 -d jprjr/php-fpm

Le conteneur est configuré par défaut pour écouter sur le port TCP/9000.

Très bien, on doit donc avoir le serveur NGinx et le moteur PHP-FPM qui sont lancés dans deux conteneurs différents. On va vérifier cela avec la commande:

$ docker ps
CONTAINER ID        IMAGE                  COMMAND                CREATED             STATUS              PORTS                           NAMES
e9dd04e7ceec        jprjr/php-fpm:latest   "php-fpm -F"           13 seconds ago      Up 12 seconds       0.0.0.0:9000->9000/tcp          webstack_php_01        
f7baa81cebdc        nginx:1                "nginx -g 'daemon of   46 minutes ago      Up 46 minutes       443/tcp, 0.0.0.0:8080->80/tcp   webstack_nginx_01

Faire communiquer les deux conteneurs (NGinx & PHP-FPM)

Tout cela est très beau mais les deux conteneurs ne se connaissent pas. Il faut, pour cela, configurer le serveur NGinx pour utiliser le moteur PHP et donc que le conteneur NGinx connaisse l’adresse IP du conteneur PHP-FPM.

Heureusement, Docker propose l’option –link permettant de répondre à ce besoin. Cette option, à utiliser au moment du lancement du conteneur, va créer dynamiquement des entrées dans le fichier host et dans des variables d’environnement du conteneur, permettant ainsi à ce dernier de connaître comment joindre ses congénères.

Par exemple:

$ docker run -it -v --link webstack_php_01:webstack_php nginx /bin/bash

root@2ce3cdb8a767:/# cat /etc/hosts | grep webstack
172.17.0.5	webstack-php

root@d9ff8a80f12a:/# env | grep WEBSTACK
WEBSTACK_PHP_PORT=tcp://172.17.0.5:9000
WEBSTACK_PHP_PORT_9000_TCP=tcp://172.17.0.5:9000
WEBSTACK_PHP_PORT_9000_TCP_ADDR=172.17.0.5
WEBSTACK_PHP_PORT_9000_TCP_PORT=9000
WEBSTACK_PHP_NAME=/webstack_nginx/webstack_php
WEBSTACK_PHP_PORT_9000_TCP_PROTO=tcp

root@2ce3cdb8a767:/# exit
exit

$ docker rm `docker ps -lq`

Maintenant que l’on sait comment faire communiquer les deux conteneurs, il suffit de configurer NGinx pour rediriger les fichier .PHP vers le moteur PHP-FPM du second conteneur.

Pour cela, plusieurs solutions sont là encore possibles. La plus simple est de surcharger la configuration NGinx par défaut(nginx.conf). Sur notre hôte, nous allons créer le fichier de configuration en question:

$ docker webstack_nginx_01/etc/nginx/nginx.conf $HOME/data/webstack/conf/nginx.conf

$ vi $HOME/data/webstack/conf/nginx.conf

daemon off;

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        #error_page   500 502 503 504  /50x.html;
        #location = /50x.html {
        #    root   /usr/share/nginx/html;
        #}

        # Pass PHP scripts to PHP-FPM
        location ~* \.php$ {
            fastcgi_index   index.php;
            fastcgi_pass    webstack_php:9000;
            #fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
            include         fastcgi_params;
            fastcgi_param   SCRIPT_FILENAME    /srv/http$fastcgi_script_name;
            fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
        }    

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        location ~ /\.ht {
            deny  all;
        }
    }

}

Note:

  • « fastcgi_pass webstack_php:9000; » qui utilise donc le hostname présent dans le fichier host
  • « fastcgi_param   SCRIPT_FILENAME    /srv/http$fastcgi_script_name; » qui va permettre à PHP-FPM d’aller chercher les pages PHP dans le même volume que le serveur Nginx mais assigné au répertoire /srv/http du conteneur (c’est la configuration par défaut de notre conteneur PHP-FPM)

Revenons à notre cas. Nous souhaitons que le conteneur NGinx (nommé webstack_nginx_01) connaisse le conteneur PHP (webstack_php_01).

On commence donc par supprimer les deux conteneurs existant:

docker stop webstack_php_01 && docker rm webstack_php_01
docker stop webstack_nginx_01 && docker rm webstack_nginx_01

puis de les recréer avec l’option –link (pour le conteneur NGinx qui va initier la connexion TCP vers le moteur PHP-FPM), la nouvelle configuration de NGinx et les volumes pointant sur notre page HTML et PHP:

docker run --name webstack_php_01 -v $HOME/data/webstack/www:/srv/http:ro -p 9000:9000 -d jprjr/php-fpm
docker run --name webstack_nginx_01 -v $HOME/data/webstack/www:/usr/share/nginx/html:ro -v $HOME/data/webstack/conf/nginx.conf:/nginx.conf:ro -p 8080:80 --link webstack_php_01:webstack_php -d nginx nginx -c /nginx.conf

On teste:

$ curl http://localhost:8080/index.html
My first page

$ curl http://localhost:8080/phpinfo.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<style type="text/css">
...

Sélection_246

Bingo !

A ce stade, nous avons donc deux conteneurs communiquant entre eux pour nous offrir un serveur Web compatible avec le langage PHP.

Le conteneur Varnish en frontal

Si vous suivez ce blog, vous savez tout le bien que je pense de l’utilisation du cache Varnish pour absorber la montée en charge des sites Web (sinon, vous pouvez effectuer une session de rattrapage en lisant ces articles). Nous allons donc créer un nouveau conteneur qui exposera le port TCP/80 et qui mettra en cache les pages construites par le serveur NGinx (qui est en écoute sur le port TCP/8080 si vous avez bien suivi…).

Nous allons utiliser l’image Varnish mise à disposition et maintenue par le contributeur jacksoncage.

On commence par la récupérer:

docker pull jacksoncage/varnish

Puis on vérifie qu’elle est bien disponible sur notre hôte:

$ docker images | grep jacksoncage
jacksoncage/varnish    latest                 46f0ea7021c1        8 months ago        472.2 MB

Comme il est indiqué dans la documentation de l’image, il faut écrire le fichier de configuration par défaut de Varnish (le fichier default.vcl):

$ vi $HOME/data/webstack/conf/default.vcl

backend default {
    .host = "webstack_nginx";
    .port = "80";
}

On demande donc à Varnish d’aller directement communiquer avec le conteneur NGinx via l’adresse IP webstack-nginx (rappelez-vous que le hostname est créé dynamiquement par Docker au démarrage du conteneur avec l’option –link) et sur le port TCP 80 (attention, ce n’est pas le port TCP/8080 exposé par Docker sur notre hôte mais celui vraiment utilisé par NGinx dans le conteneur).

A noter que cette configuration est à compléter, notamment si vous voulez héberger un blog sous WordPress (des exemples de fichiers de configuration sont disponibles ici). Attentinon, ces exemples sont pour Varnish 4.0, donc à adapter si la version du conteneur jacksoncage/varnish n’est pas en ligne.

Puis lancer le conteneur avec les options suivantes:

docker run --name webstack_varnish_01 -v $HOME/data/webstack/conf/default.vcl:/etc/varnish/default.vcl:ro -p 80:80 --link webstack_nginx_01:webstack_nginx -d jacksoncage/varnish

On redirige le port 80 du conteneur vers le port 80 de votre hôte (il ne doit bien sûr pas y avoir de serveur Web déjà en écoute sur ce port) puis on fait le lien entre le conteneur Varnish et le conteneur NGinx.

On vérifie que nos trois conteneurs sont lancés:

$ docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED             STATUS              PORTS                           NAMES
a1b853f1a38e        jacksoncage/varnish:latest   "/start"               4 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp              webstack_varnish_01                                                                        
c2bd3138864a        nginx:1                      "nginx -c /nginx.con   54 minutes ago      Up 54 minutes       443/tcp, 0.0.0.0:8080->80/tcp   webstack_nginx_01,webstack_varnish_01/webstack-nginx                                          
7cc072bb0df2        jprjr/php-fpm:latest         "php-fpm -F"           54 minutes ago      Up 54 minutes       0.0.0.0:9000->9000/tcp          ...

Et on teste notre serveur de cache Varnish:

$ curl -I http://localhost/index.html

HTTP/1.1 200 OK
Server: nginx/1.7.5
Content-Type: text/html
Last-Modified: Sat, 04 Oct 2014 16:30:45 GMT
ETag: "543020b5-15"
Content-Length: 21
Accept-Ranges: bytes
Date: Sun, 05 Oct 2014 15:26:47 GMT
X-Varnish: 320901887 320901884
Age: 46
Via: 1.1 varnish
Connection: keep-aliv

Le « Via: 1.1 varnish » confirme que notre infra commence à avoir de la gueule :).

En aparté, on peut d’ailleurs juger de la puissance de Varnish en lançant un simple bench tout d’abord directement sur le serveur NGinx (donc en baille-passant Varnish):

$ ab -t 30 -c 5 http://localhost:8080/

Complete requests:      7107
Requests per second:    232.24 [#/sec] (mean)
Time per request:       21.529 [ms] (mean)
Time per request:       4.306 [ms] (mean, across all concurrent requests)

Puis en faisant le même test en passant par Varnish:

$ ab -t 30 -c 5 http://localhost/

Complete requests:      50000
Requests per second:    3694.60 [#/sec] (mean)
Time per request:       1.353 [ms] (mean)
Time per request:       0.271 [ms] (mean, across all concurrent requests)

Les chiffres parlent d’eux même…

Gestion des conteneurs

Un simple pull sur les images préalablement téléchargé s’occupera de leurs mises à jour:

docker pull nginx
docker pull jprjr/php-fpm
docker pull jacksoncage/varnish

Comme l’on reconstruit notre infrastructure à partir de ces images, il suffira ensuite d’arrêter et de relancer les conteneurs:

docker stop webstack_varnish_01 && docker rm webstack_varnish_01
docker stop webstack_nginx_01 && docker rm webstack_nginx_01
docker stop webstack_php_01 && docker rm webstack_php_01

docker run --name webstack_php_01 -v $HOME/data/webstack/www:/srv/http:ro -p 9000:9000 -d jprjr/php-fpm
docker run --name webstack_nginx_01 -v $HOME/data/webstack/www:/usr/share/nginx/html:ro -v $HOME/data/webstack/conf/nginx.conf:/nginx.conf:ro -p 8080:80 --link webstack_php_01:webstack_php -d nginx nginx -c /nginx.conf
docker run --name webstack_varnish_01 -v $HOME/data/webstack/conf/default.vcl:/etc/varnish/default.vcl:ro -p 80:80 --link webstack_nginx_01:webstack_nginx -d jacksoncage/varnish

Note: Il est également possible de créer des images maison (avec commit + tag) et de les relancer. Cette phase peut être utile dans le cadre d’un déploiement d’une infrastructure à une autre.

Orchestration de l’infrastructure

On vient de voir que le lancement d’une infrastructure basée sur Docker peut rapidement devenir compliqué. Les conteneurs doivent être lancés dans un certain ordre, avec des options spécifiques. Il est toujours possible de scripter les commandes du chapitre précédent ou plus simplement d’utiliser un outil d’orchestration.

Vagrant vous vient en tête ? Pourtant, ce n’est pas la solution que nous allons utiliser dans ce billet.

Nous allons nous tourner vers docker-compose (anciennement Fig). C’est un logiciel en ligne de commande permettant de d’écrire son infrastructure Docker à partir d’un fichier de configuration texte au format YAML.

L’installation de Fig se fait via la commande:

sudo pip install docker-compose

Note: pour d’autre méthode d’installation, consultez la documentation sur le site officiel.

Le fichier de configuration Fig correspondant à notre infrastructure est le suivant (à éditer dans le fichier $HOME/data/webstack/docker-compose.yml):

# Webstack PHP
php:
    image: jprjr/php-fpm
    volumes:
    - www:/srv/http
    ports:
    - 9000:9000
# Webstack NGINX
nginx:
    image: nginx
    links:
    - php:webstack_php
    volumes:
    - www:/usr/share/nginx/html
    - conf/nginx.conf:/nginx.conf
    ports:
    - 8080:80
    command: nginx -c /nginx.conf
# Webstack VARNISH
varnish:
    image: jacksoncage/varnish
    links:
    - nginx:webstack_nginx
    volumes:
    - conf/default.vcl:/etc/varnish/default.vcl
    ports:
    - 80:80

On lance ensuite notre infrastructure en une seule et unique commande:

$ docker-compose up -d
Creating webstack_php_1...
Creating webstack_nginx_1...
Creating webstack_varnish_1...

Tout comme avec la ligne de commande Docker, on peut voir les conteneurs en cours d’exécution:

$ docker-compose ps
       Name                Command          State           Ports         
-------------------------------------------------------------------------
webstack_php_1                              Up      9000->9000/tcp        
webstack_nginx_1     nginx -c /nginx.conf   Up      443/tcp, 8080->80/tcp 
webstack_varnish_1   /start                 Up      80->80/tcp

Les arrêter (sans les supprimer):

$ docker-compose stop
Stopping webstack_varnish_1...
Stopping webstack_nginx_1...
Stopping webstack_php_1...

Les relancer:

$ docker-compose start
Starting webstack_php_1...
Starting webstack_nginx_1...
Starting webstack_varnish_1...

Les supprimer:

docker-compose stop && docker-compose rm

Je vous laisse découvrir les autres commandes de docker-compose sur le site officiel de la documentation.

Conclusion

Nous venons de créer les bases d’une infrastructure Web performante, facilement maintenable et évolutive. Il est ainsi facile d’y ajouter d’autres services comme une base de donnée (type MariaDB), un serveur sFTP (pour la mise à jour des pages Web) ou bien encore un outil d’analyse des logs (Varnish et NGinx).

Et de votre coté, avez-vous mis en place une infrastructure Docker pour votre serveur Web ? Si oui comment ?

Partagez votre expérience avec nous !

Catégories
Blog Open-source Planet-libre Web

Installation de NGinx avec PageSpeed sous Debian

Tous ceux qui se sont intéressés à l’optimisation du référence de leur site dans la sainte base de donnée de Google le savent bien, le temps de chargement des pages est un des facteurs clé pour en établir le classement. Google ne s’en cache plus depuis longtemps et propose toute une batterie d’outil pour identifier et optimiser la vitesse d’affichage de votre site.

Nous allons dans ce billet nous intéresser à l’optimisation de la couche basse de votre site, c’est à dire sans modification du contenu des pages, en mettant en place le module PageSpeed sur le serveur Web NGinx. J’ai utilisé un serveur sous Debian mais vous pouvez appliquer ceci, moyennant quelques adaptations, sur d’autres systèmes d’exploitations.

capture_158

PageSpeed Module ? Kesako ?

Google a  regroupé sous l’acronyme PageSpeed, un ensemble d’outils pour aider les Webmasters à optimiser leurs sites. Un des ces outil est nommé PageSpeed Module. C’est un module optionnel disponible pour les serveurs Web Apache et NGinx.

Une fois installé et configuré, ce module va, de manière dynamique et transparente, effectuer un ensemble d’optimisations lors de la mise à disposition de vos pages à vos utilisateurs. Chaque optimisation est mise en place sous la forme d’un filtre qui vont par exemple changer dynamiquement le contenu HTML de vos pages, trouver des emplacements de javascripts plus rapide ou bien optimiser les images. Comme, nous le verrons plus loin, la liste des filtres est bien sûr paramétrable au niveau des fichiers de  configuration de NGinx.

La liste complète des filtres fournis en standard par Google est disponible sur cette page.

Trêve de long discours, passons maintenant à l’installation et à la configuration de PageSpeed Module avec un serveur NGinx.

Installation de NGinx + PageSpeed Module

Vous savez tout le bien que je pense du serveur Web NGinx. J’ai donc profité de ce billet pour mettre à jour mon script d’installation automatique de NGinx afin d’y intégrer le module PageSpeed. Ainsi pour les plus pressés d’entre-vous, il suffit de télécharge ce script et de le lancer à partir d’un compte administrateur pour avoir une configuration NGinx + PageSpeed.

capture_159

Pour les autres, les plus curieux, nous allons détailler l’installation dans la suite de ce paragraphe.

On commence donc par se créer un répertoire de travail:

mkdir ~/install-nginx-pagespeed
cd ~/install-nginx-pagespeed/

Puis on télécharge les deux archives nécessaires:

wget https://github.com/pagespeed/ngx_pagespeed/archive/release-1.7.30.3-beta.zip
wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz

On décompresse le tout:

unzip release-1.7.30.3-beta.zip
cd ngx_pagespeed-release-1.7.30.3-beta/
tar zxvf ../1.7.30.3.tar.gz
cd ..

A ce stade, le répertoire ngx_pagespeed-release-1.7.30.3-beta contient donc le module PageSpeed prêt à être intégré aux sources de NGinx.

On récupère donc les sources de ce dernier:

wget http://nginx.org/download/nginx-1.4.4.tar.gz

On décompresse puis on installe:

tar zxvf nginx-1.4.4.tar.gz
cd nginx-1.4.4/
./configure --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --http-log-path=/var/log/nginx/access.log --with-http_dav_module --http-client-body-temp-path=/var/lib/nginx/body --with-http_ssl_module --http-proxy-temp-path=/var/lib/nginx/proxy --with-http_stub_status_module --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --with-debug --with-http_flv_module --with-http_realip_module --with-http_mp4_module --add-module=../ngx_pagespeed-release-1.7.30.3-beta
make

Enfin on installe la nouvelle version de NGinx contenant le module PageSpeed sur son système (attention cela va écraser votre installation existante mais pas les fichiers de configurations).

sudo make install

On relance NGinx pour prendre en compte la nouvelle installation.

sudo service nginx restart

On a donc un beau NGinx avec le module PageSpeed disponible. Par défaut, ce module n’est pas activé. Il faut donc passer à l’étape suivant: la configuration du module.

Configuration du module PageSpeed pour NGinx

C’est assez simple car tout est localisé dans la section server (ou http dans la cas d’une mutualisation avec plusieurs hôtes virtuels) des fichiers de configuration de NGinx. On commence donc par identifier cette section puis d’y ajouter les lignes suivantes pour activer le module PageSpeed en mode « pass through » (ce mode permet de choisir de manière exhaustive les filtres à appliquer):

server {
        ...

	# PageSpeed
        # enable ngx_pagespeed
        pagespeed on;
        pagespeed FileCachePath /var/ngx_pagespeed_cache;
        # Ensure requests for pagespeed optimized resources go to the pagespeed handler
        # and no extraneous headers get set.
        location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
                add_header "" "";
        }
        location ~ "^/ngx_pagespeed_static/" { }
        location ~ "^/ngx_pagespeed_beacon$" { }
        location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
        location /ngx_pagespeed_global_statistics { allow 127.0.0.1; deny all; }
        location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }

       ...
}

Ces lignes permettent:

  1. d’activer pagespeed (pagespeed on)
  2. de configurer le répertoire utiliser par PageSpeed pour cacher ses informations (FileCachePath)
  3. de s’assurer que les requêtes vers PageSpeed ne sont pas perturbées (location)

Pour le cache on utilise le répertoire /var/ngx_pagespeed_cache qu’il faut créer et configurer au niveau des droits pour que NGinx puisse y accéder (dans mon cas, le processus NGinx est lancé avec l’utilisateur www-data).

sudo mkdir /var/ngx_pagespeed_cache
sudo chown www-data:www-data /var/ngx_pagespeed_cache

Ensuite à la suite des autres lignes de la section server (ou http) on active les filtres souhaités. Voici un exemple des filtres que j’utilise sur mon serveur hébergeant ce blog:

server {
        ...

        # enable collapse whitespace filter
        pagespeed EnableFilters collapse_whitespace;

        # enable JavaScript library offload
        pagespeed EnableFilters canonicalize_javascript_libraries;

        # combine multiple CSS files into one
        pagespeed EnableFilters combine_css;

        # combine multiple JavaScript files into one
        pagespeed EnableFilters combine_javascript;

        # remove tags with default attributes
        pagespeed EnableFilters elide_attributes;

        # improve resource cacheability
        pagespeed EnableFilters extend_cache;

        # flatten CSS files by replacing @import with the imported file
        pagespeed EnableFilters flatten_css_imports;
        pagespeed CssFlattenMaxBytes 5120;

        # defer the loading of images which are not visible to the client
        pagespeed EnableFilters lazyload_images;

        # enable JavaScript minification
        pagespeed EnableFilters rewrite_javascript;

        # enable image optimization
        pagespeed EnableFilters rewrite_images;

        # pre-solve DNS lookup
        pagespeed EnableFilters insert_dns_prefetch;

        # rewrite CSS to load page-rendering CSS rules first.
        pagespeed EnableFilters prioritize_critical_css;

	# make Google analytics async
	pagespeed EnableFilters make_google_analytics_async;
}

Test et validation

Il existe tout un tas d’outils pour tester la vitesse de chargement de vos pages. J’utilise personnellement GTMetrix et  PageSpeed Insights. On peut ainsi facilement quantifier le gain de l’utilisation du module PageSpeed sur son site.

Il est clair que le module PageSpeed n’aura pas le même impact sur les les sites ayant pris en compte les problématiques de SEO et d’optimisation du chargement dès leurs conceptions que sur les autres. Mais au vu du faible overhead CPU et mémoire de ce module, je vous conseille de l’intégrer de base dans vos serveurs Web.

Utilisez-vous ce module (ou son pendant pour Apache ?) pour l’hébergement de vos sites ? Quels sont les filtres que vous mettez en place ?

Sources ayant servi à la rédaction de ce billet:

Catégories
Image Open-source Planet-libre Web

Gérer vos photos avec OpenPhoto, un service auto-hébergé

C’est suite à un tweet sur l’abandon du développement de la version GNU/Linux de Picassa par les équipes de Google que j’ai entendu parler pour la première fois du projet OpenPhoto (bien que comme nous allons le voir les deux sujets ne soient pas liés).

OpePhoto propose d’héberger dans un « cloud » vos photos, permettant ainsi un accès dématérialisé (plus besoin d’apporter sa clé USB pour montrer les photos de vacances à ses parents/amis).

OpenPhoto propose pour cela deux solutions:

  • un service en ligne proposant de gérer vos photos (importation, catégories, tag, applications smartphones, API…) mais en les hébergeant dans votre « cloud » (Dropbox ou votre espace de stockage Amazon S3 et prochainement Google Drive).
  • une version communautaire et libre permettant d’auto-héberger son propre serveur. Cette version propose en plus un stockage local des photos (sans passer par Dropbox ou Amazon S3).

C’est sur cette deuxième configuration que nous allons nous pencher dans ce billet en proposant une procédure d’installation et de configuration de Open Photo sur une machine Debian Squeeze avec NGinx , PHP-FPM et MySQL (la procédure doit être la même sous Ubuntu, mais je n’ai pas vérifié).

Note: à l’heure de la rédaction de ce billet, il y a peu ou très peu de documentation sur le Web sur comment installer OpenPhoto sur un serveur Nginx (alors que l’on trouve un tas de procédure pour les autres serveurs Web du marché sur le GitHub officiel…). Si une âme généreuse veut proposer une adaptation de ce billet dans le même formalisme que l’installation sous Apache, je pense que le projet serait très reconnaissant… (je m’en suis chargé).

Préparation de l’installation

Je pars sur le principe ou vous avez une machine Debian sur laquelle Nginx et PHP-FPM sont déjà installé. Si ce n’est pas le cas, vous pouvez suivre ce billet.

En plus, il faudra installer les paquets suivants:

sudo apt-get install mysql-server git-core php5-dev php5-mysql php5-curl curl php5-gd php5-mcrypt php5-imagick php-pear exiftran

On configure PHP en éditant les variable suivantes dans le fichier /etc/php5/fpm/php.ini (à adapter à votre besoin, notamment si vous avez un appareil photo avec un capteur générant des images > 16 Mo):

file_uploads = On
upload_max_filesize = 16M
post_max_size = 16M

On active également l’oAuth (pour l’authentification des applications tierces comme par exemple les applis iPhone et Android):

sudo pecl install oauth
sudo sh -c "echo \"extension=oauth.so\" >> /etc/php5/conf.d/oauth.ini"

On redémarre PHP-FPM pour prendre en compte les modifications:

sudo service php-fpm restart

Installation de OpenPhoto

On créé ensuite un répertoire dans notre serveur Web (/var/www/openphoto) et on télécharge la dernière version de la version communautaire (libre) de OpenPhoto:

sudo mkdir /var/www/openphoto
sudo git clone git://github.com/photo/frontend.git /var/www/openphoto

Puis on prépare l’arborescence:

sudo mkdir /var/www/openphoto/src/userdata
sudo mkdir /var/www/openphoto/src/html/photos
sudo mkdir /var/www/openphoto/src/html/assets/cache
sudo chown -R www-data:www-data /var/www/openphoto

Enfin on génère le fichier de configuration Nginx /etc/nginx/sites-enabled/openphoto pour le site OpenPhoto (à adapter également à votre configuration, notamment au niveau du server_name):

server {
	listen 80;
	server_name openphoto.mondomaine.com;
	root /var/www/openphoto/src/html; 

	index  index.php;
	client_max_body_size 25M;
	default_type text/html;
	charset utf-8;

	if (!-e $request_filename) {
		rewrite ^/([^?]*)(\?+([^?]*))*$ /index.php?__route__=/$1&$3 last;
	} 

	# PHP scripts -> PHP-FPM server listening on 127.0.0.1:9000
	# Check cache and use PHP as fallback.
	location ~* \.php$ {
                 try_files $uri =404;

                 fastcgi_pass 127.0.0.1:9000;
                 fastcgi_index index.php;
                 include fastcgi_params;
		 fastcgi_ignore_client_abort off;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}

	# Global restrictions configuration file.

	location = /favicon.ico {
		log_not_found off;
		access_log off;
	}

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}

	location ~ /\. {
		deny all;
		access_log off;
		log_not_found off;
	}

	location ~ \.ini$ {
		deny all;
		access_log off;
		log_not_found off;
	}

	add_header Cache-Control "max-age=315360000";
	# Mise ne cache des ressources statiques
	location ~* ^.+\.(jpg|jpeg|gif|css|png|js|xml)$ {
		expires 30d;
		access_log off;
	}
}

On redémarre NGinx pour prendre en compte le site:

sudo service nginx restart

Puis on crée une nouvelle base de donnée MySql. Notez sur une feuille, le nom de la base (openphoto), le nom de l’utilisateur (openphoto) et le mot de passe associé (openphotomdp2012):

# mysql -u root -p
Enter password: 

mysql> create database openphoto;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON openphoto.* TO "openphoto"@"localhost" IDENTIFIED BY "openphotomdp2012";
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye

Configuration initiale de OpenPhoto

La suite de la configuration se fera à partir d’un navigateur Web, plus besoin de la ligne de commande :).

On doit dans un premier temps créer un compte sur le site OpenPhoto (même si on utilise pas la version en ligne et seulement une version auto-hébergé). Une fois le mail de confirmation reçu et la confirmation effectué, vous pouvez poursuivre l’installation en vous rendant à l’URL: http://openphoto.mondomaine.com (remplacer mondomaine.com par votre domaine que vous avez configurez dans le fichier de configuration NGinx). Si vous n’avez pas de domaine, il est possible de passer directement par l’adresse IP de votre machine.

Vous devez arriver sur la page suivante:

On entre:

  1. l’adresse email associé à votre compte OpenPhoto
  2. on laisse le thème par défaut et on clique sur « Continue to step 2 »

On passe à la deuxième étape de l’installation:

On sélectionne:

  1. une base de donnée de type MySQL (que l’on a préalablement créer dans le chapitre précédant)
  2. un stockage local des photos (on peut noter qu’il est possible de mixer stockage local et Dropbox)
  3. on passe à la troisième et dernière étape

Elle permet de configurer notre base de donnée MySQL (reprendre votre petite feuille…):

A la fin de cette procédure, votre serveur OpenPhoto est prêt !

Prise en main et premières impressions

La première chose à faire est d’importer quelques photos. On peut utiliser la page Upload qui propose une importation par Drag & Drop (ou sélection plus classique dans le gestionnaire de fichiers) ou bien l’application dédiée de votre SmarthPhone (Android et iPhone). Les images sont téléchargés sur votre serveur avec une très élégante barre de progression. On note au passage qu’OpenPhoto utilise les dernières technologies HTML5.

On peut ensuite éditer les images en y ajoutant une description, des tags, des coordonnées GPS, des droits (public ou privé) et une licence. Ces informations sont bien sûr récupérées automatiquement si elles sont présentes dans les méta-données du fichier.

Elle est pas belle ma fille ? 🙂

OpenPhoto permet de créer des groupes d’utilisateurs ayant des droits sur certaines photos. Par exemple, si vous créez un groupe Famille, alors il sera possible de classer vos photos familiales dans ce groupe afin qu’elles ne soient visibles que par vos proches. Pour grouper vos photos dans des groupes, le plus simple est d’aller dans le menu Manage, de sélectionner les photos en question (par un simple clic sur le bouton pin) puis de cliquer sur le bouton « Batch edit » et enfin de séléctionner le groupe.

Mes premières impressions sont très bonnes. OpenPhoto est rapide, stable. Le seul problème que j’ai rencontré est au niveau de l’affichage de la Gallery ou les photos sont déformées. Je vais essayer de le pousser un peu en important un grand nombre d’images (je ferai une màj du billet).

On sent une grande marge de manoeuvre au niveau des fonctionnalités proposées. Il est d’ailleurs possible de voter avec la communauté pour influencer la roadmap du logiciel sur les futures fonctions. J’aime le fait qu’OpenPhoto se concentre uniquement sur la gestion des images, contrairement à OwnCloud dont j’avais parlé dans un précédent billet.

Que pensez-vous de ce genre de service ?

Êtes vous prêts à franchir le pas et d’auto-héberger vos photos sur une de vos machines ?

Catégories
Open-source Planet-libre Systeme Web

NGinx – Protéger son site avec une authentification simple HTTP

Un petit billet « flash express » pour  protéger son site (ou un répertoire de son site) avec une authentification simple (type login/password) sur un serveur NGinx.

Pré-requis

Il faut disposer d’un serveur NGinx bien configuré (par exemple en utilisant ce script d’auto-installation pour Debian ou Ubuntu) puis du logiciel htpasswd que l’on peut installer sous Debian/Ubuntu avec la commande suivante:

[cc]

sudo apt-get install apache2-utils

[/cc]

Création du fichier .htpasswd

Ce fichier va contenir, de manière chiffré, le mot de passe associé à l’utilisateur. La commande à utiliser pour créer ce fichier est la suivante:

[cc]

sudo htpasswd -c /var/www/.htpasswd nicolargo

New password:

Re-type new password:

Adding password for user nicolargo

[/cc]

Ou:

  • -c est une option pour créer le fichier (sans cette option, le couple login/password est ajouté)
  • /var/www/ est l’emplacement du fichier .htpasswd. Le contenu du répertoire /var/www/ (donc la racine de mon site Web) sera donc protégée par le couple login/password
  • nicolargo est le nom de l’utilisateur (login)
  • ilfaut sasir deux fois le mot de passe (password)

Configuration de NGinx

Pour que NGinx puisse gérer les fichiers .htpasswd, il faut ajouter modifier la configuration de son site (à  adapter selon votre configuration):

[cc]

server {

listen 80;

server_name localhost;

root /var/www;

# Static

location / {

index index.html index.htm;

auth_basic « Login »;

auth_basic_user_file /var/www/.htpasswd;

}

# Protect hidden file to read/write access

location ~ /\. {

deny all;

}

}

[/cc]

Après avoir rechargé la configuration:

[cc]

sudo /etc/init.d/nginx restart

[/cc]

Il ne reste plus qu’à…

Tester

En pointant un navigateur sur le site en question, une bannière d’authentification va apparaitre:

 

Note sur la sécurité

Attention de ne PAS utiliser se mécanisme pour protéger des informations sensibles. En effet il n’y a pas de chiffrement des données lors de la transmission en HTTP entre le navigateur et le serveur et le fichier .htpasswd peut être récupéré en cas de corruption de votre serveur…

Catégories
Blog Open-source Planet-libre Web

Configuration Varnish+Nginx pour WordPress

Vu le nombre d’articles sur l’utilisation du serveur de cache Varnish pour une utilisation avec le CMS WordPress, force est de constater qu’il est difficile de faire le tri pour en sortir LA configuration. Dans ce billet, je vais donc vous présenter ma configuration qui tourne depuis quelques jours sur le serveur hébergeant le Blog de Nicolargo.

Ce serveur sous Debian Squeeze est composé de:

  • Varnish
  • Nginx avec le module PHP-FPM
  • WordPress avec le plugin « Varnish HTTP Purge »

Je maintiendrai à jour une configuration stable (avec des commentaire en Anglais) de cette pile HTTP dans le GIT suivant:

https://github.com/nicolargo/varnish-nginx-wordpress

Une configuration pour quoi faire ?

Le principal objectif est d’optimiser votre serveur pour supporter une montée en charge pouvant aller jusqu’à plusieurs centaines de requêtes HTTP par seconde. C’est à dire une configuration adaptée pour une grande majorité des blogs personnels à fort trafic.

Avec une pile HTTP classique (c’est à dire sans cache), toutes les requêtes vers WordPress vont entraîner:

  • l’exécution d’un script PHP générant en sortie un fichier HTML
  • des requêtes vers la base de donnée MySQL
  • la lecture sur disque des éléments statiques de la page (fichiers CSS, JS, images…)

Lors de ces premières requêtes il est important d’avoir un thème bien optimisé. Le plugin W3 Total Cache peut vous aider dans cette démarche en optimisant les fichiers CSS (compression / regroupement) et en mettant dans un cache certaine requêtes SQL. Il faut également noter qu’avec un système de cache externe comme Varnish, la première requête va également engendrer ces actions mais pas les suivantes.

Les deux premiers points sont fortement consommateurs de ressources matérielles (CPU et mémoire). Ainsi, la charge globale de votre serveur augmente avec le nombre de requêtes simultanées. Arrivé à saturation, votre serveur ne peut plus répondre correctement aux requêtes et le temps de chargement de vos pages commencent à augmenter jusqu’à arriver au point ou il n’est plus capable de rien faire.

L’utilisation d’un cache comme Varnish permet de fournir directement les fichier HTML au navigateur client sans passer par l’exécution du script PHP et les requêtes MySQL.

Concernant le troisième point, le problème vient de la relative lenteur des accès disques (notamment si vous êtes sur un hébergement de type virtuel (aka) VPS).

Une optimisation possible est de lire les objets statiques non pas depuis le disque mais directement depuis un cache mis en RAM. Deux solutions sont possibles, soit faire effectuer cette tache par Varnish (que l’on peut optimiser en utilisant un disque tmpfs pour le répertoire de travail de Varnish) qui en plus des pages HTML va également « cacher » les objets statiques, soit laisser NGinx gérer cela directement, notamment en utilisant une brique comme Memcached. Si les deux sont comparables en terme de performances pures (c’est à dire la capacité à supporter un grand nombre de requêtes simultanées), il semble que NGinx est une consommation CPU moins importante.

Avant de cacher il faut savoir purger

Les lecteurs attentifs ont déjà dû noter qu’il y avait un trou dans la raquette dans l’exposé précédant. En effet, par définition, WordPress génère des sites dynamiques ou les articles peuvent évoluer, des commentaires peuvent être ajoutés. Il faut donc un mécanisme pour prévenir Varnish de mettre à jour son cache quand certaines actions sont faites sur le blog.

Heureusement pour nous, WordPress dispose d’un grand nombre de plugins permettant d’automatiser cette tache. W3 Total Cache, déjà mentionné dans le premier chapitre dispose d’une option pour  communiquer avec Varnish. Il semble cependant qu’il y est des problèmes quand l’on configure ce plugin avec plusieurs serveurs Varnish (pour faire du partage de charge). Je conseille donc l’utilisation d’un plugin ne faisant que la tache de purge:  Varnish HTTP Purge.

Il faut donc désactiver la fonction de purge Varnish dans W3 Total Cache (si ce dernier est installé):

puis activer le plugin Varnish HTTP Purge:

On passe aux résultats

Pour avoir un « test bed » stable, j’ai installé les briques sur une machine dédiée sous Debian Squeeze. J’ai ensuite rédigé un billet de test comprenant du texte et 3 images.

Test de montée en charge locale avec Apache Bench

Dans un premier temps j’ai utilisé l’utilitaire Apache Bench (utilitaire ab) qui permet de simuler en local (c’est à dire sans les contraintes réseau) un grand nombre de requêtes simultanées sur l’URL du billet de test.

Sans Varnish / Sans W3 Total Cache:

[cce lang= »bash »]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

Requests per second: 20.45 [#/sec] (mean)

[/cce]

=> CPU proche de 95% pendant le test.

Sans Varnish / Avec W3 Total Cache:

[cce lang= »bash »]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

Requests per second: 232.62 [#/sec] (mean)

[/cce]

=> CPU proche de 85% pendant le test.

On note une augmentation des performances mais la charge CPU reste forte. Les processus PHP-FPM sont nombreux.

Avec Varnish / Sans W3 Total Cache:

[cce lang= »bash »]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

Requests per second: 8001.76 [#/sec] (mean)

[/cce]

=> CPU proche de 30% pendant le test.

Le gain est impressionnant par rapport à la configuration sans Varnish. On atteint un nombre de requêtes par seconde très important (> 8000 en moyenne) avec une marge CPU ne dépassant pas les 35% !

Avec Varnish / Avec W3 Total Cache:

[cce lang= »bash »]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

Requests per second: 8018.47 [#/sec] (mean)

[/cce]

=> CPU proche de 30% pendant le test.

Comme on n’a pas ou peu de gain supplémentaire en utilisant W3 Total Cache en plus de Varnish. J’ai donc décidé de ne plus utilisé W3 Total Cache sur mon blog WordPress. Il sera remplacé par « Varnish HTTP Purge » pour la gestion des purges de Varnish et « WP Minify » pour la réduction automatique des fichier CSS et JavaScript.

Test de montée en charge online avec Blitz.io

Si vous ne connaissez pas le service Blitz.io, je vous conseille la lecture du très bon billet de Romain sur le sujet.

J’ai utilisé la commande « rush » suivante:

[cce]

–timeout 5000 –region ireland –pattern 1-250:60 http://blogtest.nicolargo.com/2011/09/lorem.html

[/cce]

NGinx seul:

A partir de 50 utilisateurs, le temps de chargement des pages commence à augmenter pour arriver au timeout (limité à 5 secondes pour les tests chez Blitz.io) vers 120 utilisateurs.

NGinx avec Varnish:

Dans cette configuration, je ne rencontre aucune chute de performance avec 250 utilisateurs simultanés.

Grâce à Romain (encore lui) j’ai pu lancer sur le Blog de Nicolargo (Varnish + Nginx) un test avec 500 utilisateurs simultanés (par défaut Blitz.io est limité à 250).

Voici le résultat sur le Blog de Nicolargo:

Pas de problème jusqu’à 500 utilisateurs simultanés !!!

Test des purges

Pour valider que le plugin « Varnish HTTP Purge » fonctionnaite bien j’ai effectué les taches suivantes en vérifiant que la page était bien mise à jour pour un lecteur lambda:

  • Modification d’un billet existant
  • Suppression d’un billet existant
  • Ajout d’un commentaire
  • Modification d’un commentaire
  • Suppression d’un commentaire

Tous les tests ont été concluant.

Conclusion

Le couple Varnish + Nginx est donc une des pile que l’on peut utiliser pour obtenir un blog performant et résistant à une montée en charge bien supérieure aux nombres maximum de visiteurs sur la plupart des sites Internet. Ce n’est bien pas la seule solution et il existe sûrement des piles encore plus optimisé (notamment au niveau statique avec un serveur comme G-WAN), mais il est de mon point de vu, celui qui offre le meilleur ratio stabilité/sécurité/performance.

Pour suivre l’activité de la configuration étudiée dans ce billet, je vous conseille de vous abonnez au projet GitHub.

Quelques unes des sources de ce billet:

Catégories
Blog Open-source Web

Migration du blog vers une Dedibox DC

Ce matin, vers les 10h, j’ai procédé à la migration de mon blog depuis un serveur VPS Gandi 4 parts vers une Dedibox DC.  J’ai choisi un samedi matin car c’est à ce moment là que le trafic est le plus faible sur le site.

Voici la procédure que j’ai suivi:

  • Installation du nouveau serveur en suivant cette procédure
  • Sauvegarde de la base MySQL depuis le serveur VPS Gandi
  • Fermeture des commentaires sur le blog WordPress du serveur VPS Gandi
  • Copie du répertoire wp-contents vers la Dedibox DC
  • Importation de la base MySQL sur la Dedibox DC
  • Test du nouveau serveur
  • Modification des serveurs DNS

 

La migration semble se dérouler comme sur des roulettes. J’ai encore quelques connexions sur l’ancien serveur, depuis des réseaux dont les DNS ne sont pas encore à jour.

Au niveau des performances, les graphes suivants parlent d’eux même, le nouveau serveur résiste beoucoup mieux à la charge, il faut dire que j’utilise un nouveau stack HTTP: Varnish 3 + Nginx.

Performances avant la migration:

Performances après la migration:

Si vous rencontrez des problèmes pour accéder à mon blog, merci de me prévenir :).

Update: Certains lecteurs rencontrent des effets de bord (page non mise à jour après un commentaire et affichage de la version mobile), j’ai donc désactivé Varnish en attendant de trouver LA configuration qui va bien. J’ai refait un test avec Load Impact et l’on voit clairement que l’on perd en perfo…

Update2: Tout est rentré dans l’ordre 🙂

Catégories
Blog Open-source Planet-libre Systeme Web

Installation pas à pas d’un serveur de blog WordPress sur Debian Squeeze

Je viens de passer le cap et de m’abonner à un serveur dédié chez Online.net. Mon choix s’est porté vers une Dedibox DC. J’ai longtemps hésité avec une OVH Kimsufi 16G mais le fait que la Dedibox propose en standard deux disques fonctionnant en RAID1 à fait la différence (avec l’âge ou privilégie la sécurité à la performance…).

Avant de migrer mon blog sur ce nouveau serveur (il est actuellement hébergé chez un VPS Gandi 4 parts), j’ai profité de disposer d’un serveur tout neuf pour valider une procédure complète d’installation et d’optimisation d’un blog WordPress sur un serveur Debian Squeeze en utilisant le « stack » Web suivant: Varnish + Nginx + MemCached.

L’objectif de ce billet est de partager cette procédure avec vous.

Introduction

Nous allons donc détaillé l’installation d’un blog WordPress sur une installation toute fraîche de Debian Squeeze (version stable) pré-installé dans mon cas par Online.net avec un minimum de logiciels (pas d’Apache ni d’autres serveurs Web). Vous l’avez compris, pour suivre la procédure suivante, il faut s’assurer qu’aucun serveur Web n’est installé sur votre machine.

Post installation du système

J’ai pris l’habitude de créer des scripts de post installation pour les OS (desktop et server) que j’utilise. Dans le cas qui nous intéresse je vais donc utiliser le script: squeezeserverpostinstall.sh.

Pour le télécharger puis le lancer, il suffit de saisir les commandes suivantes à partir d’un compte administrateur ou directement en root):

wget --no-check-certificate https://raw.github.com/nicolargo/debianpostinstall/master/squeezeserverpostinstall.sh
chmod a+x squeezeserverpostinstall.sh
./squeezeserverpostinstall.sh

Comme le serveur est directement connecté à Internet et à moins d’être très joueur, je vous conseille de configurer quelques règles de Firewall. J’ai mis à disposition un jeu de règles assez facile à modifier en éditant le fichier /etc/init.d/firewall.sh. Pour le télécharger et l’installer:

wget --no-check-certificate -O /etc/init.d/firewall.sh https://raw.github.com/nicolargo/debianpostinstall/master/firewall.sh
chmod a+x /etc/init.d/firewall.sh
update-rc.d firewall.sh defaults 20
service firewall start

Note: par défaut les ports SSH entrant et HTTP et DNS sortant sont autorisés.

Pour modifier ces listes, il suffit de configurer les variables suivantes dans le fichier /etc/init.d/firewall.sh:

# Services that the system will offer to the network
TCP_SERVICES="22" # SSH only
UDP_SERVICES=""

# Services the system will use from the network
REMOTE_TCP_SERVICES="80 443" # web browsing
REMOTE_UDP_SERVICES="53" # DNS

A ce stade, vous devriez avoir un serveur à jour et sécurisé. Passons donc à l’étape suivante.

Installation de Nginx + PHP-FPM + Memcached

C’est actuellement une des combos les plus performantes pour héberger des serveurs Web basées sur PHP (ce qui est le cas du CMS WordPress). Pour effectuer simplement et rapidement ces logiciels, j’utilise un script maisonnginxautoinstall.sh. Il faut donc saisir les commandes suivantes:

wget --no-check-certificate https://raw.github.com/nicolargo/debianpostinstall/master/nginxautoinstall.sh
chmod a+x nginxautoinstall.sh
./nginxautoinstall.sh

Le script va installer la dernière version stable de Nginx puis le daemon PHP-FPM qui permet de booster les performances des scripts PHP et enfin le gestionnaire de cache mémoire MemCached (note: le script fonctionne également sur Debian Lenny 5).

Pour adapter les performances de Nginx à votre CPU, il faut modifier la variable worker_processes le fichier /etc/nginx/nginx.conf. Pour obtenir la valeur optimale pour votre système, vous pouvez lancer la commande suivante:

cat /proc/cpuinfo | grep processor | wc -l

Qui donne la valeur 4 sur ma Dedibox (4 coeurs/CPU). On édite le fichier nginx.conf de la manière suivante:

user www-data;

# Set this value to 1 or N with N = N-Core
worker_processes  4;
worker_rlimit_nofile 8192;
events {
	# max_clients = worker_processes * worker_connections
	worker_connections  1024;
	# Only for Linux 2.6 or >
	use epoll;
	# Accept as many connections as possible
	multi_accept on;
}

http {
	# Mime types
	include       	mime.types;
	default_type  	application/octet-stream;

	# Log format
	set_real_ip_from 	127.0.0.1; 
	real_ip_header 		X-Forwarded-For; 
	log_format 	main '$remote_addr - $remote_user [$time_local]  $status '
		'"$request" $body_bytes_sent "$http_referer" '
    		'"$http_user_agent" "$http_x_forwarded_for"';

	# Hide the Nginx version number
	server_tokens off;

	# Some tweeks...
	sendfile        		on;
	tcp_nodelay			on;
	#tcp_nopush			on;

	# Timeouts
	#keepalive_timeout  		10 10;
	keepalive_timeout  		65;
	client_body_timeout   		30;
	client_header_timeout 		30;
	send_timeout          		30;
	client_max_body_size		8M;
	reset_timedout_connection 	on;

	# Gzip module configuration
	gzip  			on;
	gzip_disable 		"MSIE [1-6].(?!.*SV1)";
	gzip_vary 		on;
	gzip_comp_level 	3;
	gzip_proxied 		any;
	gzip_buffers 		16 8k;

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}

On relance le serveur pour prendre en compte la configuration:

service nginx restart

Installation du langage PHP

WordPress use et abuse du langage PHP, une installation optimisé du moteur permettant d’exécuter le code est donc nécessaire. Personnellement j’utilise l’implémentation PHP5 FPM qui est réputé pour ses performances. Elle est installé par défaut avec mon script d’auto-install de Nginx.

La configuration est stocké dans le répertoire /etc/php5/fpm. Mon fichier php-fpm.conf ressemble à cela:

[global]
pid = /var/run/php5-fpm.pid
error_log = /var/log/php5-fpm.log
emergency_restart_interval = 1m 
process_control_timeout = 10s 
include=/etc/php5/fpm/pool.d/*.conf

Avec WordPress comme CMS, je vous encourage à stocker les fichiers de sessions dans une base NoSQL de type Redis afin de ne pas se retrouver avec des milliers de petits fichiers dans le répertoire /tmp. Pour cela, il suffit d’ajouter les lignes suivantes dans le fichier /etc/php5/fpm/php.ini:

session.save_handler = "redis"
session.save_path = "tcp://127.0.0.1:6379?weight=1"

Dernière étape et non des moindres, la configuration du pool de processus PHP-FPM que vous allez dédier à votre blog WordPress (par exemple /etc/php5/fpm/pool.d/www.conf dans mon cas):

[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.status_path = /status
request_terminate_timeout = 120s
rlimit_files = 65535
chdir = /

On peut relancer PHP

service php5-fpm restart

et passer à l’étape suivante, la base de donnée…

Installation de MySQL

A l’heure actuelle, WordPress utilise une base de donnée MySQL pour fonctionner (je préférerai PgSQL mais bon…). Il faut donc installer le serveur de base de donnée MySQL:

apt-get install mysql-server php5-mysql
service php5-fpm restart

Optimiser un peu celle-ci en modifiant quelques variables dans le fichier /etc/mysql/my.cnf:

query_cache_type = 1
query_cache_limit = 2M
query_cache_size = 32M

et relancer le daemon pour que la configuration soit prise en compte:

service mysql restart

On passe ensuite à la phase de création de la base de données nommée wordpress accessible par utilisateur/motdepasse:

# mysql -u root -p

mysql> create database wordpress;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON wordpress.* TO "utilisateur"@"localhost" IDENTIFIED BY "motdepasse";
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> exit

Installation du CMS WordPress

J’utilise la dernière version stable de WordPress disponible sur le site officiel:

cd /var/www
wget http://wordpress.org/latest.tar.gz
tar zxvf latest.tar.gz
cp wordpress/wp-config-sample.php wordpress/wp-config.php
chown -R www-data:www-data /var/www/wordpress

Ensuite on configure la base de donnée dans le fichier wordpress/wp-config.php:

...
define('DB_NAME', 'wordpress');
define('DB_USER', 'utilisateur');
define('DB_PASSWORD', 'motdepasse');
define('WP_CACHE', true);
...

Il suffit ensuite de finaliser l’installation de WordPress en pointant un navigateur Web vers http://votredomaine.com/wordpress/wp-admin/install.php.

Si vous avez changé la structure du permalink (par exemple chez moi c’est /%year%/%monthnum%/%postname%.html), il faut modifer la configuration Nginx, plus précisément la section « Location / » dans le fichier /etc/nginx/sites-enabled/default-site:

server{
        listen 80;

        server_name blog.nicolargo.com;
        root	/var/www/blog.nicolargo.com;
        index 	index.php index.html index.htm;

        access_log /var/log/nginx/blog.access_log;
        error_log /var/log/nginx/blog.error_log;

        # Security
        include global/security.conf;

        location / {
                # This is cool because no php is touched for static content. 
                # include the "?$args" part so non-default permalinks doesn't break 
when using query string
                try_files $uri $uri/ /index.php?$args;
        }

	# PHP-FPM
	include global/php-fpm.conf;

	# STATICS FILES
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

avec les fichiers inclus suivants:

Securité /etc/nginx/global/security.conf:

location = /favicon.ico {
	log_not_found off;
	access_log off;
}

location = /robots.txt {
	allow all;
	log_not_found off;
	access_log off;
}

location ~ /\. {
	deny all;
	access_log off;
	log_not_found off;
}

et PHP-FPM /etc/nginx/global/php-fpm.conf:

# PHP scripts -> PHP-FPM server listening on 127.0.0.1:9000
location ~ \.php$ {
	# The following line prevents malicious php code to be executed through some uploaded file (without php extension, like image)
	# This fix shoudn't work though, if nginx and php are not on the same server, other options exist (like unauthorizing php execution within upload folder)
	# More on this serious security concern in the "Pass Non-PHP Requests to PHP" section, there http://wiki.nginx.org/Pitfalls
	try_files $uri =404;

	# PHP	
	# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
	fastcgi_pass   127.0.0.1:9000;
	fastcgi_index  index.php;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	include fastcgi_params;
	fastcgi_param  QUERY_STRING     $query_string;
	fastcgi_param  REQUEST_METHOD   $request_method;
	fastcgi_param  CONTENT_TYPE     $content_type;
	fastcgi_param  CONTENT_LENGTH   $content_length;
	fastcgi_intercept_errors        on;
	fastcgi_ignore_client_abort     off;
	fastcgi_connect_timeout 60;
	fastcgi_send_timeout 180;
	fastcgi_read_timeout 180;
	fastcgi_buffers 4 256k;
	fastcgi_buffer_size 128k;
	#fastcgi_buffers 256 16k;
	#fastcgi_buffer_size 16k;
	fastcgi_busy_buffers_size 256k;
	fastcgi_temp_file_write_size 256k;
}

Ne pas oublier de relancer NGinx pour prendre en compte cette modification:

service nginx restart

Installation du plugin WP Super Cache

Après quelques années sous d’utilisation de W3 Total Cache et la mise en place de mon proxy/cache Varnish, j’ai choisi d’utiliser le plugin WP Super Cache qui s’occupe de cacher les pages demandées par les utilisateurs non identifiées (donc pas 90% du trafic) afin que PHP et MySQL ne soit pas appelé lors de ces requêtes.

Il est également possible de précharger la mise en cache des pages les plus visitées et de les mettre automatiquement à jour de manière régulière.

Une fois installé et activé il faut se rendre dans le menu de configuration du plugin et de cliquer sur l’onglet « Easy » et « Mise en cache Activée (Recommandé) ».

A ce stade, on peut faire quelques tests de performances avec Apache Bench (disponible dans le paquet Debian apache2-utils):

[cce lang= »bash »]

Requests per second: 219.53 [#/sec] (mean) (options -t 30 -c 5)

[/cce]

ou avec le service en ligne Load Impact qui permet de simuler gratuitement jusqu’à 50 utilisateurs simultanés sur votre site:

On voit bien que les page du blog se chargent rapidement (environ 500ms) même avec 50 utilisateurs simultanés.

Puis arriva Varnish…

J’ai mis à jour ma configuration de Varnish+Nginx pour WordPress dans le billet suivant. Vous pouvez le suivre en lieu et place du chapitre qui suit…

Vous savez tout le bien que je pense de Varnish. Nous allons donc maintenant ajouter cet accélérateur de site Web dans notre configuration. Il est à noter que cette étape est optionnelle. Vous pouvez tout à fait rester avec la configuration du chapitre précédent qui offre déjà de belles performances.

On commence par installer la dernière version de Varnish en utilisant le dépôt officiel.

apt-get install curl
curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add -
echo "deb http://repo.varnish-cache.org/debian/ $(lsb_release -s -c) varnish-3.0" >> /etc/apt/sources.list.d/varnish.list
apt-get update
apt-get install varnish

La version 3 de Varnish apporte certaines modifications au niveau de la syntaxe des fichiers de configuration. Si vous avez donc une config fonctionnelle en version 2, je vous conseille de lire cette page pour l’adapter.

On commence par éditer le fichier de configuration /etc/varnish/default.vcl:


Puis la manière dont le daemon va se lancer dans le fichier /etc/default/varnish:


Enfin on reconfigure NGinx pour ne plus écouter sur le port 80 (c’est Varnish qui va prendre le relais) mais sur le port 8080. Il suffit de changer la deuxième ligne du fichier /etc/nginx/sites-enabled/wordpress:

...
listen 8080;
...

On n’oublie pas d’ouvrir les port au niveau du Firewall (fichier /etc/init.d/firewall.sh):

# Services that the system will offer to the network
TCP_SERVICES="22 80" # SSH, Web
UDP_SERVICES=""

# Services the system will use from the network
REMOTE_TCP_SERVICES="25 80 443" # Mail, Web browsing
REMOTE_UDP_SERVICES="53" # DNS

...

On relance les services:

service firewall.sh restart
service nginx restart
service varnish restart

Afin pour que Varnish soit prévenu quand un billet est modifié, il faut installer et activier le plugin Varnish HTTP purge.

Le site devrait fonctionner normalement mais avec des performances boostées. Par exemple, le même test Apache Bench donne les résultats suivants:

Requests per second: 9425.03 [#/sec] (mean) (options -t 30 -c 5)

A comparer avec 220 requêtes par secondes sans Varnish…

On voit même une amélioration du temps de chargement des pages (300ms vs 500ms) qui reste constant avec  Load Impact:

Conclusion

On arrive à la fin de ce (trop ?) long billet. Le sujet est vaste et il y a sûrement des améliorations à faire dans la configuration que je viens de vous présenter. Les commentaires ci-dessous sont fait pour partager vos expériences.

Je vous signale également que je regroupe tout les billets sur l’hébergement sur la page suivante.

Catégories
Open-source Planet-libre Reseau Web

Installation automatique de NGinx, PHP-FPM, MemCached sous Debian

Au début du mois nous avons vu ensemble l’installation d’un serveur NGinx sous Ubuntu. Sous Debian,  il faut mettre un peu plus les mains dans le cambouis, en effet il est parfois utile de partir des sources plutôt que des dépôts officiels (notamment au niveau de la présence ou non d’un module).

J’ai donc développé un petit script shell pour automatiser l’installation (ou la mise à jour) d’un serveur Web rapide, léger et performant sous une Debian (Squeeze ou Lenny).

Ce script va effectuer les choses suivantes:

Il est bien sûr possible d’adapter ce script à vos besoins et de l’utiliser comme bon vous semble. Si vous rencontrez des erreurs ou que vous avez en tête des améliorations possibles, merci de laisser un commentaire en bas de ce billet.

Récupération du script

Le script est disponible dans mon GitHub:

NGinxAutoInstall.sh

Vous pouvez également faire ces actions en ligne de commande dans un terminal:

wget https://raw.github.com/nicolargo/debianpostinstall/master/nginxautoinstall.sh

Il faut ensuite le rendre exécutable:

chmod a+x ./nginxautoinstall.sh

Lancement du script

Il faut lancer le script en root (droit d’administration):

su - -c "$PWD/nginxautoinstall.sh"

Si tout se passe correctement, le script devrait afficher:

Validation et test de performances

Votre serveur est maintenant opérationnel, il vous reste à mettre vos page HTML et scripts PHP dans le répertoire /var/www et tester le tout en entrant l’URL suivante dans un navigateur Web: http://@devotreserveur/.

Vous pouvez également tester les performances brutes de votre serveur en utilisant HTTPerf (disponible dans les dépôts Debian). Sur mon serveur de test (VPS Gandi 1 part), j’obtiens les perfos suivantes:

httperf –client=0/1 –server=localhost –port=80 –uri=/ –send-buffer=4096 –recv-buffer=16384 –num-conns=5000 –num-calls=10

Request rate: 6833.4 req/s (0.1 ms/req)

Conclusion

Avec NGinx, on obtient rapidement de très bonnes performances et le couple PHP-FPM, MemCached permet d’avoir une bonne base pour héberger, par exemple, votre blog WordPress (lire l’article sur le sujet dans ce blog).

Je suis bien sur preneur de tous commentaires/remarques sur le script.

Catégories
Developpement Open-source Planet-libre Reseau Web

Installation et test de NGinx sous Ubuntu

NGinx est une des alternative au serveur Web Apache (il est actuellement utilisé par plus de 6% des serveurs Web). Il se targue d’être plus rapide, plus léger et facile à configurer.

Nous allons vérifier tout cela dans ce billet en détaillant une installation de NGinx 0.8.54 (Stable) sur une machine GNU/Linux (Ubuntu Desktop 10.10) avec en bonus le support FastCGI de PHP et de Perl !

Installation de NGinx

On commence par ajouter le dépôt officiel pour la version stable:

sudo add-apt-repository ppa:nginx/stable

sudo aptitude update

Puis on installe la bête (facile non ?):

sudo aptitude install nginx

Remarque: si un serveur Web (Apache ou autre) tourne déjà sur votre machine, l’installation de NGinx se passera normalement, par contre il n’arrivera pas à se lancer car le port HTTP par défaut (TCP/80) sera déjà occupé. La solution la plus propre est de configurer NGinx pour qu’il écoute sur un autre port (TCP/81 par exemple) puis faire vos tests en forcant l’utilisation de ce port dans votre navigateur Internet (en ajoutant :81 aux URL). Une fois Nginx validé, il suffira de supprimer l’autre serveur Web de votre machine, puis de reconfigurer Nginx sur le port par défaut (TCP/80).

Premier contact avec NGinx

Un script de démarrage nommé nginx a été installé dans le répertoire /etc/init.d. On peut voir la liste des commandes accepté par ce script en saisissant la ligne de commande suivante:

sudo service nginx

Usage: nginx {start|stop|restart|reload|force-reload|status|configtest}

On va donc activer la configuration de test:

sudo service nginx configtest

Testing nginx configuration: nginx.

Puis lancer le serveur:

sudo service nginx start

Starting nginx: nginx.

On ouvre un navigateur sur la même machine puis on entre l’UTL suivante: http://localhost/

La page suivante devrait s’afficher:

On peut ensuite arrêter le serveur:

sudo service nginx stop

Stopping nginx: nginx.

Puis passer à l’étape suivante…

Configuration du serveur NGinx

Les fichiers de configuration se trouvent dans le répertoire /etc/nginx. Les habitués d’Apache ne seront pas trop perturbés par la structure de l’arborescence de ce répertoire:

 

drwxr-xr-x 2 root root 4096 2011-01-05 08:26 conf.d/

-rw-r–r– 1 root root 884 2011-01-05 08:04 fastcgi_params

-rw-r–r– 1 root root 2258 2011-01-05 08:04 koi-utf

-rw-r–r– 1 root root 1805 2011-01-05 08:04 koi-win

-rw-r–r– 1 root root 2066 2011-01-05 08:04 mime.types

-rw-r–r– 1 root root 1340 2011-01-05 08:04 nginx.conf

-rw-r–r– 1 root root 465 2011-01-05 08:04 scgi_params

drwxr-xr-x 2 root root 4096 2011-01-05 10:36 sites-available/

drwxr-xr-x 2 root root 4096 2011-01-05 10:36 sites-enabled/

-rw-r–r– 1 root root 497 2011-01-05 08:04 uwsgi_params

-rw-r–r– 1 root root 3071 2011-01-05 08:04 win-utf

On y retrouve (entre autres):

  • nginx.conf: le fichier de configuration central
  • conf.d/: un répertoire contenant des fichiers de configuration additionnels
  • sites-available/: répertoire contenant la liste des fichier de configuration des sites disponibles
  • sites-enabled/: répertoire contenant la liste des fichiers de configuration des sites actifs (liens symboliques vers le répertoire site-availables)

On commence par jeter un coups d’oeil au fichier nginx.conf…. Quel bonheur par rapport à celui d’Apache :).

On passe ensuite au fichier du site par défaut /etc/nginx/sites-available/default (que l’on a activé tout à l’heure par la commande ‘sudo service nginx configtest’):

server {

listen 80

 

root /usr/share/nginx/www;

index index.html index.htm;

 

server_name localhost;

 

location / {

try_files $uri $uri/ /index.html;

}

 

location /doc {

root /usr/share;

autoindex on;

allow 127.0.0.1;

deny all;

}

 

location /images {

root /usr/share;

autoindex off;

}

 

}

On peut donc voir que l’on a un site qui écoute sur le port TCP/80 (listen   80) et sert les pages se trouvant dans le répertoire /usr/share/nginx/www (root /usr/share/nginx/www) à partir de l’URL http://localhost/ (server_name localhost).

Nous allons nous baser sur cet exemple pour construire un nouveau fichier de configuration propre à nos besoins.

On commence par créer l’arborescence qui va héberger nos pages (par exemple /home/labo/www). Si le répertoire n’existe pas il faut le créer et lui donner les bons droits:

mkdir /home/labo/www

Enfin on édite une page de test:

# vi /home/labo/www/index.html

<html><body>Ma page</body></html>

Ensuite on passe à la création du fichier de configuration du site.

sudo vi /etc/nginx/sites-available/monsite

Avec le contenu suivant (à adapter à votre configuration):

# Mon site a moi

 

server {

listen 80;

 

root /home/labo/www;

index index.html index.htm;

 

server_name localhost;

 

location / {

# First attempt to serve request as file, then

# as directory, then fall back to index.html

try_files $uri $uri/ /index.html;

}

 

}

On supprime le site par defaut et on active le notre:

cd /etc/nginx/sites-enabled

sudo rm default

sudo ln -s ../sites-available/monsite

On redémarre le serveur Nginx:

sudo service nginx restart

Restarting nginx: nginx.

Puis  on teste la page: http://localhost/

Pour rendre le site « visible depuis l’extérieur », il faut changer la ligne:

server_name localhost;

Puis la remplacer par:

server_name www.mondomaine.com;

Il faut bien sur que le nom www.mondomaine.com pointe sur l’adresse IP de votre serveur Nginx…

Test des performances

Pour voir ce qu’il a dans le ventre, j’ai installé en Nginx et Apache sur ma machine. Nginx écoutant sur le port TCP/81 et Apache sur le port TCP/80.

J’ai ensuite utilisé le logiciel httperf (disponible dans les dépôts Ubuntu) pour simuler des requêtes sur le serveur.

Test du serveur Apache:

# httperf –client=0/1 –server=localhost –port=80 –uri=/ –send-buffer=4096 –recv-buffer=16384 –num-conns=5000 –num-calls=10

Request rate: 4284.8 req/s (0.2 ms/req)

Puis test du serveur NGinx:

# httperf –client=0/1 –server=localhost –port=81 –uri=/ –send-buffer=4096 –recv-buffer=16384 –num-conns=5000 –num-calls=10

Request rate: 6332.6 req/s (0.2 ms/req)

On a donc un gain d’environ 30% en terme de requêtes supportées par le serveur.

 

 

Request rate / Request number

 

Support du PHP

De nos jours, un serveur Web sans support PHP c’est un peu comme un Ferrari avec des roues de 13 pouces. Dans l’optique d’avoir un serveur performant nous allons donc utiliser le module externe PHP FPM (PHP FastCGI) qui s’occupera de l’exécution des scripts PHP dans un processus indépendant de NGinx (merci à cet article qui m’a bien aidé).

On commence par installer le module:

sudo add-apt-repository ppa:brianmercer/php

sudo aptitude update && sudo aptitude install php5-fpm

Par défaut, le processus PHP-FPM va se mettre en écoute sur le port TCP/9000 et écouté les requêtes venant seulement de la machine locale (localhost).

Il ne reste plus qu’à modifier le fichier de configuration de votre site pour prendre en compte le langage PHP (fichier /etc/nginx/sites-available/monsite):

# Mon site a moi

server {

listen 80;

server_name localhost;

root /home/labo/www;

 

location / {

index index.php index.html;

}

 

location ~ \.php$ {

fastcgi_pass 127.0.0.1:9000;

include /etc/nginx/fastcgi_params;

fastcgi_index index.php;

}

}

Attention de bien avoir configurer la variable root (« root /home/labo/www » dans mon exemple), sinon vous risquez de tomber sur une erreur 404 lors du passage du script PHP vers le process PHP-FPM.

On relance ensuite Nginx:

sudo service nginx restart

Restarting nginx: nginx.

Pour tester que le PHP fonctionne bien, le plus simple est de créer un fichier info.php (à mettre à la racine du site /home/labo/www/) contenant:

<?php

phpinfo();

?>

Puis de pointer votre navigateur Web vers l’URL: http://localhost/info.php

La page suivante devrait s’afficher:

Support de Perl

Tout comme PHP, nous allons utiliser FastCGI pour exécuter les scripts Perl depuis notre serveur NGinx. Le principe est le même. Un processus (fastcgi-wrapper.pl) va se mettre en écoute sur le port TCP/8999 puis attendre les demandes d’exécution envoyées par NGinx.

Contrairement à PHP, il n’existe pas (encore) de package Ubuntu permettant d’automatiser l’installation de ce processus. Il faut donc mettre un peu les mains dans le cambouis (merci à ce blog) !

On commence par installer le module Perl FCGI sur lequel le processus fastcgi-wrapper.pl va se baser:

sudo perl -MCPAN -e ‘install FCGI’

On installe le processus fastcgi-wrapper.pl qui va s’occuper de l’exécution  des scripts Perl:

sudo wget -O /usr/bin/fastcgi-wrapper.pl http://lindev.fr/public/nginx/fastcgi-wrapper.pl

sudo chmod 755 /usr/bin/fastcgi-wrapper.pl

La plupart des tutos que j’ai trouvé sur le Net utilise ensuite un script init.d pas très beau à voir (http://lindev.fr/public/nginx/perl-fastcgi). En effet, pour arrêter le processus on a droit à un beau killall -9 perl ! Autant dire que si vous avez d’autres processus Perl en tache de fond de votre serveur cela risque de poser quelques problèmes :). J’ai donc écrit un nouveau script basée sur celui du wrapper PHP.

On automatise le lancement de ce script au démarrage du serveur:

sudo wget -O /etc/init.d/perl-fastcgi https://raw.github.com/nicolargo/ubuntupostinstall/master/perl-fastcgi

sudo chmod 755 /etc/init.d/perl-fastcgi

sudo update-rc.d perl-fastcgi defaults

Puis on le lance en tache de fond:

sudo service perl-fastcgi start

Il ne reste plus qu’à modifier le fichier de configuration Nginx de votre site pour prendre en compte les scripts Perl:

# Mon site a moi

server {

listen 80;

server_name localhost;

root /home/labo/www;

 

location / {

index index.php index.html;

}

 

location ~ \.php$ {

fastcgi_pass 127.0.0.1:9000;

include /etc/nginx/fastcgi_params;

fastcgi_index index.php;

}

 

location ~ \.pl$ {

fastcgi_pass 127.0.0.1:8999;

include /etc/nginx/fastcgi_params;

fastcgi_index index.pl;

}

}

On relance ensuite Nginx:

sudo service nginx restart

Restarting nginx: nginx.

Pour tester que le Perl fonctionne bien, le plus simple est de créer un fichier info.pl (à mettre à la racine du site /home/labo/www/) contenant:

#!/usr/bin/perl

print « Content-type: text/html\n\n »;

print « <html><body>Hello, world.</body></html> »;

Attention, contrairement au script PHP, les fichier .pl douivent avoir les droits en exécution sous peine de ce trouver devant le message suivant:

Error: No such CGI app – /home/labo/www/info.pl may not exist or is not executable by this process.

On doit donc saisir la commande:

chmod a+x /home/labo/www/info.pl

Puis de pointer votre navigateur Web vers l’URL: http://localhost/info.pl

La page suivante devrait s’afficher:

Optimisation corner !

On passe maintenant à quelques optimisations que l’on peut ajouter à la configuration de son site (merci à @T1B0).

On commence par le fait de ne pas loguer les message 404 sur le fichier favicon.ico (histoire de ne pas surcharger ses logs):

location = /favicon.ico {

access_log off;

return 204;

}

Ensuite on optimise la durée d’expiration des en-tête des fichiers statiques (pour les caches):

location ~* ^.+\.(jpg|jpeg|gif|css|png|js|xml)$ {

expires 30d;

}

Pour aller plus loin, vous pouvez également lire ce billet chez K-Tux. (notamment l’utilisation de memcache qui est intégré à NGinx !).

Conclusion

Vous avez donc à votre disposition un beau serveur Web NGinx avec le support FastCGI PHP & Perl !

Elle est pas belle la vie ?