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 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
Blog Open-source Systeme Web

12 étapes pour optimiser les performances de son blog WordPress

Lorsque l’on choisi d’héberger son blog WordPress (sur un serveur dédié ou virtuel), la problématique des performances vient assez vite sur le tapis. En effet, l’optimisation du blog permet non seulement de réduire le temps de chargement des pages (et donc d’être bien vu par seigneur gOOgle) mais également de dimensionner au plus juste son serveur: gain de temps d’un coté, gain d’argent de l’autre.

Nous allons donc dans ce billet parcourir une liste non exhaustive de techniques d’optimisations:

  • ETAPE 1: Hardware
  • ETAPE 2: Noyau Linux
  • ETAPE 3: Mise à jour du système d’exploitation
  • ETAPE 4: MemCached
  • ETAPE 5: Les modules Apache
  • ETAPE 6: Configuration d’Apache
  • ETAPE 7: XCache (PHP)
  • ETAPE 8: MySQL
  • ETAPE 9: WP-DBManager
  • ETAPE 10: W3 Total Cache
  • ETAPE 11: Thème WordPress
  • ETAPE 12: Tester/Surveiller

Les commentaires seront bien sur là pour nous faire partager vos solutions !

Le hardware

ETAPE 1) C’est un peu le serpent qui se mort la queue… En effet il est assez difficile de dimensionner le hardware d’un serveur sans avoir fait les optimisations est sans connaitre précisément le trafic du blog (surtout vrai pour les nouveaux blog).

C’est en partie pour ces raisons qui j’ai choisi un serveur VPS de chez Gandi. En effet il est possible d’augmenter ou de diminuer les « parts » affectées à son serveur de manière dynamique (une « part » correspond à une ressource CPU, mémoire et disque).

J’ai actuellement « 3 parts » sur le serveur du Blog de Nicolargo mais je m’en sers également pour d’autres besoins (je pense que pour ce blog, un serveur avec « 2 parts » suffirait largement). Pour une première expérience dans le monde du blogging, un serveur « 1 part » devrait convenir (environ 12€ HT par mois).

Je n’entrerai pas dans les discussions sur le coups relativement élevé de cette solution par rapport à un serveur dédié comme l’offre Dedibox de Online.net.

Le système d’exploitation

L’optimisation du système d’exploitation dépend bien sûr de la distribution Linux utilisée. Lors de la création de mon serveur j’ai choisi d’utiliser Ubuntu Server 8.04 que j’ai fait évolué en 9.04. Pourquoi cette distribution GNU/Linux ? Tout simplement car c’est celle que je connais le plus…

ETAPE 2 ) On commence par optimiser le noyau Linux . Je passe rapidement sur les explications. Il existe de nombreux article sur le net détaillant ces configurations. La configuration donnée est celle de mon serveur VPS (3 parts, 1 Go de RAM), elle doit être adaptée à votre configuration hardware.

Il faut éditer/modifier le fichier /etc/sysctl.conf (disponible sur GitHub):


Puis on applique:

sudo sysctl -p

Sources:

ETAPE 3) La première chose à faire quand on administre un serveur est bien entendu de le maintenir à jour au niveau des logiciels systèmes et applicatifs. Pour cela je m’aide d’un petit logiciel nommé cron-apt. Ce dernier permet de m’avertir par mail quand une mise à jour est disponible (par exemple une nouvelle version d’Apache ou une librairie PHP). En plus de corriger des failles de sécurités, les mises à jours permettent souvent d’obtenir de meilleures performances (que ce soit en rapidité ou en consommation de ressources).

L’installation est des plus simple:

sudo aptitude install cron-apt

Configuration en éditant le fichier /etc/cron-apt/config, notamment les lignes suivantes:

MAILTO= »nom@domaine.com »

MAILON= »always »

Un mail sera automatiquement envoyé à l’adresse nom@domaine.com, tout les matins à 4:00. Voici un exemple:

On peut voir qu’une mise à jour est disponible. Il ne reste plus qu’a se connecter en SSH sur le serveur et faire un:

sudo aptitude safe-upgrade

Il est possible de faire automatiquement les mises à jour mais je pense cela risqué si quelque chose se passe mal…

On critique souvent les serveurs VPS pour leurs faibles performances disque. Bien que je trouve celle des VPS Gandi plutôt acceptable (environ 6 Mo/s pour l’écriture et 24 Mo/s pour la lecture de petits fichiers type script PHP), il est intéressant de mettre en place un cache mémoire sur notre serveur. Ainsi, les applications compatibles pourront lire et écrire les données en RAM et non plus sur disque.

