Apache2 c’est un peu le dinosaure du web. Le serveur de la fondation du même nom n’a plus à être présenté. Moderne, hyper configurable, puissant, quoi qu’on en dise, il reste un incontournable et répond à la plupart des besoins. Voyons tout de même en détail comme l’installer et l’optimiser.
Mesdames, Messieurs, oui, j’ai bien dit l’optimiser. On a l’habitude d’installer Apache avec un simple coup d’apt-get
et puis s’en vont. Or s’il est vrai que la configuration par défaut suffit à bien des usages, il ne fait aucun mystère qu’une config plus fine apportera sécurité, rapidité et scalabilité.
Installation
Toutes les commandes exécutées ci-après sont exécutées en root. Pensez donc à passer en root avec sudo su
ou à faire précéder vos commandes de sudo
.
Le serveur Apache est bien entendu disponible dans les dépôts de Debian et d’Ubuntu. Pour l’installer, nous pouvons nous contenter d’un :
apt-get install apache2
Cependant, si l’on veut profiter des dernières fonctionnalités, telle que le http2, il va falloir installer une version plus moderne que celle proposée dans les dépôts.
add-apt-repository ppa:ondrej/apache2 apt-get update apt-get install apache2
On a ici au préalable ajouté un depôt « ppa » non officiel contenant les dernières versions d’Apache. Ce dernier dépôt est maintenu par le mainteneur de PHP des dépôts Debian. On peut donc s’y fier sans trop de craintes. Je n’ai pas vérifié, mais ça marche normalement aussi sur Debian.
C’est tout pour l’installation. Entrez maintenant l’adresse ip de votre serveur dans un navigateur, si tout s’est bien déroulé, vous devriez obtenir ce message :
It works! This is the default web page for this server. The web server software is running but no content has been added, yet.
Le dossier dans lequel se trouvent les fichiers HTML par défaut se situe dans /var/www/html/
et le texte que vous venez de lire est tout simplement ce qui est contenu dans /var/www/html/index.html
.
Bien qu’on puisse utiliser apache out of the box, en plaçant simplement nos fichiers html dans www/html/
, nous allons explorer les options de configuration les plus courantes.
Création des VirtualHosts
Vous pouvez grâce à cette technique, héberger plusieurs sites sur le même serveur Apache. Attention cependant, pour qu’Apache puisse savoir vers quel site il doit vous rediriger, il faut que vous y accédiez via un nom de domaine, c’est grâce à ce dernier qu’il sera en mesure de vous présenter le bon site. Ceci ne marchera donc pas si vous entrez directement l’adresse ip du serveur dans votre navigateur. Néanmoins, pour les besoins de tests, vous pouvez modifier votre fichier hosts pour simuler une résolution DNS.
Apache possède deux répertoires dans /etc/apache2/
dans lesquels on place nos VHosts : sites-available
et sites-enabled
. Le premier regroupe tous les sites disponibles, tandis que le second concerne les sites actifs.
Ainsi, Apache n’ira pas regarder les VHosts contenus dans sites-available
. Cela permet donc de faire des tests, de temporairement retirer un site, de préparer un nouveau site ou une migration etc. Lorsque tout est prêt, il suffit de faire un lien symbolique depuis sites-available
vers sites-enabled
. Apache fournit même une commande spécialement à cet effet : a2ensite nom_du_vhost
ainsi que son pendant inverse a2dissite nom_du_vhost
.
Créons maintenant notre premier VHost dans /etc/apache2/sites-available/buzut.conf
.
# Apache doit écouter sur le port 80 pour le http # il est aussi possible de répondre à des requêtes sur des ports non standards # ou même de ne pas définir de port spécifique en utilisant "*" <VirtualHost *:80> # nom d'hôte que le serveur utilise ServerName buzut.fr # noms alternatifs que le serveur utilise pour servir le même contenu ServerAlias www.buzut.fr blog.buzut.fr # email de contact de l'administrateur # apache l'affiche sur certaines pages d'erreurs ServerAdmin adresse@mail.com # path de la racine du contenu à servir DocumentRoot /var/www/buzut/ # ces règles s'appliquent à la racine # et à tous les répertoires et fichiers descendants <Directory /var/www/buzut/> # interdiction de lister les fichiers dossier # au cas où pas de page index présente # suivre les liens symboliques (gain de performance) Options -Indexes +FollowSymLinks # .htaccess peut redéfinir ces paramètres [All|None] # on gagne en performance à mettre à none # on perd néanmoins en souplesse de configuration AllowOverride None # on précise que tous les utilisateurs ont accès au dossier web # ainsi, en cas de maintenance, on peut s'autoriser uniquement soi même Require all granted </Directory> # on peut néanmoins les redéfinir ou les compléter pour un répertoire particulier <Directory /var/www/buzut/> Options Indexes </Directory> </VirtualHost>
VirtualHost
et ServerName
Nous avons configuré ce VirtualHost pour répondre à toutes les requêtes sur le port 80 : *:80
. Il est également possible de préciser une ip mais cela ne fait sens que dans le cas où le serveur sert des sites sur plusieurs ip publiques distinctes.
Par ailleurs, qu’il s’agisse d’ip ou de port, la directive VirtualHost ne modifie en aucun cas la configuration dictée par la directive Listen
. Donc si le serveur n’est pas configuré pour écouter sur un port donné, le VHost mentionnant ce port ne sera d’aucune utilité.
En outre, le fait que ce VHost commence par *:80
ne signifie pas qu’il gère toutes les requêtes vers ce serveur sur ce port. Apache utilise le VirtualHost le plus spécifique correspondant à une requête pour y répondre. Pour configurer un autre VHost, il suffit de spécifier un autre bloc avec un ServerName
différent. D’ailleurs, si vous n’avez qu’un VHost, ou pour en utiliser un par défaut, vous pouvez tout à fait omettre la directive ServerName
.
Notez bien qu’un fichier de configuration de VHost peut contenir autant de directives VirtualHost
que vous le souhaitez, donc autant de sites ou domaines différents. Mais il est tout de même recommandé de séparer les configurations de sites n’ayant rien à voir dans des fichiers différents. Cela vous permettra en outre de les activer et désactiver indépendamment les uns des autres.
DocumentRoot
DocumentRoot
concerne la racine du site à servir. En théorie, Apache ne servira rien qui soit en dehors de ce path, et tout chemin défini dans l’url est relatif à cette racine. Si j’emploie le terme en théorie, c’est parce qu’il est possible avec les liens symboliques et avec la directive Alias
de dire à Apache de servir des éléments se trouvant hors de la racine.
Revenons-en à notre root. Si celle-ci est définie à /var/www/buzut/
et que l’url accédée est https://buzut.fr/wp-content/themes/buzut-theme/img/logo.jpg
, Apache ira chercher logo.jpg
sur le serveur dans /var/www/buzut/wp-content/themes/buzut-theme/img/logo.jpg
.
En outre, si l’url tente d’accéder à un répertoire, Apache tentera de servir le fichier défini par la directive DirectoryIndex
(en général index.html
, .php
, .pl
, ou .cgi
).
Cette configuration par défaut peut bien entendue être modifiée au niveau du VHost : DirectoryIndex landing.html
. Par ailleurs, si aucun de ces fichiers n’est présent, Apache tentera d’afficher un listing du répertoire si l’option Indexes
est présente.
Vous l’aurez peut-être noté, mais si par défaut Indexes
est désactivé dans notre racine (-Indexes
), c’est que cette option permet de parcourir les fichiers et répertoires du serveur (dans la limite de ce qui est accessible publiquement). À moins que cela soit explicitement recherché, il n’y a pas lieu de laisser quiconque naviguer dans notre arborescence.
Directory
Cette directive permet de définir les règles qui s’appliquent à un répertoire, ses fichiers et sous-répertoires. Require
permet de controler qui accède à ces ressources. Ici, tout le monde, Require all denied
refuserait l’accès à tout le monde. On peut également n’autoriser que certaines addresses comme le souligne Eric dans les commentaires.
Require host my_alloweddomain.name Require ip 192.168.0.110 # autorise une seule ip Require ip 192.168.1.0 /24 # autorise 192.168.1.1 à 192.168.1.254 Require ip 172.16.0.0/16 # autorise 172.16.0.1 à 172.16.255.254 Require ip 10.0.0.0/8 # autorise 10.0.0.1 - 10.255.255.254
Pour en savoir plus sur ces directives, vous avez la doc à votre disposition.
Comme expliqué dans les commentaires de l’exemple, il est possible d’appliquer un comportement particulier à un sous-répertoire en définissant de nouvelles règles dans une directive Directory
plus spécifique.
Le AllowOverride
dont il est fait mention permet à un fichier .htaccess
de redéfinir les règles s’appliquant à un répertoire directement depuis celui-ci. Il suffit pour cela de placer les règles s’appliquant à Directory
dans un fichier nommé .htaccess
que l’on place dans le répertoire en question.
Sachez toutefois que lorsque cette option est activée, Apache doit vérifier pour chaque répertoire si un fichier .htaccess
est présent. Dans le cas d’arborescences profondes, cela peut générer un travail supplémentaire non négligeable pour Apache et impacter les performances.
Les modules complémentaires
Selon les besoins de votre site, il vous faudra peut-être activer des modules supplémentaires. Par exemple, si vous utilisez l’URL-rewriting, il faudra activer le module mod_rewrite
:
a2enmod rewrite Enabling module rewrite. To activate the new configuration, you need to run: service apache2 restart
Il nous est dit qu’il faut redémarrer le serveur : To activate the new configuration, you need to run: service apache2 restart
. Alors redémarrez-le.
Apache possède de très nombreux modules qui viennent élargir ses fonctionnalités. Vous trouverez sur le site officiel la liste de tous les modules disponibles.
Puisque nous parlons des modules, nous allons aussi en désinstaller quelques uns dont nous n’avons pas l’utilité. Une bonne politique dans la gestion d’un serveur est que tout ce qui ne sert pas peut être désactivé et supprimé. D’une part ceci nous permet d’économiser des ressources (les modules d’apache prennent de la place en mémoire), d’autre part, ce sont autant de failles potentielles que l’on supprime.
En ce qui me concerne, je ne vire que le mod CGI (et il sera utile pour ceux utilisant PHP-FMP), la plupart de ceux pre-activés servent souvent.
Vous utiliserez pour désactiver les mods la commande a2dismod
suivi du nom du module à désactiver. Ex : a2dismod autoindex
. Il peut être judicieux de ne pas tous les supprimer d’un coup et de tester après chaque désactivation si tout marche bien. Vous pouvez aussi utiliser la commande apache2ctl configtest
qui vérifie la syntaxe de vos fichiers de config. Ça peut s’avérer intéressant si par exemple vous désactivez un mod dont vous avez besoin et auquel vous faites appel dans vos fichiers dans /etc/apache2/sites-enabled
.
Note : je dis supprimer, mais n’allez pas supprimer ensuite le fichier du module, ça ne sert à rien pour le peu d’espace que vous allez gagner, et si vous en avez besoin pour une raison x ou y plus tard, vous serez content de n’avoir qu’à le réactiver.
Au besoin, vous trouverez dans mon article regroupant les commandes Linux les plus utiles, une partie web qui reprend l’ensemble des commandes Apache utiles.
Par ailleurs, si vous souhaitez exécuter du php, il va falloir l’installer aussi. Sans lui, notre serveur Apache servira vos fichiers de code php tels quels. Admettons-le, c’est moyen…
SSL/TLS et HTTP/2
SSL/TLS, je ne pense pas avoir besoin de l’expliquer. Mais HTTP/2, qu’est-ce que c’est ? Tout simplement la dernière version du protocole de la norme HTTP. Cette version apporte de nombreux avantages dont un sérieux gain en performances.
HTTP/2 ne fonctionne qu’en TLS. De toute façon, avec l’émergence de Let’s Encrypt et ses certificats TLS gratuits, nous n’avons plus aucune excuse pour ne pas offrir une connexion sécurisée à nos sites.
Pour installer un certificat Let’s encrypt, je vous laisse entre les mains de la doc officielle.
Vous voilà en possession de vos certificats, voyons donc à quoi ressemble notre VHost TLS et HTTP/2.
# on redirige le http vers le https <VirtualHost buzut.fr:80> ServerName buzut.fr ServerAdmin adresse@mail.com Redirect permanent / https://buzut.fr/ </VirtualHost> # le port par défaut du https est 443, on pense donc bien à le spécifier <VirtualHost buzut.fr:443> # on active le http/2 avec fallback vers le http/1.1 # tous les navigateurs ne sont pas compatibles Protocols h2 http/1.1 ServerName buzut.fr ServerAdmin adresse@mail.com DocumentRoot /var/www/buzut ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # on active le ssl/tls et on renseigne les certificats SSLEngine on # et on renseigne les path vers les certificats # # Fichier de données contenant le certificat X.509 du serveur codé en PEM SSLCertificateFile /etc/letsencrypt/live/buzut.fr/cert.pem # Fichier contenant la clé privée du serveur codée en PEM SSLCertificateKeyFile /etc/letsencrypt/live/buzut.fr/privkey.pem # Fichier contenant les certificats de CA du serveur codés en PEM SSLCertificateChainFile /etc/letsencrypt/live/buzut.fr/chain.pem # on active HSTS pour 6 mois pour le domaine et les sous-domaines # on autorise aussi l'ajout du site dans les listes pre-chargées Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" </VirtualHost>
Pour activer TLS, il faut donc trois choses :
- définir le port d’écoute à 443,
- activer le support de tls avec
SSLEngine on
, - définir les chemins vers les différents certificats et clefs.
Par ailleurs, les modules permettant le support du TLS et de http2 ne sont pas forcement activés. Pour ce faire, on fera simplement un petit coup de a2enmod
:
a2enmod ssl && a2enmod http2 service apache2 restart
Nous nous sommes ici contenté d’activer le TLS (bien que le module s’appelle SSL !). Cependant, si la sécurité vous intéresse, il est possible d’affiner la configuration du module TLS. Vous pouvez d’ailleurs tester votre serveur avec ce scanner SSL/TLS et générer vos configurations serveurs avec le générateur de Mozilla.
Tout ce qui ne concerne pas directement le vhost trouve sa place directement dans le module ssl situé dans /etc/apache2/mods_available/ssl.conf
.
Si vous souhaitez en savoir plus sur le HSTS, je vous laisse avec l’article Wikipedia qui est bien détaillé.
Les fichiers de log
Par défaut, apache écrits ses logs dans /var/log/apache2
. Il y a trois fichiers distincts :
- Le
error.log
, qui regroupe toutes les erreurs de apache ainsi que de ces modules (c’est donc là que vous retrouverez par exemple les erreurs de php), - L’
access.log
, qui regroupe les logs d’accès au serveur principal, - Le
other_vhosts_access.log
, qui logue les accès des autres VHosts.
En réalité, la définition du fichier de log des accès se fait dans le VHost. Si vous voulez écrire vos logs dans le access.log
au lieu du other_vhosts_access.log
, ou même définir vous-même le nom de fichier de log, il va vous falloir rajouter une ligne dans le VHost.
CustomLog ${APACHE_LOG_DIR}/access.log combined
Vous pouvez remplacer access.log par le nom qui vous plaît si vous voulez en changer. Quant à combined
, cela concerne le format des logs. Pour en savoir plus à ce sujet, je vous invite à aller consulter la doc.
Petit point de détail cependant, si vous ne spécifiez pas explicitement le access.log
dans votre VHost, les logs iront automatiquement dans other_vhosts_access.log
. Ce comportement peut ne pas convenir.
Nous pourrions par exemple vouloir ne pas activer les logs d’accès (pour des questions de performances par exemple). Dans ce cas, il va falloir désactiver une configuration. Laissez-moi donc introduire la commande a2disconf
. Vous l’aurez deviné, elle va de paire avec a2enconf
. Pour désactiver le other_vhosts_access.log
, il faut donc exécuter :
a2disconf other-vhosts-access-log
Enfin, pour activer ce petit VHost, nous allons désactiver le site default, et activer le notre. Pour se faire, nous allons utiliser deux commandes :
a2dissite
, qui permet de désactiver un vhost,a2ensite
, qui, à l’inverse, permet de les activer.
a2dissite default Site default disabled. To activate the new configuration, you need to run: service apache2 reload a2ensite mon_site Enabling site default. To activate the new configuration, you need to run: service apache2 reload service apache2 reload * Reloading web server config apache2 ...done.
Le serveur nous spécifie la commande à effectuer pour que les modifications soient prisent en compte. Il n’est pas ici nécessaire de redémarrer apache, un simple rechargement avec la commande service apache2 reload
suffit.
Sécurité
Les CHMOD
Afin de bien sécuriser son serveur, il ne s’agit pas simplement de « balancer » les fichiers sur le serveur. Il faut accorder une vigilance toute particulière aux droits que possèdent ces fichiers.
La base consiste à donner le moins de droits possible aux fichiers et répertoires. Ainsi, le chmod devra être à 555 pour les répertoires et à 444 pour les fichiers. Si le propriétaire des répertoires et fichiers est le compte du développeur et non le serveur web, il peut être pratique de passer à respectivement 755 et 744. De cette manière, vous pourrez éditer vos fichiers sans passer en root.
J’ai écrit un article détaillé au sujet des CHMOD dans le contexte de l’hébergement web. N’hésitez pas à vous y référer pour plus de détails.
Le fichier de configuration security
Il existe un fichier de configuration relatif à la sécurité d’apache : /etc/apache2/conf-available/security
. Les réglages qu’il apporte ne sont en réalité pas déterminants pour la sécurité de notre serveur. Voyons néanmoins les paramètres qu’il contient :
ServerTokens
: Envoi des informations relative à l’OS et la version d’Apache dans l’en-tête serveur,ServerSignature
: Donne des informations en bas des pages créées par le serveur (page d’erreur, 404 etc),TraceEnable
: La méthode TRACE est réservée pour le débogage.
On va donc placer ServerTokens
à Prod, ServerSignature
à Off et TraceEnable
à Off. C’est tout pour ce fichier.
Empêcher de parcourir les fichiers
Au niveau de la configuration de votre site, il est prudent de préciser quelques paramètres concernant la racine de fichiers :
<VirtualHost *:80> ServerAdmin contact@monsite.fr DocumentRoot /var/www <Directory /> # empêche un fichier .htaccess de redéfinir ces paramètres AllowOverride None # empêche de parcourir le syteme de fichiers # il faudra donc bien placer cette directive à granted # dans le(s) répertoire(s) contenant votre/vos site(s) Order allow,deny Require all denied </Directory> <Directory /var/www/monsite/> … </directory> </VirtualHost>
Les modules complémentaires relatifs à la sécurité
Parmi les modules d’Apache, certains permettent d’améliorer la sécurité. Je n’expliquerai pas ici leur fonctionnement, parce que cela nécessiterait un article complet, mais je vais vous donner les liens qui vont bien.
Mod_security
est une sorte de firewall pour Apache [en]Mod_evasive
, qui protège des floods et attaque DDoS.
Pour ma part, je ne les utilise pas. Vous pouvez installer fail2ban pour améliorer la sécurité de votre serveur. Le pare-feu iptables, vous permet de bien vous prémunir contre les attaques DDoS.
Optimisation des performances
On parle beaucoup de Nginx dès lors que l’on mentionne les performances dans le web. Je dédis d’ailleurs moi même un article à ce sujet. Cependant, Apache reste un serveur extraordinaire et qui sait se montrer très performant.
On commence rapidement par vérifier quel est le module MPM utilisé, à savoir, prefork
, worker
ou event
.
Le plus vieux des trois est le MPM prefork, ce dernier utilise un processus par connexion. Par conséquent, il est plus vorace en RAM et moins adapté aux serveurs devants faire face à de très nombreuses connexions simultanées. En revanche, il est thread-safe. Il est également le seul à supporter le mod_php
. Les autres modes devront utiliser php-fpm.
Le plus récent des trois modes est le MPM event
. Il reprend le principe du MPM worker
– à savoir un modèle hybride multi-processus et multi-threads – et l’améliore pour mieux gérer la saturation des connexions dû à keep-alive. Sauf raison spécifique, on utilisera de préférence le dernier ; d’autant plus que le MPM prefork
ne supporte pas le HTTP/2.
# affiche les modules disponibles apache2ctl -M
Bien configuré, le MPM prefork
peut être très performant. Aussi, pour des raisons de compatibilité, je détaille également l’optimisation de ce dernier. Néanmoins, prefork
ne supporte pas le HTTP/2, on privilégiera donc le MPM event
autant que possible.
MPM prefork
& event
Les optimisations concernant le MPM prefork
se trouvent dans /etc/apache2/mods-enabled/mpm_prefork.conf
tandis que celles relatives à event
se trouvent dans /etc/apache2/mods-enabled/mpm_event.conf
.
MaxRequestWorkers
- Permet de déterminer le nombre maximal de requêtes pouvant être traitées simultanément. Au delà, toutes les requêtes iront dans une file d’attente.
Pour le
prefork
, cela correspond au nombre maximum de processus enfants qui pourront être lancés. Pensez que cette valeur est limitée parServerLimit
(cette directive se définit dans le fichier de configuration globale d’Apache). Il vous faudra donc l’augmenter si vous voulez fixer un nombre de workers plus grands.Dans le cas du MPM
event
,MaxRequestWorkers
fait référence au nombre global maximum de threads. Étant donné que chaque processus possède un nombre de threads donné – fixé par la directiveThreadsPerChild
que nous verrons plus bas – le nombre total de processus est définit parMaxRequestWorkers
/ThreadsPerChild
et ne peut dépasserServerLimit
.Étant donné que pour le MPM prefork, la RAM consitue la limite, voici comment définir le nombre : (RAM totale – RAM utilisée par les autres processus) / taille moyenne d’un processus Apache. Munissez-vous de
top
etps aux
pour cette mission ! Et si vous être vraiment des gros flemmards, j’ai la formule magique qu’il vous faut pour calculer le poids moyen d’un process Apache :# grep apache pour Ubuntu / grep httpd pour Debian ps aux | grep apache | awk '{print $6/1024;}' | awk '{avg += ($1 - avg) / NR;} END {print avg " MB";}' 38.1419 MB
MaxConnectionsPerChild
- Fixé par défaut à 0 (infini), cette directive permet de faire « mourir » un processus après qu’il ait servit un certain nombre de requêtes. Cela peut-être intéressant dans le cas de fuites mémoires. Par exemple, avec
mod_php
, si les processus ont tendances à avoir une emprunte mémoire qui grossit indéfiniment, on pourra les limiter à un certain nombre de requêtes et un nouveau prendra la relève. Comme la création de nouveaux processus consomme du CPU, il s’agit de trouver le juste équilibre. StartServers
- Cette directive, qu’on utilise en général conjointement avec
MinSpareServers
etMaxSpareServers
, spécifie le nombre de processus enfants qu’Apache doit lancer au démarrage.La création et l’arrêt de processus est dynamique. Cependant, dans le cas de sites à très fort trafic, il peut être judicieux de démarrer directement avec de nombreux processus pour pouvoir affronter la charge sans un temps de warm up. Aussi, on jouera avec les directives
(min|max)SpareServers
afin de :- toujours avoir un minimum de processus enfants prêts à réceptionner des requêtes,
- ne pas tuer des processus lors d’une baisse momentannée de trafic alors qu’une autre vague risque d’arriver, obligeant une couteuse opération de killing/re-creation.
Dans le MPM
event
, on ne raisonne pas en processus mais en threads. Ces deux directives dont donc remplacées parMinSpareThreads
etMaxSpareThreads
. ThreadsPerChild
- Il s’agit du nombre de threads lancé par chaque enfant. Chaque processus enfant créé ses threads au démarrage et n’en créé plus par la suite. Cette valeur ne peut dépasser
ThreadLimit
. En outre, si le nombre de threads est trop important, cela peut rendre le système instable. ThreadLimit
- Cette directive fixe la valeur maximum qu’il est possible d’allouer à
ThreadsPerChild
. Tandis queThreadsPerChild
peut être redéfinie via un reload, il faudra impérativement arrêter puis le re-démarrer le serveur si l’on veut modifierThreadLimit
.Par ailleurs, allouer une valeur inutilement importante et bien au delà de
ThreadsPerChild
aboutira à une consommation mémoire plus importante.
Configuration générale
Ces optimisations ne concernent pas un MPM en particulier, elles se trouvent dans /etc/apache2/apache2.conf
ou httpd.conf
sur Debian.
KeepAlive
&KeepAliveTimeout
- Cette option offerte par le HTTP/1.1 permet de servir plusieurs requêtes dans la même connexion TCP. Ainsi, on garde littéralement ouverte une connexion TCP afin de pouvoir servir de nouvelles requêtes en évitant de perdre du temps en refaisant un handshake TCP. C’est particulièrement utile pour servir tous les assets d’une page sans ouvrir 10000 connexions (typiquement JS, CSS, images).
C’est bien beau tout cela, mais notre petit
KeepAlive
bousille littéralement la capacité d’Apache de faire face à la charge. On l’a vu, Apache est limité parMaxRequestWorkers
, or si on conserve les connexions ouvertes, forcement, on peut moins en servir en même temps…KeepAlive
permet quand même d’améliorer l’expérience utilisateur sur les connexion à forte latence (mobile et connexion géographiquement éloignées Europe/USA par exemple). De même, cela permet d’améliorer les performances dans le cas de polling Ajax.Néanmoins, l’intérêt baisse quelque peu avec le HTTP/2 car il permet le multiplexage et le pipelining. Faites vos calculs, mais si vous avez un peu de charge, il est conseillé de clairement abaisser les 30 secondes par défaut.
FollowSymLinks
- Nous l’avons déjà mentionné plus haut, mais il vaut mieux préciser cette option. En son absence, ou dans le cas où il est explicitement indiqué de ne pas les suivre, Apache devra faire des appels système supplémentaires afin de vérifier si le pointeur est un lien symbolique ou non. De plus, dans la mesure où le résultats ne sont pas mis en cache par Apache, c’est le bingo à chaque requête.
AllowOverride
- Nous l’avons déjà mentionné aussi. Cette directive permet d’activer les fichiers
.htaccess
, grande spécificité de Apache. Ces petits fichiers de configuration permettent une grande souplesse car ils offrent la possibilité de configurer le comportement de sous-répertoires directement depuis ces derniers.Ainsi, il est possible de laisser les utilisateurs ou les développeurs gérer eux-mêmes le comportement des répertoires dont ils sont responsables (rewriting etc). Dans une équipe où développeurs et administrateurs ont des rôles bien différents, cela laisse plus de latitudes aux développeurs.
Néanmoins, c’est au sacrifice d’un peu de performances puisque Apache devra vérifier dans chaque répertoire le présence ou non d’un fichier de config, et le lire le cas échéant.
DirectoryIndex
- Cette directive permet de spécifier le fichier à servir par défaut lors de la requête d’un répertoire. Typiquement la racine d’un site par exemple :
buzut.fr
et non pasbuzut.fr/index.php
. Apache sert donc automatiquementindex.php
lorsqu’on requête ce répertoire.Il est possible – et on le voit souvent – de ne spécifier que le nom de base sans l’extension
index
. Cela permet à Apache de servirindex.php
,index.html
,index.pl
etc. On gagnera en performance à spécifier les types, et il est possible d’établir une liste. Dans ce cas, les fichiers à gauche seront servis en priorité sur ceux à droite dans la liste.DirectoryIndex index.php index.html index.pl
Sachant tout cela, après avoir laissé tourner le serveur quelques temps, il peut être judicieux de lancer un script qui analysera la config et différents paramètres afin de vous fournir quelques voies d’optimisations. Le script en question s’appelle apache2buddy
et pour le lancer, rien de plus simple :
curl -L http://apache2buddy.pl/ | perl
Compression
Par défaut, Apache compresse certains types de fichiers avant de les envoyer. Les fichiers sont ainsi plus légers et le temps de transfert est réduit. Le navigateur les décompresse à la volée et voilà.
Ceci est géré par le module deflate
qui compresse le tout en gzip (ou deflate, selon la demande du navigateur). Dans 99% du temps vous n’avez rien à faire. Cependant, il y a un type de media non compressé par défaut et qui peut pourtant avantageusement en tirer profit, il s’agit des images svg.
Pour permettre à Apache de les compresser à la volée, rendez-vous dans le fichier de configuration dudit module : /etc/apache2/mods-available/deflate.conf
<IfModule mod_deflate.c> <IfModule mod_filter.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css AddOutputFilterByType DEFLATE application/x-javascript application/javascript applic$ AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/xml # j'ai ici ajouté le type MIME du svg AddOutputFilterByType DEFLATE image/svg+xml </IfModule> </IfModule>
On recharge ensuite la configuration avec un savant coup de service apache2 reload
et en voiture Simone !
Nous l’avons dit, Apache compresse à la volée, ce qui signifie qu’à chaque requête, les fichiers sont compressés avant envoi. On comprends dès lors qu’il faut trouver le juste milieu entre taille du fichier et temps de compression. En effet, si le fichier est trop long à compresser, peut-être est-ce plus rapide de ne pas le compresser, ou de moins le compresser.
La compression à la volée fait tout à fait sens pour les contenus générés dynamiquement. Cependant, dans le cas de fichiers statiques (html brut, JavaScript, CSS…), il est possible de compresser en amont et d’indiquer à Apache de servir ces fichiers déjà compressés si le navigateur les supporte. Cela permet en outre d’utiliser les taux de compression les plus élevés.
Vous avez peut-être entendu parler de Brotli [en]. Il s’agit d’un format de compression mis au point en 2015 par Google qui offre des taux de compressions bien supérieurs à Gzip. Étant donné que la quasi totalité navigateurs le prennent en charge, nous n’allons pas nous priver de pré-compresser aussi en brotli.
En revanche, deflate étant beaucoup moins demandé, nous n’allons pas nous en préoccuper. En dernier recours, si rien d’autre n’est supporté, Apache utilisera la compression à la volée.
La compression étant en amont, ce n’est pas Apache qui la gère. On peut donc l’effectuer en local, lors du processus de build par exemple ou lors du deploy. Une fois que tous ces fichiers sont sur le serveur, on va spécifier à Apache via quelques règles de réécriture de les servir avec les bons en-têtes.
# Déclare le type MIME brotli # pour les fichiers que l'on va servir en brotli # vous pouvez ajouter le xml, json et tout fichier à base de texte si pertinent <Files *.js.br> AddType "text/javascript" .br AddEncoding br .br </Files> <Files *.css.br> AddType "text/css" .br AddEncoding br .br </Files> <Files *.svg.br> AddType "image/svg+xml" .br AddEncoding br .br </Files> <Files *.html.br> AddType "text/html" .br AddEncoding br .br </Files> # Idem pour le gzip <Files *.js.gz> AddType "text/javascript" .gz AddEncoding gzip .gz </Files> <Files *.css.gz> AddType "text/css" .gz AddEncoding gzip .gz </Files> <Files *.svg.gz> AddType "image/svg+xml" .gz AddEncoding gzip .gz </Files> <Files *.html.gz> AddType "text/html" .gz AddEncoding gzip .gz </Files> # on démarre le moteur de réécriture RewriteEngine on RewriteBase / # Transmet les fichiers pré-compressés en brotli RewriteCond %{HTTP:Accept-Encoding} br RewriteCond %{REQUEST_FILENAME}.br -f RewriteRule ^(.*)$ $1.br [L] # Transmet les fichiers pré-compressés en gzip RewriteCond %{HTTP:Accept-Encoding} gzip RewriteCond %{REQUEST_FILENAME}.gz -f RewriteRule ^(.*)$ $1.gz [L]
HTTP/2 push
Nous avons vu dans la section sur le HTTP/2 comment activer ce dernier sur le serveur. Cette version du protocole permet de faire du push, c’est à dire d’envoyer au navigateur des éléments qu’il n’a pas encore demandé. Cela permet par exemple de lui envoyer le CSS et le JS avant même qu’il ne les demande, on gagne donc le temps du parsing. On peut mettre en place cela très facilement avec un en-tête.
Néanmoins, comme on envoie des éléments sans l’avis du navigateur, cela court-circuite le cache de ce dernier. Il ne faudrait donc pas envoyer des éléments qu’il possède déjà, au risque de gaspiller des ressources réseau. On va alors lui transmettre les éléments seulement s’il n’y a aucun cookie d’envoyé. Cela signifie qu’il s’agit probablement de la première visite sur le site.
Cette technique implique évidemment que votre site créé des cookies. Même sans le faire explicitement, de nombreux scripts embarqués dans vos pages créent des cookies (Google Analytics par exemple). Si ce n’est pas le cas, vous pouvez demander à Apache d’en créer un.
# Pour tous les fichiers .html ou html gzippé ou brotlisé # on balance automatiquement le css et le js s'il n'y a pas de cookie <Files *.html.br> Header add Link "</styles/styles.min.css>;rel=preload" "expr=-z %{req:Cookie}" Header add Link "</js/scripts.min.js>;rel=preload" "expr=-z %{req:Cookie}" </Files> <Files *.html.gz> Header add Link "</styles/styles.min.css>;rel=preload" "expr=-z %{req:Cookie}" Header add Link "</js/scripts.min.js>;rel=preload" "expr=-z %{req:Cookie}" </Files> <Files *.html> Header add Link "</styles/styles.min.css>;rel=preload" "expr=-z %{req:Cookie}" Header add Link "</js/scripts.min.js>;rel=preload" "expr=-z %{req:Cookie}" </Files>
That’s it pour le push !
On en a fini avec la configuration d’apache. Je vous laisse quand même avec la doc officielle (qui est bien conçue et en français), au cas où vous voudriez creuser certains points.