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 fraiche de Debian Squeeze (version stable 6.0.2) 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

./firewall.sh

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).

Puis dans la section html du même fichier, il faut fixer les variables suivantes:

sendfile on;

keepalive_timeout 5;

tcp_nodelay off;

tcp_nopush on;

On relance le serveur pour prendre en compte la configuration:

/etc/init.d/nginx restart

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

/etc/init.d/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:

/etc/init.d/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 version francisée  de WordPress disponible sur le site officiel:

cd /var/www

wget http://fr.wordpress.org/wordpress-3.2.1-fr_FR.tar.gz

tar zxvf wordpress-3.2.1-fr_FR.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:

location / {

index index.php;

# Rewrite rules

if (!-e $request_filename) {

rewrite ^(.+)$ /index.php?q=$1 last;

}

}

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

/etc/init.d/nginx restart

Installation du plugin WordPress W3 Total Cache

J'utilise W3 Total Cache depuis maintenant 1 an et je suis très satisfait des performances de ce plugin WordPress qui optimise le temps de chargement et augmente les performances des blogs. L'installation se fait via l'interface Web d'administration de WordPress (menu Extensions > Ajouter).

Une fois installé et activé 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 les pré-requis sont installés, notamment:

Memcache extension: Installed

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 avec des visiteurs venant d'un peu partout sur la planète.

Ne pas oublier de désactiver le "Preview" qui rend caduque toutes les configurations quand il est actif (Enable).

Le plugin devrait produire un fichier nommé nginx.conf à la racine de votre blog (c'et à dire dans /var/www/wordpress). Ce fichier remplace en fait le fichier .htaccess dans le monde Apache. Nous allons devoir le mettre dans la configuration de notre serveur NGinx.

Afin de clarifier cette configuration j'ai créé l'arborescence suivante:

mkdir /etc/nginx/global

mkdir /etc/nginx/sites-available

mv  /etc/nginx/sites-enabled/default-site  /etc/nginx/sites-available/

cp  /etc/nginx/sites-available/default-site  /etc/nginx/sites-available/wordpress

ln -s /etc/nginx/sites-available/wordpress  /etc/nginx/sites-enabled/wordpress

Nous allons ensuite mettre le fichier de configuration généré par W3 Total Cache dans le répertoire global puis le renommer avec un nom plus explicite (wordpress-w3-total-cache.conf):

cp /var/www/wordpress/nginx.conf  /etc/nginx/global/wordpress-w3-total-cache.conf

Note: de part l'utilisation d'un permalink utilisant l'extension .html ( /%year%/%monthnum%/%postname%.html), j'ai du éditer ce fichier et supprimer les extensions .html et .htm sur la ligne suivante:

location ~ \\.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$ {

J'ai ensuite créé le fichier global/security.conf:

# 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;

}

et global/php-fpm.conf:

# PHP scripts -> PHP-FPM server listening on 127.0.0.1:9000

location ~ \\.php$ {

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

include fastcgi_params;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

}

Pour finalement modifier le fichier de configuration du site (/etc/nginx/site-enabled/wordpress) pour prendre en compte tout cela:

server {

listen 80;

server_name www.mondomaine.com;

location / {

root /var/www/wordpress;

index index.php index.html index.htm;

# Rewrite rules

if (!-e $request_filename) {

rewrite ^(.+)$ /index.php?q=$1 last;

}

# Security

include global/security.conf;

# W3 Total Cache

include global/wordpress-w3-total-cache.conf;

# PHP-FPM

include global/php-fpm.conf;

}

}

On redémarre le serveur Nginx pour appliquer la configuration:

/etc/init.d/nginx restart

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

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

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:

backend default {

.host = "127.0.0.1";

.port = "8080";

}

sub vcl_recv {

# Rules for all requests

# Only the blog URL is cached

#if (req.http.host ~ "(www.mondomaine.com)") { set req.backend = blog; }

#else { return (pass); }

# Compatiblity with Apache log

remove req.http.X-Forwarded-For;

set req.http.X-Forwarded-For = client.ip;

# Post requests will not be cached

if (req.request == "POST") {

return (pass);

}

# Normalize encoding/compression

if (req.http.Accept-Encoding) {

if (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; }

elsif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; }

else { remove req.http.Accept-Encoding; }

}

# Remove has_js and Google Analytics __* cookies.

if (req.http.cookie) {

set req.http.Cookie = regsuball(req.http.Cookie, "(^|;s*)(__[a-z]+|has_js)=[^;]*", "");

# Remove a ";" prefix, if present.

set req.http.Cookie = regsub(req.http.Cookie, "^;s*", "");

# Remove empty cookies.

if (req.http.Cookie ~ "^s*$") {

unset req.http.Cookie;

}

}

# Serve the page

unset req.http.vary;

# If I am logged in to wordpress, I DO NOT WANT TO SEE cached pages

if ( req.url ~ "^/wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_" ) {

return (pass);

} else {

# If I'm just a regular visitor

# If the request is static

if (req.url ~ ".(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)$") {

# Remove the cookie and make the request static

unset req.http.cookie;

return (lookup);

}

# Try to lookup in the cache

return (lookup);

}

# Cookie ? Not cacheable by default

if (req.http.Authorization || req.http.Cookie) {

return (pass);

}

# if host header is empty return 404

error 404 req.http.host;

return (lookup);

}

sub vcl_fetch {

#if (req.http.host ~ "(www.mondomaine.com)") {

# Do not cache POST requests

if (req.request == "POST") {

return (hit_for_pass);

}

# If the request is static

if (req.url ~ ".(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)$") {

# Cache it, and make it last 2 hours

set beresp.ttl = 7200s;

# Make the request static by removing any cookies set by those static files

unset beresp.http.set-cookie;

# Deliver the cached object

return (deliver);

}

# If I am logged in to wordpress, I DO NOT WANT TO SEE cached pages

if (req.http.cookie ~ "wordpress_logged_in") {

return (hit_for_pass);

} else {

# Cache anything for 2 minutes. When the cache expires it will be cached again and again, at the time of the request

set beresp.ttl = 120s;

return (deliver);

}

#}

}

sub vcl_deliver {

# Secure the header

remove resp.http.Via;

remove resp.http.X-Varnish;

remove resp.http.Server;

remove resp.http.X-Powered-By;

}

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

START=yes

NFILES=131072

MEMLOCK=82000

DAEMON_OPTS="-a :80 \\

-T localhost:6082 \\

-f /etc/varnish/default.vcl \\

-S /etc/varnish/secret \\

-p thread_pool_add_delay=2 \\

-p thread_pools=4 \\

-p thread_pool_min=200 \\

-p thread_pool_max=4000 \\

-p cli_timeout=25 \\

-p session_linger=100 \\

-s malloc,512M"

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:

/etc/init.d/firewall.sh restart

/etc/init.d/nginx restart

/etc/init.d/varnish restart

Pour que le plugin W3 Total Cache puisse interagir avec Varnish, il suffit d'activer la fonction suivante:

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.

Vus : 4025
Publié par Nicolargo : 402