Optimisation du serveur d'un site Web

Votre site est en ligne et vous avez tout fait pour optimiser son contenu. En êtes-vous absolument certain ? Avez-vous aussi optimisé le comportement de votre serveur ?

Dans cet article, nous abordons l'optimisation du traffic, côté serveur.

Aujourd'hui, plus de 60% des sites sont hébergés sur des serveurs Apaches (Usage statistics and market share of Apache for websites).

Dans cet artcile, nous allons voir comment optimiser le comportement du serveur avec des techniques utilisables méme dans le cas d'un hébergement pour lequel vous n'accédez pas à la confirguration intime d'Apache.

Le fichier .htaccess

Le fichier .htaccess est un fichier de configuration permettant de définir le comportement d'Apache pour le répertoire (et ses sous-répertoires) dans lequel il doit agir.

Il est donc tout à fait possible de mettre en place différentes stratégies dans un même site en plaçant plusieurs fichiers .htaccess à différents endroits, le fichier .htacess parent restant actif tant que les directives qu'il contient ne sont pas modifiées.

Pour notre travail d'optimisation, nous allons donc travailler sur le fichier .htaccess placé à la racine du site, car nous cherchons à améliorer le comportement pour l'ensemble du site.

Le fichier .htaccess est un simple fichier texte que vous pouvez éditer avec n'importe quel outil.

Note : Windows à du mal à travailler avec un fichier ne comportant qu'une extension. je vous suggère donc d'utiliser un éditeur texte un peu évolué ou de renommer, le temps de l'édition, le fichier en htaccess.txt, par exemple.

.htaccess : attention !

Le fichier .htaccess prend effet immédiatement, car il est lu à chaque requête sur votre serveur.

Cela signifie qu'une erreur de syntaxe ou de codage provoquera immédiatement un dysfonctionnement de votre site.

Par ailleurs, ce fichier permet des réglages fins et très puissants, alors ne le manipulez pas à la légère !

Enfin, il est à noter qu'une ligne débutant par # est considérée comme commentaire.

Vous pouvez faire des essais avec l'exemple ci-dessous (en prenant garde de ne pas écraser un fichier .htaccess déjà présent !), en commentant / décommentant les directives d'accès au contenu de votre site.

                                    
                                        #
                                        #  Cette directive n'est pas prises en compte :
                                        #     interdiction d'accès absolue au contenu
                                        # -------------------------------------------------------
                                        # deny from all
                                        
                                        #
                                        #  Alors que celle-ci est appliquée :
                                        #     autorisation de tous les accès
                                        # -------------------------------------------------------
                                        allow from all
                                    
                                

Gérer le contenu

Comme évoqué plus haut, le fichier htaccess.txt est lu lors de chaque accès au site.

En conséquence, limitez son contenu (donc sa taille) au minimu possible :

  • réduisez les commentaires à leur partie utile,
  • supprimez toutes les directives inutiles, par exemple :
    • des directives pour les fichiers *.swf n'ont pas de sens si vous n'tuilisez pas Flash,
    • des directives de restriction d'accès apportent-elles quelque chose pour un site totalement public ?

Pour exemple, le fichier htaccess.txt de 1 Ko ci-dessous :

                                    
                                        #
                                        #  Controles de comportement du site : www.monsite.com
                                        #  - auteur       : I. Ahounou
                                        #  - modification : 1er novembre 2012
                                        # =======================================================
                                        # 
                                        
                                        #
                                        #  Types MIME
                                        # -------------------------------------------------------
                                        AddType text/html .htm
                                        AddType text/html .html
                                        AddType application/x-httpd-php .foo
                                        AddType text/javascript .js
                                        AddType text/css .css
                                        AddType application/x-shockwave-flash .swf
                                        AddType video/x-flv .flv
                                        AddType image/gif .gif
                                        AddType image/jpg .jpg
                                        AddType image/png .png
                                        AddType application/pdf .pdf
                                        AddType application/zip .zip
                                        
                                        #
                                        #  Accès universel
                                        # -------------------------------------------------------
                                        allow from all
                    
                                        #
                                        #  Langue par défaut et charset
                                        # -------------------------------------------------------
                                        AddDefaultCharset UTF-8
                                        AddLanguage fr-FR .html .htm .css .js
                                        
                                        #
                                        # -------------------------------------------------------
                                        #  Fin du fichier .htaccess
                                        # -------------------------------------------------------
                                        #
                                    
                                

Nous remarquons de nombreuses choses inutiles :

  • la quantité de lignes de commentaires,
  • la description de types MIME standards,
  • l'accès universel au contenu, appliqué par défaut.

Il ne reste donc que l'application générique de la langue et du charset, qui sont une alternative viable si vous ne les décrivez pas dans le <header> des pages.