ETAPE 4) Nous allons donc installer MemCached, un cache mémoire libre.  On commence par installer le cache ainsi que la librairie Perl associée (qui sera utilisée par WordPress):

sudo aptitude install libcache-memcached-perl php5-memcache memcached

Par défaut, le cache écoute sur l’adresse 127.0.0.1 et sur le port TCP/11211. La taille du cache mémoire est de 64 Mo. J’ai gardé ces paramètres pour mon utilisation.

On peut obtenir des statistiques sur l’utilisation de MemCached en utilisant la commande:

# echo « stats » | nc localhost 11211

STAT pid 2806

STAT uptime 698465

STAT time 1283351366

STAT version 1.2.2

STAT pointer_size 32

STAT rusage_user 31.829989

STAT rusage_system 123.891742

STAT curr_items 12834

STAT total_items 1394993

STAT bytes 48830599

STAT curr_connections 11

STAT total_connections 16845

STAT connection_structures 31

STAT cmd_get 4012823

STAT cmd_set 1394993

STAT get_hits 2547543

STAT get_misses 1465280

STAT evictions 5694

STAT bytes_read 10561103955

STAT bytes_written 37908972470

STAT limit_maxbytes 67108864

STAT threads 1

END

Apache & PHP

On continue ensuite avec l’optimisation du serveur Apache (version 2.xx au moment de l’écriture de ce billet).

ETAPE 5) Apache se base sur un système de modules pour ajouter de nouvelles fonctions à votre serveur Web. Sous Ubuntu Server, la liste des modules actifs se trouvent dans le répertoire /etc/apache2/mods-enabled. Un petit ls dans ce répertoire vous donne donc la liste. L’optimisation consiste à supprimer les modules non utilisés. Je vous conseille la lecture de ce billet qui donne la liste des modules nécessaires au fonctionnement de WordPress. Attention, si votre serveur héberge d’autres sites Web que votre blog, il faut vérifier de ne pas supprimer un module utile…

Voici la liste de mes modules sur mon serveur:

alias.conf autoindex.conf dir.conf negotiation.load

alias.load autoindex.load dir.load php5.conf

auth_basic.load cgi.load env.load php5.load

authn_file.load dav.load expires.load rewrite.load

authz_default.load dav_svn.conf headers.load setenvif.conf

authz_groupfile.load dav_svn.load mime.conf setenvif.load

authz_host.load deflate.conf mime.load status.conf

authz_user.load deflate.load negotiation.conf status.load

ETAPE 6) On configure ensuite la manière dont les processus Apache sont lancés et gérés en mémoire et d’autres paramètres. Il faut éditer la section suivante dans le fichier /etc/apache2/apache2.conf (ou httpd.conf sur d’autre distribution GNU/Linux). Pour une description des paramètres, merci de lire le billet suivant:

<IfModule mpm_prefork_module>

StartServers 5

MinSpareServers 5

MaxSpareServers 10

MaxClients 40

MaxRequestsPerChild 2000

</IfModule>

# KeepAlive: Whether or not to allow persistent connections

KeepAlive On

# MaxKeepAliveRequests: The maximum number of requests to allow

MaxKeepAliveRequests 200

# KeepAliveTimeout: Number of seconds to wait for the next request

KeepAliveTimeout 5

# Timeout: The number of seconds before receives and sends time out.

Timeout 50

J’ai également modifier le fichier /etc/apache2/conf.d/optimization pour gagner quelques précieux  points aux tests Yslow et Page Speed:

Header unset ETag

FileETag None

On applique la configuration en relançant Apche:

sudo /etc/init.d/apache2 restart

Sources:

ETAPE 7) WordPress se base sur le langage PHP qui est connu pour être flexible mais pas très performant. C’est pour cela qu’il est nécessaire d’installer un cache PHP sur votre serveur Web WordPress. En gros, il permet de mettre en cache le code PHP déjà compilé. J’utilise personnellement XCache.

L’installation est simple:

sudo aptitude install php5-xcache

On configure ensuite le fichier/etc/php5/conf.d/xcache.ini (à adapter à votre configuration):

xcache.size = 64M

On relance le serveur Web:

sudo /etc/init.d/apache2 restart

Source:

MySQL

Souvent décriée, MySQL reste à l’heure actuelle la base de donnée officielle supportée par le moteur de blogging WordPress. Nous allons donc étudier quelques techniques d’optimisation.