Il est donc possible, et recommandé, de transformer ce fichier, par exemple comme suit.

                                    
                                        #  I. Ahounou - 01/11/2012
                    
                                        #  Langue par défaut et charset
                                        AddDefaultCharset UTF-8
                                        AddLanguage fr-FR .html .htm .css .js
                                    
                                

Le fichier ne pèse plus que 128 octets et uniquement 2 directives sont prises en compte, sans altérer le comportement du serveur !

Utiliser la compression

Apache est capable de transmettre des fichiers compressés au navigateur client qui se charge alors de les décompresser.

En activant cette possibilité, les fichiers transmis sont allégés de manière souvent drastique et transitent donc plus rapidement vers l'internaute.
Vous me direz que la contrepartie est du temps de décompression. Vous avez raison. Mais au regard de la puissance des machines actuelles, le gain de temps reste largement appréciable.

Pour utiliser cette possibilité, votre serveur s'appuie sur le module MOD_DEFLATE que nous allons employer, uniquement s'il est opérationnel, avec la directive <IfModule module>...</IfModule>.


Attention

Suivant le serveur exécutant Apache, ce module est soit mod_deflate.c pour des environnements Unix, Linux, soit mod_deflate.so pour des environnements Windows. Le code ci-dessous propose les 2 tests de présence en utilisant uniquement l'identificateur.

Pour être véritablement efficace, il est important de préciser aux différents proxy intermédiaires de la chaîne de transmission Internet de ne pas décompresser le contenu à la place de l'internaute. Ceci est possible en ajoutant une directive de type header lors de l'utilisation de la compression serveur.

Mais bien entendu, il existe des incompatibilités avec certains navigateurs, comme Netscape et Internet Explorer (pour les anciennes versions).
Nous pouvons traiter ces cas par des tests avec la directive BrowserMatch test.

                                    
                                        <IfModule mod_deflate>
                                            # Compression avec MOD_DEFLATE
                                            AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml text/javascript application/x-javascript application/x-httpd-php
                    
                                            #Pour les navigateurs incompatibles
                                            BrowserMatch ^Mozilla/4 gzip-only-text/html
                                            BrowserMatch ^Mozilla/4\.0[678] no-gzip
                                            BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
                                            BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
                                            
                                            # Les proxies ne doivent pas décompresser à la place de l'internaute
                                            Header append Vary User-Agent env=!dont-vary
                                        </IfModule>
                                    
                                

Contrôler le cache du navigateur

En contrôlant l'activité du cache du navigateur client, il est possible de le forcer à enregistrer une copie locale des fichiers statiques (images, fichiers html, etc.), mais en conservant hors cache les fichiers dynamiques (php et cgi).

En réalisant cette opération, une partie non négligeable des fichiers ne transitent plus par Internet, mais sont directement lus depuis le disque dur de l'ordinateur. Gain de temps maximal pour l'affichage des pages, du moins pour les visiteurs réguliers !

Pour contrôler les fichiers mis en cache, nous allons utiliser la directive <FilesMatch test>...</FilesMatch>, pour manipuler le header.


Note : La syntaxe des tests utilisés par la directive FilesMatch s'appuie sur les expressions régulières. Vous pouvez vous familiariser, si nécessaire avec cette syntaxe, en utilisant les tutoriaux du site Expreg.com/ et réaliser des test préliminaires depuis le site Annuaire-Info.com.


                                    
                                        <IfModule mod_headers>
                                            # Mise en cache pour un mois
                                            <FilesMatch ".(ico|jpe?g|png|gif|swf|flv|gz)$">
                                                Header set Cache-Control "max-age=2592000"
                                            </FilesMatch>
                                        
                                            # Mise en cache pour 2 heures
                                            <filesMatch ".(css|js)$">
                                                Header set Cache-Control "max-age=7200"
                                            </filesMatch>
                                        
                                            # Désactive la mise en cache
                                            <FilesMatch ".(pl|php|cgi)$">
                                                Header unset Cache-Control
                                            </FilesMatch>
                                        </IfModule>
                                    
                                

Gérer le délai d'expiration

Dans la même logique que la gestion du cache, il est possible de préciser au serveur que des fichiers suffisament récent sont déjà en possession de l'utilisateur et qu'il n'est pas utile de les transmettre une nouvelle.

Pour cela, il faut utiliser les directives Expires... du module mod_expires.

Par exemple :

                                    
                                        <IfModule mod_expires>
                                            ExpiresActive On
                                            ExpiresDefault "access plus 7200 seconds"
                                            AddType image/x-icon .ico
                                            ExpiresByType image/gif "access plus 2592000 seconds"
                                            ExpiresByType image/ico "access plus 2592000 seconds"
                                            ExpiresByType image/jpg "access plus 2592000 seconds"
                                            ExpiresByType image/png "access plus 2592000 seconds"
                                            ExpiresByType image/jpeg "access plus 2592000 seconds"
                                            ExpiresByType image/icon "access plus 2592000 seconds"
                                            ExpiresByType image/x-icon "access plus 2592000 seconds"
                                            ExpiresByType text/css "access plus 2592000 seconds"
                                            ExpiresByType text/html "access plus 7200 seconds"
                                            ExpiresByType text/javascript "access plus 2592000 seconds"
                                            ExpiresByType application/xhtml+xml "access plus 7200 seconds"
                                            ExpiresByType application/x-javascript "access plus 2592000 seconds"
                                            ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
                                        </IfModule>
                                    
                                
Note

A priori, la gestion du délai d'expiration n'est pas utile dans le cas de l'usage de la mise en cache et réciproquement. Choisissez l'une des deux méthode et allégez votre fichier .htaccess !

Gestion des versions de fichier

Le ETAG permet d'identifier la version d'un fichier. Ainsi, en l'utilisant, le serveur sait s'il y a eu une mofidification du fichier depuis la précédente requête et peut donc décider, opportunément, de le transmettre.

L'inconvénient de cette gestion, est que le serveur et le client doivent s'informer mutuellement pour chaque fichier, ce qui consomme de la bande passante et du délai de réactivité.

Ma recommandation est donc de désactiver cette fonctionnalité.

                                    
                                        Header unset ETag
                                        FileETag none
                                    
                                

Conclusion

En conclusion, vous trouverez ci-dessous la synthèse des paramétrages évoqués.

                                    
                                        # Compression
                                        <IfModule mod_deflate>
                                            # Compression avec MOD_DEFLATE
                                            AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml text/javascript application/x-javascript application/x-httpd-php
                                            
                                            #Pour les navigateurs incompatibles
                                            BrowserMatch ^Mozilla/4 gzip-only-text/html
                                            BrowserMatch ^Mozilla/4\.0[678] no-gzip
                                            BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
                                            BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
                                            
                                            # Les proxies ne doivent pas décompresser à la place de l'internaute
                                            Header append Vary User-Agent env=!dont-vary
                                        </IfModule>
                                                  
                                        # Cache
                                        <IfModule mod_headers>
                                         # Mise en cache pour un mois
                                         <FilesMatch ".(ico|jpe?g|png|gif|swf|flv|gz)$">
                                          Header set Cache-Control "max-age=2592000"
                                         </FilesMatch>
                                        
                                            # Mise en cache pour 2 heures
                                         <filesMatch ".(css|js)$">
                                          Header set Cache-Control "max-age=7200"
                                         </filesMatch>
                                        
                                         # Désactive la mise en cache
                                            <FilesMatch ".(pl|php|cgi)$">
                                          Header unset Cache-Control
                                         </FilesMatch>
                                        </IfModule>
                                        
                                        # Expiration
                                        <IfModule mod_expires>
                                            ExpiresActive On
                                            ExpiresDefault "access plus 7200 seconds"
                                            AddType image/x-icon .ico
                                            ExpiresByType image/gif "access plus 2592000 seconds"
                                            ExpiresByType image/ico "access plus 2592000 seconds"
                                            ExpiresByType image/jpg "access plus 2592000 seconds"
                                            ExpiresByType image/png "access plus 2592000 seconds"
                                            ExpiresByType image/jpeg "access plus 2592000 seconds"
                                            ExpiresByType image/icon "access plus 2592000 seconds"
                                            ExpiresByType image/x-icon "access plus 2592000 seconds"
                                            ExpiresByType text/css "access plus 2592000 seconds"
                                            ExpiresByType text/html "access plus 7200 seconds"
                                            ExpiresByType text/javascript "access plus 2592000 seconds"
                                            ExpiresByType application/xhtml+xml "access plus 7200 seconds"
                                            ExpiresByType application/x-javascript "access plus 2592000 seconds"
                                            ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
                                        </IfModule>
                    
                                        # Désactivation ETAG
                                        Header unset ETag
                                        FileETag none
                                    
                                

Après essai, voici les résultats mesurés :

Page d'accueil Images optimisées
Premier accès, cache vide
Sans optimisation .htaccess 6,09 s 7,27 s
Avec optimisation .htaccess 3,95 s 3,71 s
Gains 2,14 s (= 35%) 3,56 s (= 49%)
 
Nouvel accès
Sans optimisation 4,35 s 3,65 s
Avec optimisation 2,23 s 1,9 s
Gains 2,12 s (= 49%) 1,75 s (= 48%)

Le constat est sans appel : en moyenne 45% de temps de chargement gagné pour chaque page.


Maintenant, c'est à vous, car n'oublions pas qu'il est communément admis qu'à chaque seconde de chargement d'une page, c'est 10 internautes qui fuient !