ETAPE 8) On commence par éditer le fichier de configuration /etc/mysql/my.cnf pour ajuster la taille des caches (encore une fois les valeurs sont à adapter en fonction de votre audience/configuration):

query_cache_type = 1

query_cache_limit = 2M

query_cache_size = 32M

ETAPE 9) On installe ensuite le plugin WordPress WP-DBManager. Ce dernier permet de maintenir une base de données optimisée à travers le temps. En plus des fonctions de sauvegarde (manuelle ou automatique) et de restauration de votre base de données WordPress, ce plugin permet de d’optimiser et réparer cette même base.

Source:

WordPress

ETAPE 10) L’installation standard de WordPress (la fameuse installation en 5 minutes) ne tient pas en compte de l’optimisation. Nous allons voir comment configurer l’utilisation parallèle de XCache et Memcached (préalablement installé dans les étapes n°3 et n°5). Pour cela nous allons utiliser l’indispensable plugin W3 Total Cache.

Après l’installation du plugin, il faut se rendre dans le menu Performance > General setting de la page d’administration de WordPress puis cliquer sur le bouton Compatibility check pour vérifier que XCache et Memcached sont bien détectés:

Opcode cache: XCache

Memcache extension: OK

Ensuite on configure WordPress pour utiliser Memcached en activant toutes le fonctions de cache (CDN mis à part) et en utilisant le démon Memcached. Exemple de configuration pour les pages:

Dans le menu Page cache settings j’active toutes les fonctions sauf pour les pages 404:

Dans le menu suivant (Minify settings), j’active toutes les fonctions. Cela à pour but d’optimiser les pages, css et js avant d’être envoyés vers les lecteurs (attention, certains JS n’aiment pas beaucoup ces optimisations, à tester donc…).

Enfin, dans le menu Browser Cache setting, j’active toutes les fonctions et les expires header lifetime à:

  • 3600 secondes pour JS / CSS
  • 3600 secondes pour le HTML
  • 2592000 secondes pour les autres fichiers

A l’heure actuelle, le trafic généré par mon blog ne nécessite pas l’utilisation de caches réseau répartis (CDN). Mais c’est une optimisation à prendre en compte pour les « gros » sites.

Sources:

ETAPE 11) Rien ne sert d’avoir un kernel Linux, un serveur Web, un moteur PHP et un WordPress optimisés si le thème de votre blog est mal développé. Il est important de tester ce thème et notamment les plugins utilisées. Ces derniers utilisent souvent des JavaScripts qui peuvent pénaliser fortement le temps de chargement de vos pages. Rien de tel que des mesures de type YSlow et Page Speed pour mettre en évidence ce qui ne va pas.

Sources:

Tester/surveiller son serveur

ETAPE 12) Pour tester les optimisations mise en place, j’utilise l’outil  GTMetrix qui donne les valeurs YSlow et Page Speed (avec un archivage vous permettant de voir l’évolution des performances de votre blog à travers le temps).

De manière locale et surtout pour valider la configuration de votre serveur Web (Apache dans ce document), vous pouvez utiliser la commande suivante:

ab -t30 -c5 http://blog.mondomaine.com/

La ligne intéressante donnant le nombre maximal de requête par seconde que votre blog peut supporter est la suivante:

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

A un niveau plus bas, la commande Linux netstat permet de donner pas mal d’informations sur l’état des sockets:

netstat -tan | grep ‘:80 ‘ | awk ‘{print $6}’ | sort | uniq -c

Enfin, pour surveiller l’activité de MySQL, j’utilise la commande MySqlReport.

Autres optimisations possibles

D’autres optimisations sont possibles, pour vous donner un exemple, je suis tombé l’autre jour sur le première article d’une série en cours sur le blog d’Antoine Benkemoun qui propose d’utiliser Squid pour booster les performances de votre site. C’est une technique très intéressante mais qui nécessite, pour être vraiment efficace, l’utilisation deux deux machines différentes. Une servant de reverse proxy-cache et une autre hébergeant votre blog.

Il est aussi possible de se passer du serveur Web Apache (il est vrai un peu lourd à administrer) pour se pencher vers des serveurs plus légers comme NGinx ou Cherookee. Update: Ou bien d’utiliser NGinx comme serveur Web pour les pages statiques et Apache pour les pages dynamiques (voir exemple de configuration ici). L’avantage d’une telle configuration est un gain non négligeable en terme de consommation mémoire.

Il existe un nombre incalculable d’optimisations possibles, j’espère d’ailleurs en découvrir de nouvelles dans vos commentaires…