Web 04 Http Mise en Oeuvre

HTTP Mise en oeuvre

1. Apache HTTPd Server

1.1. Introduction à Apache HTTP Server

Le logiciel libre Apache HTTP Server (Apache) est un serveur HTTP créé et maintenu au sein de la fondation Apache. C’est le serveur HTTP le plus populaire du World Wide Web. Il est distribué selon les termes de la licence Apache.

Historique

Apache est apparu en avril 1995. Au début, il s’agissait d’une collection de correctifs et d’additions au serveur NCSA HTTPd 1.3, qui était dans ledomaine public et le serveur HTTP alors le plus répandu. De cette origine, de nombreuses personnes affirment que le nom Apache vient de a patchy server, soit « un serveur rafistolé ». Par la suite, Apache a été complètement réécrit, de sorte que, dans la version 2, il ne reste pas de trace de NCSA HTTPd.

Au début, Apache était la seule alternative sérieuse et libre au serveur HTTP de Netscape (iPlanet, maintenant Sun ONE). Depuis avril 1996, selon l’étude permanente de Netcraft, Apache est devenu le serveur HTTP le plus répandu sur Internet.

Part de marché d’Apache :

  • En mai 1999, il faisait tourner 57 % des serveurs Web, début 2004, il était à environ 69 % de parts de marché, et il ne détient plus que 50,61 % du marché à la fin du mois de janvier 2008 ;
  • En février 2008, Apache représente 50,93 % des parts de marché ;
  • En novembre 2008, 72,45 % de parts de marché pour Apache ;
  • En novembre 2011, 65,00 % de parts de marché pour Apache ;
  • En mai 2014, 38,00 % de parts de marché pour Apache et 33,00 % pour Microsoft IIS.
  • En janvier 2015 sur l’analyse de 876,812,666 sites, correspondant à 5,061,365 ordinateurs frontaux, les parts de marché sont de 39.74 % pour Apache, et 27,52 % pour IIS. Sur les part de marché des serveurs actifs (en excluant les sites parkings) par contre, 50.72 % pour Apache, 14.82 % pour Nginx et IIS passe en 3e position avec seulement 10.55 %, perdant 1.17 % de parts par rapport au mois précédent.
  • En février 2017, Apache est utilisé par 59,76% du total des domaines français enregistrés.

La version 2 d’Apache possède plusieurs avancées majeures par rapport à la version 1, entre autres le support de plusieurs plates-formes (Windows, Linux et UNIX, entre autres), le support de processus légers UNIX, une nouvelle API et le support IPv6.

La fondation Apache (Apache Software Foundation ou ASF) a été créée en 1999 à partir du groupe Apache (Apache Group) à l’origine du serveur en 1995. Depuis, de nombreux autres logiciels utiles au World Wide Web sont développés à côté du serveur HTTP.

Voir aussi Comparison of web server software

Disponibilité

Apache fonctionne principalement sur les systèmes d’exploitation UNIX (Linux, Mac OS X, Solaris, BSD et UNIX) et Windows. La version Windows n’est considérée comme stable que depuis la version 1.2 d’Apache. Apache est utilisé par de nombreux produits, dont WebSphere d’IBM, ainsi que par Oracle Corporation.

Fonctionnalités

Apache est conçu pour prendre en charge de nombreux modules lui donnant des fonctionnalités supplémentaires : interprétation du langage Perl, PHP, Python et Ruby, serveur proxy, Common Gateway Interface, Server Side Includes, réécriture d’URL, négociation de contenu, protocoles de communication additionnels, etc. Néanmoins, il est à noter que l’existence de nombreux modules Apache complexifie la configuration du serveur web. En effet, les bonnes pratiques recommandent de ne charger que les modules utiles : de nombreuses failles de sécurité affectant uniquement les modules d’Apache sont régulièrement découvertes.

Les possibilités de configuration d’Apache sont une fonctionnalité phare. Le principe repose sur une hiérarchie de fichiers de configuration, qui peuvent être gérés indépendamment. Cette caractéristique est notamment utile aux hébergeurs qui peuvent ainsi servir les sites de plusieurs clients à l’aide d’un seul serveur HTTP. Pour les clients, cette fonctionnalité est rendue visible par le fichier .htaccess.

Parmi les outils aidant la maintenance d’Apache, les fichiers de log peuvent s’analyser à l’aide de nombreux scripts et logiciels libres tels que AWStats, Webalizer ou W3Perl. Plusieurs interfaces graphiques facilitent la configuration du serveur.

Sources et crédits

1.2. Arborescence et architecture logicielle

  • Prise en charge des processus
  • Modules et configuration de modules
  • Fichiers de configuration : /etc/httpd/conf/ (CentOS)
  • Emplacement des fichiers à servir : /var/www/html/

Le logiciel Apache HTTP peut connaître différents emplacements selon la distribution Linux utilisée. On retrouve ces modèles comme étape de configuration d’une compilation par les sources du logiciel. On trouvera dans les sources du logiciel un fichier config.layout qui illustre différents modèles d’emplacement des résultats d’une compilation :

$ head -n35 config.layout
##
##  config.layout -- Pre-defined Installation Path Layouts
##
##  Hints:
##  - layouts can be loaded with configure's --enable-layout=ID option
##  - when no --enable-layout option is given, the default layout is `Apache'
##  - a trailing plus character (`+') on paths is replaced with a
##    `/<target>' suffix where <target> is currently hardcoded to 'apache2'.
##    (This may become a configurable parameter at some point.)
##

#   Classical Apache path layout.
<Layout Apache>
    prefix:        /usr/local/apache2
    exec_prefix:   ${prefix}
    bindir:        ${exec_prefix}/bin
    sbindir:       ${exec_prefix}/bin
    libdir:        ${exec_prefix}/lib
    libexecdir:    ${exec_prefix}/modules
    mandir:        ${prefix}/man
    sysconfdir:    ${prefix}/conf
    datadir:       ${prefix}
    installbuilddir: ${datadir}/build
    errordir:      ${datadir}/error
    iconsdir:      ${datadir}/icons
    htdocsdir:     ${datadir}/htdocs
    manualdir:     ${datadir}/manual
    cgidir:        ${datadir}/cgi-bin
    includedir:    ${prefix}/include
    localstatedir: ${prefix}
    runtimedir:    ${localstatedir}/logs
    logfiledir:    ${localstatedir}/logs
    proxycachedir: ${localstatedir}/proxy
</Layout>

Source : Installation par les sources d’Apache HTTP Server

1.3. Configuration globale

Sous CentOS 7, les directives de configuration se retrouvent dans le fichier /etc/httpd/conf/httpd.conf.

Directive ServerRoot

La directive ServerRoot permet de définir le répertoire dans lequel le serveur est installé. En particulier, il contiendra les sous-répertoires conf/ et logs/. Les chemins relatifs indiqués dans les autres directives (comme Include ou LoadModule) seront définis par rapport à ce répertoire.

Directive ServerSignature

  • Syntaxe: ServerSignature On|Off|EMail
  • Défaut: ServerSignature Off

La directive ServerSignature permet de définir une ligne de pied de page fixe pour les documents générés par le serveur (messages d’erreur, listings de répertoires ftp de mod_proxy, sorties de mod_info, etc…). Dans le cas d’une chaîne de mandataires, l’utilisateur n’a souvent aucun moyen de déterminer lequel des mandataires chaînés a généré un message d’erreur, et c’est une des raisons pour lesquelles on peut être amené à ajouter un tel pied de page.

La valeur par défaut Off supprime la ligne de pied de page (et est ainsi compatible avec le comportement des versions 1.2 et antérieures d’Apache). la valeur On ajoute simplement une ligne contenant le numéro de version du serveur ainsi que le nom du serveur virtuel issu de la directive ServerName, alors que la valeur EMail ajoute en plus une référence “mailto:” à l’administrateur du document référencé issu la directive ServerAdmin.

Directive ServerTokens

  • Syntaxe: ServerTokens Major|Minor|Min[imal]|Prod[uctOnly]|OS|Full
  • Défaut: ServerTokens Full

Cette directive permet de contrôler le contenu de l’en-tête Server inclus dans la réponse envoyée au client : cet en-tête peut contenir le type de système d’exploitation du serveur, ainsi que des informations à propos des modules compilés avec le serveur.

  • ServerTokens Full (ou non spécifié) : Le serveur envoie par exemple : Server: Apache/2.4.2 (Unix) PHP/4.2.2 MyMod/1.2
  • ServerTokens Prod[uctOnly] : Le serveur renvoie (par exemple): Server: Apache
  • ServerTokens Major : Le serveur renvoie (par exemple): Server: Apache/2
  • ServerTokens Minor : Le serveur renvoie (par exemple): Server: Apache/2.4
  • ServerTokens Min[imal] : Le serveur renvoie (par exemple): Server: Apache/2.4.2
  • ServerTokens OS : Le serveur renvoie (par exemple): Server: Apache/2.4.2 (Unix)

Cette définition s’applique à l’ensemble du serveur et ne peut être activée ou désactivée pour tel ou tel serveur virtuel.

Directive LoadModule

  • Syntaxe: LoadModule module nom-fichier

La directive LoadModule permet de lier le fichier objet ou la bibliothèque nom-fichier avec le serveur, et d’ajouter la structure de module nommée module à la liste des modules actifs. module est le nom de la variable externe de type module dans le fichier, et est référencé comme Identificateur de module dans la documentation des modules. Exemple :

LoadModule status_module modules/mod_status.so

charge le module spécifié depuis le sous-répertoire des modules situé à la racine du serveur.

1.4. Serveur virtuel basé sur le nom

Comment le serveur sélectionne-t-il le serveur virtuel basé sur le nom approprié

Il est important de savoir que la première étape de la résolution de serveur virtuel basée sur le nom est une résolution basée sur IP. La résolution de serveur virtuel basée sur le nom ne fait que choisir le serveur virtuel basé sur le nom le plus approprié, en se limitant aux candidats qui conviennent le mieux du point de vue IP. La résolution basée sur IP est sans objet si l’on utilise un caractère générique (*) pour l’adresse IP dans toutes les directives VirtualHost.

A l’arrivée d’une requête, le serveur va rechercher l’argument de section <VirtualHost> présentant la meilleure (la plus exacte) correspondance avec la paire adresse IP/port utilisée dans la requête. Si plusieurs serveurs virtuels possèdent cette même paire adresse IP/port, Apache va ensuite comparer les valeurs des directives ServerName et ServerAlias avec le nom de serveur présent dans la requête.

Si vous ne définissez pas de directive ServerName pour un serveur virtuel à base de nom, le serveur utilisera par défaut le nom de domaine entièrement qualifié (FQDN) déduit du nom d’hôte système. Cette configuration sans nom de serveur explicite peut conduire à des erreurs de choix du serveur virtuel à utiliser et est déconseillée.

Le serveur virtuel à base de nom par défaut pour une paire adresse IP/port Si aucune directive ServerName ou ServerAlias ne correspond dans la liste de serveurs virtuels présentant la meilleure correspondance du point de vue adresse IP/port, c’est le premier serveur virtuel de cette liste qui sera utilisé.

Utilisation de serveurs virtuels par nom

  • Modules Apparentés : Core
  • Directives Apparentées
    • DocumentRoot
    • ServerAlias
    • ServerName
    • <VirtualHost>

La première étape consiste à créer une section <VirtualHost> pour chacun des serveurs à définir. Dans chaque section <VirtualHost>, vous devez définir au minimum une directive ServerName pour désigner le serveur concerné et une directive DocumentRoot pour préciser l’emplacement sur le système de fichiers du contenu de ce serveur.

Le serveur principal disparaît

Par exemple, supposez que vous hébergez le domaine www.example.com et que vous souhaitez ajouter le serveur virtuel other.example.com qui pointe sur la même adresse IP. Il vous suffit d’ajouter la configuration suivante à httpd.conf :

<VirtualHost *:80>
    # Le premier serveur virtuel de la liste est aussi le
    # serveur par défaut pour *:80
    ServerName www.example.com
    ServerAlias example.com
    DocumentRoot "/www/domain"
</VirtualHost>

<VirtualHost *:80>
    ServerName other.example.com
    DocumentRoot "/www/otherdomain"
</VirtualHost>

Autrement, vous pouvez spécifiez une adresse IP explicite à la place de * dans la directive <VirtualHost>. Par exemple, cette méthode est utile si vous souhaitez faire tourner quelques serveurs virtuels par nom sur une même adresse IP, et d’autres, soit par IP, soit basés sur un autre jeu de serveurs virtuels par nom sur une autre adresse IP.

Plusieurs serveurs sont accessibles par plus d’un nom. Il suffit de placer la directive ServerAlias dans une section <VirtualHost>. Par exemple, dans la première section <VirtualHost> ci-dessus, la directive ServerAlias indique aux utilisateurs les autres noms permis pour accéder au même site Web :

ServerAlias example.com *.example.com

ainsi, toutes les requêtes portant sur un domaine example.com seront servies par le serveur virtuel www.example.com. Les caractères joker * et ? peuvent être utilisés pour les correspondances. Bien entendu, vous ne pouvez pas inventer des noms et les placer dans une directive ServerName ou ServerAlias. Tout d’abord, votre serveur DNS doit être correctement configuré pour lier ces noms à une adresse IP associée avec votre serveur.

La recherche du serveur virtuel à base de nom qui correspond au plus près à la requête s’effectue parmi les <virtualhost> selon leur ordre d’apparition dans le fichier de configuration. Le premier serveur virtuel dont le ServerName ou le ServerAlias correspond est utilisé, sans priorité particulière en cas de présence de caractères génériques (que ce soit pour le ServerName ou le ServerAlias).

La liste complète des noms dans la section VirtualHost sont traités comme une directive ServerAlias sans caractères génériques.

Finalement, vous pouvez affiner la configuration des serveurs virtuels en plaçant d’autres directives à l’intérieur des sections <VirtualHost>. La plupart des directives peut être placée dans ces sections en y changeant seulement la configuration du serveur virtuel associé. Pour déterminer si une directive particulière est permise, consultez le contexte de la directive. Le jeu de directives configurées dans le contexte du serveur principal (en dehors de toutes sections <VirtualHost>) sera utilisé seulement s’il n’y a pas de configuration contraire par un serveur virtuel.

Directive ServerName

Terminologie :

La directive ServerName permet de définir les protocole, nom d’hôte et port d’une requête que le serveur utilise pour s’authentifier lui-même.

La directive ServerName permet (éventuellement en conjonction avec la directive ServerAlias) d’identifier de manière unique un serveur virtuel, lorsqu’elle est utilisée dans un contexte de serveurs virtuels à base de noms.

Cette directive est aussi utilisée lors de la création d’URLs de redirection relatives quand la directive UseCanonicalName est définie à une valeur autre que la valeur par défaut.

Par exemple, si le nom de la machine hébergeant le serveur web est simple.example.com, la machine possède l’alias DNS www.example.com, et si vous voulez que le serveur web s’identifie avec cet alias, vous devez utilisez la définition suivante :

ServerName www.example.com

Si vous définissez des serveurs virtuels à base de nom, une directive ServerName située à l’intérieur d’une section <VirtualHost> spécifiera quel nom d’hôte doit apparaître dans l’en-tête de requête Host: pour pouvoir atteindre ce serveur virtuel.

Directive ServerAlias

La directive ServerAlias permet de définir les noms alternatifs d’un serveur utilisables pour atteindre des serveurs virtuels à base de nom. La directive ServerAlias peut contenir des caractères génériques, si nécessaire.

<VirtualHost *:80>
  ServerName server.example.com
  ServerAlias server server2.example.com server2
  ServerAlias *.example.com
  UseCanonicalName Off
  # ...
</VirtualHost>

La recherche du serveur virtuel à base de nom correspondant au plus près à la requête s’effectue selon l’ordre d’apparition des directives <virtualhost> dans le fichier de configuration. Le premier serveur virtuel dont le ServerName ou le ServerAlias correspond est choisi, sans priorité particulière si le nom contient des caractères génériques (que ce soit pour ServerName ou ServerAlias).

Tous les noms spécifiés au sein d’une section VirtualHost sont traités comme un ServerAlias (sans caractères génériques).

Directive ServerAdmin

La directive ServerAdmin permet de définir l’adresse de contact que le serveur va inclure dans tout message d’erreur qu’il envoie au client. Si le programme httpd ne reconnait pas l’argument fourni comme une URL, il suppose que c’est une adresse électronique, et lui ajoute le préfixe mailto: dans les cibles des hyperliens. Il est cependant recommandé d’utiliser exclusivement une adresse électronique, car de nombreux scripts CGI considèrent ceci comme implicite. Si vous utilisez une URL, elle doit pointer vers un autre serveur que vous contrôlez. Dans le cas contraire, les utilisateurs seraient dans l’impossibilité de vous contacter en cas de problème.

Il peut s’avérer utile de définir une adresse dédiée à l’administration du serveur, par exemple :

ServerAdmin www-admin@foo.example.com

car les utilisateurs ne mentionnent pas systématiquement le serveur dont ils parlent !

Directive DocumentRoot

Cette directive permet de définir le répertoire à partir duquel httpd va servir les fichiers. S’il ne correspond pas à un Alias, le chemin de l’URL sera ajouté par le serveur à la racine des documents afin de construire le chemin du document recherché. Exemple :

DocumentRoot "/usr/web"

un accès à http://my.example.com/index.html se réfère alors à /usr/web/index.html. Si chemin répertoire n’est pas un chemin absolu, il est considéré comme relatif au chemin défini par la directive ServerRoot.

Le répertoire défini par la directive DocumentRoot ne doit pas comporter de slash final.

Directive Error

Si une erreur peut être détectée dans la configuration, souvent un module manquant, cette directive peut être utilisée pour générer un message d’erreur personnalisé, et interrompre la lecture de la configuration.

Par exemple,

# vérification du chargement de mod_include
<IfModule !include_module>
  Error "mod_include is required by mod_foo.  Load it with LoadModule."
</IfModule>

# vérification de la définition de SSL ou (exclusif) NOSSL
<IfDefine SSL>
<IfDefine NOSSL>
  Error "Both SSL and NOSSL are defined.  Define only one of them."
</IfDefine>
</IfDefine>
<IfDefine !SSL>
<IfDefine !NOSSL>
  Error "Either SSL or NOSSL must be defined."
</IfDefine>
</IfDefine>

Directive ErrorLog

La directive ErrorLog permet de définir le nom du fichier dans lequel le serveur va journaliser toutes les erreurs qu’il rencontre. Si le chemin fichier n’est pas absolu, il est considéré comme relatif au chemin défini par la directive ServerRoot.

ErrorLog "/var/log/httpd/error_log"

Si le chemin fichier commence par une barre verticale “(|)”, il est considéré comme une commande à lancer pour traiter la journalisation de l’erreur.

ErrorLog "|/usr/local/bin/httpd_errors"

Voir les notes à propos des journaux redirigés pour plus d’informations.

L’utilisation de syslog à la place d’un nom de fichier active la journalisation via syslogd(8) si le système le supporte. Le dispositif syslog par défaut est local7, mais vous pouvez le modifier à l’aide de la syntaxe syslog:facility, où “facility” peut être remplacé par un des noms habituellement documentés dans la page de man syslog(1). Le dispositif syslog local7 est global, et si il est modifié dans un serveur virtuel, le dispositif final spécifié affecte l’ensemble du serveur

ErrorLog syslog:user

Des modules supplémentaires peuvent fournir leurs propres fournisseurs ErrorLog. La syntaxe est similaire à celle de l’exemple syslog ci-dessus.

Directive ErrorLogFormat

La directive ErrorLogFormat permet de spécifier quelles informations supplémentaires vont être enregistrées dans le journal des erreurs en plus du message habituel.

| Chaîne de format |Description | | – | – | | %a | Adresse IP et port clients | %E | Etat d’erreur APR/OS et chaîne | %F | Nom du fichier source et numéro de ligne de l’appel du journal | %{name}i | En-tête de requête name | %k | Nombre de requêtes persistantes pour cette connexion | %l | Sévérité du message | %L | Identifiant journal de la requête | %m | Nom du module qui effectue la journalisation du message | %M | Le message effectif | %P | Identifiant du processus courant | %T | Identifiant du thread courant | %t | L’heure courante | %{u}t | L’heure courante avec les microsecondes | %{cu}t | L’heure courante au format compact ISO 8601, avec les microsecondes | %v | Le nom de serveur canonique ServerName du serveur courant. | %V | Le nom de serveur du serveur qui sert la requête en accord avec la définition de la directive UseCanonicalName. | \ (anti-slash espace) | Espace non délimiteur | % (pourcentage espace) | Délimiteur de champ (aucune sortie)

Voir https://httpd.apache.org/docs/2.4/fr/mod/core.html#errorlogformat pour la signification des codes.

  • Exemple simple

    ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M"
    
  • Exemple (format par défaut pour les MPMs threadés)

    ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
    

    Cet exemple renverrait un message d’erreur du style :

    [Thu May 12 08:28:57.652118 2011] [core:error] [pid 8777:tid 4326490112] [client ::1:58619] File does not exist: /usr/local/apache2/htdocs/favicon.ico
    

Notez que certains champs sont totalement supprimés s’ils n’ont pas été définis.

  • Exemple (similaire au format 2.2.x)

    ErrorLogFormat "[%t] [%l] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
    
  • Exemple avancé avec identifiants journal de requête/connexion

    ErrorLogFormat "[%{uc}t] [%-m:%-l] [R:%L] [C:%{C}L] %7F: %E: %M"
    ErrorLogFormat request "[%{uc}t] [R:%L] Request %k on C:%{c}L pid:%P tid:%T"
    ErrorLogFormat request "[%{uc}t] [R:%L] UA:'%+{User-Agent}i'"
    ErrorLogFormat request "[%{uc}t] [R:%L] Referer:'%+{Referer}i'"
    ErrorLogFormat connection "[%{uc}t] [C:%{c}L] local\ %a remote\ %A"
    

Directive LogLevel

La directive LogLevel permet d’ajuster la verbosité des messages enregistrés dans les journaux d’erreur (voir la directive ErrorLog). Les niveaux disponibles sont présentés ci-après, par ordre de criticité décroissante :

| Niveau | Description | Exemple | |–|–|–| | emerg | Urgences - le système est inutilisable. | “Child cannot open lock file. Exiting” | alert | Des mesures doivent être prises immédiatement. | “getpwuid: couldn’t determine user name from uid” | crit | Conditions critiques. | “socket: Failed to get a socket, exiting child” | error | Erreurs. | “Premature end of script headers” | warn | Avertissements. | “child process 1234 did not exit, sending another SIGHUP” | notice | Evènement important mais normal. | “httpd: caught SIGBUS, attempting to dump core in …” | info | Informations. | “Server seems busy, (you may need to increase StartServers, or Min/MaxSpareServers)…” | debug | Messages de débogage. | “Opening config file …”

Lorsqu’un niveau particulier est spécifié, les messages de tous les autres niveaux de criticité supérieure seront aussi enregistrés. Par exemple, si LogLevel info est spécifié, les messages de niveaux notice et warn seront aussi émis.

Il est recommandé d’utiliser un niveau crit ou inférieur.

Par exemple :

LogLevel notice

Spécifier un niveau sans nom de module va attribuer ce niveau à tous les modules. Spécifier un niveau avec nom de module va attribuer ce niveau à ce module seulement.

Il est possible de spécifier un module par le nom de son fichier source ou par son identificateur, avec ou sans le suffixe _module. Les trois spécifications suivantes sont donc équivalentes :

LogLevel info ssl:warn
LogLevel info mod_ssl.c:warn
LogLevel info ssl_module:warn

Il est aussi possible d’attribuer un niveau de journalisation par répertoire :

LogLevel info
<Directory "/usr/local/apache/htdocs/app">
  LogLevel debug
</Directory>

Exemples de configuration VirtualHost

Source : https://httpd.apache.org/docs/2.4/fr/vhosts/examples.html Source : https://httpd.apache.org/docs/2.4/fr/vhosts/mass.html

2. Pratique de Apache HTTPd Server

2.1. Installation de HTTPd Server sur Centos

Après une installation RHEL7 / Centos 7 :

fqdn="server.example.com"
hostnamectl set-hostname ${fqdn}
yum install -y curl firewalld
yum groupinstall -y "Web Server"
echo "127.0.0.1 ${fqdn}" >> /etc/hosts
echo "ServerName ${fqdn}" >> /etc/httpd/conf/httpd.conf
systemctl enable httpd
systemctl start httpd
systemctl enable firewalld
systemctl start firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --reload

Examen des emplacements du logiciel

La commande rpm -ql donne la liste des fichiers du paquetage httpd :

rpm -ql httpd

Principalement, on retouve les emplacements (pour Centos/RHEL) :

  • /etc/httpd/ avec notamment le fichier principal de configuration httpd.conf : fichiers de configuration.
  • /etc/httpd/conf.d/ : fichiers de configuration supplémentaires (vhosts).
  • /usr/lib64/httpd/ modules et librairies.
  • /usr/sbin/ binaires : httpd, apachectl, etc.
  • /usr/share/doc/httpd-*/ : documentation.
  • /var/log/httpd/ : emplacement des logs par défaut.
  • /var/www/html/ : emplacement par défaut des pages à servir.

2.2. Configurer un hôte virtuel

Fichier de configuration

cat /usr/share/doc/httpd*/httpd-vhosts.conf
# Virtual Hosts
#
# Required modules: mod_log_config

# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at
# <URL:http://httpd.apache.org/docs/2.4/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.

#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
#
<VirtualHost *:@@Port@@>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "@@ServerRoot@@/docs/dummy-host.example.com"
ServerName dummy-host.example.com
ServerAlias www.dummy-host.example.com
ErrorLog "/var/log/httpd/dummy-host.example.com-error_log"
CustomLog "/var/log/httpd/dummy-host.example.com-access_log" common
</VirtualHost>

<VirtualHost *:@@Port@@>
ServerAdmin webmaster@dummy-host2.example.com
DocumentRoot "@@ServerRoot@@/docs/dummy-host2.example.com"
ServerName dummy-host2.example.com
ErrorLog "/var/log/httpd/dummy-host2.example.com-error_log"
CustomLog "/var/log/httpd/dummy-host2.example.com-access_log" common
</VirtualHost>

Mise en place d’un hôte virtuel HTTP

Mise en place pour l’hôte virtuel host1.example.com.

Le principe consiste à adapter la copie de ce fichier d’exemple dans /etc/httpd/conf.d/ sous le nom host1.example.com.

Pour rendre nos opérations plus souples, notamment si vous voulez choisir un autre nom de domaine, on propose de placer le nom de domaine en variable :

httpdomain="host1.example.com"

Résolution de nom locale

echo "127.0.0.1 ${httpdomain}" >> /etc/hosts

Création du dossier et des pages Web

mkdir -p /var/www/html/${httpdomain}
echo "${httpdomain} test page" > /var/www/html/${httpdomain}/index.html

Restauration de la policy Selinux sur le dossier créé

restorecon -Rv /var/www/html/${httpdomain}

Création du dossier et des fichiers pour les logs

mkdir -p /var/log/httpd
touch /var/log/httpd/${httpdomain}-error_log
touch /var/log/httpd/${httpdomain}-access_log

Configuration du vhost HTTP

cat << EOF > /etc/httpd/conf.d/${httpdomain}.conf
<VirtualHost *:80>
ServerAdmin webmaster@${httpdomain}
DocumentRoot /var/www/html/${httpdomain}
ServerName ${httpdomain}
ErrorLog /var/log/httpd/${httpdomain}-error_log
CustomLog /var/log/httpd/${httpdomain}-access_log common
</VirtualHost>
EOF

Redémarrage du service

apachectl restart

Diganostic

curl ${httpdomain}
httpd -D DUMP_VHOSTS
VirtualHost configuration:
*:80                   host1.example.com (/etc/httpd/conf.d/host1.example.com.conf:1)
*:443                  192.168.122.39 (/etc/httpd/conf.d/ssl.conf:56)

Script create_vhost_httpd.sh

https://gist.github.com/goffinet/33205a18152fe3a87a5cf2d46e65dc3f

bash -x create_vhost_httpd.sh host1.example.com
#!/bin/bash
#create_vhost_httpd.sh in Centos7
#Variables
host=$1
port="80"
location="/var/www/html"
error_log="/var/log/httpd/${host}-error_log"
access_log="/var/log/httpd/${host}-access_log common"
#Résolution de nom locale
echo "127.0.0.1 ${host}" >> /etc/hosts
#Création du dossier et des pages Web
mkdir -p ${location}/${host}
echo "${host} test page" > ${location}/${host}/index.html
#Restauration de la policy Selinux sur le dossier créé
restorecon -Rv ${location}/${host}
#Création du dossier et des fichiers pour les logs
mkdir -p /var/log/httpd
touch /var/log/httpd/${host}-error_log
touch /var/log/httpd/${host}-access_log
#Configuration du vhost
cat << EOF > /etc/httpd/conf.d/${host}.conf
<VirtualHost *:${port}>
ServerAdmin webmaster@${host}
DocumentRoot ${location}/${host}
ServerName ${host}
ErrorLog ${error_log}
CustomLog ${access_log}
</VirtualHost>
EOF
#Activation et lancement du service
systemctl enable httpd
systemctl start httpd
systemctl restart httpd
#Diganostic
curl ${host}
httpd -D DUMP_VHOSTS

2.3. Configuration d’un vhost en HTTPS

Trois possibilités pour faire fonctionner HTTPS avec des certificats x509 :

  1. Générer un CSR et le soumettre à un CA (Autorité de Certification) : le plus fonctionnel et sûr, mais moins souple et le plus coûteux sur le plan financier et administratif.
  2. Générer un certificat auto-signé : coût nul, mais pose un problème de sécurité qui peut devenir indépassable pour certaines applications. Utile pour des environnement de développement ou pour assurer la confidentialité simplement.
  3. Let’s Encrypt : coût nul, facile à déployer, sûr.

Aussi, il s’agit de s’intéresser à la force des certificats et aux protocoles autorisés.

Différentes méthodes sont disponibles, certaines valides dans tous les cas ou uniquement sous cette distribution RHEL7/Centos7.

Toujours pour une question de souplesse, on propose de placer le nom de domaine en variable :

httpdomain="host1.example.com"

Force des certificats

Cipherli.st Strong Ciphers for Apache, nginx and Lighttpd

“Red Hat Keypair Generation ©” tout-en-un

L’utilitaire crypto-utils crée les configurations HTTPS pour Apache.

yum install -y crypto-utils

Par exemple, on s’informera sur la commande genkey :

# genkey --help
Unknown option: help
Usage: genkey [options] servername
    --test   Test mode, faster seeding, overwrite existing key
    --genreq Generate a Certificate Signing Request (CSR)
    --makeca Generate a self-signed certificate for a CA
    --days   Days until expiry of self-signed certificate (default 30)
    --renew  CSR is for cert renewal, reusing existing key pair, openssl certs only
    --cacert Renewal is for a CA certificate, needed for openssl certs only
    --nss    Use the nss database for keys and certificates
    --gdb    For package maintainers, to trace into the nss utilities
genkey ${httpdomain}

Génération du certificat public et de la clé auto-signée

openssl req -nodes -x509 -newkey rsa:4096 -days 365 \
-out /etc/pki/tls/certs/${httpdomain}.crt \
-keyout /etc/pki/tls/private/${httpdomain}.key \
-subj "/C=BE/ST=Brussels/L=Brussels/O=IT/CN=${httpdomain}"

Génération d’un CSR en manuel

  • Génération d’un clé sécurisée et non sécurisée
  • Génération du CSR

Eventuellement, auto-signer la requête CSR avec sa propre clé.

Si plusieurs certificats sont à gérér en interne, il est peut être nécessaire d’implémenter une autorité de certification (CA).

Ansible : Module command

Voici une solution fonctionnelle avec le module command mais elle est “brut de décoffrage”.

- name: Install nginx and python-openssl
  apt:
    name:
      - nginx
      - python-openssl
    update_cache: yes
    cache_valid_time: 3600

- name: Create self-signed certificate, if configured.
  command: >
    openssl req -x509 -nodes -subj '/CN=localhost' -days 365
    -newkey rsa:4096 -sha256 -keyout {{ key_file }} -out {{ cert_file }}
    creates={{ cert_file }}
  notify: restart nginx

- name: "fix right on key file"
  file:
    name: "{{ key_file }}"
    mode: 0600
  notify: restart nginx

Ansible : Modules openssl_*

Voici une solution avec des variables et des tâches idempotentes grâce aux modules Ansibles openssl_* :

  • openssl_privatekey
  • openssl_csr
  • openssl_certificate
  • openssl_dhparam

Variables

vars:
  key_file: "/path/{{ ansible_fqdn }}.key.pem"
  csr_file: "/path/{{ ansible_fqdn }}.csr.pem"
  cert_file: "/path/{{ ansible_fqdn }}.cert.pem"
  dh_file: "/path/{{ ansible_fqdn }}.dh.pem"

Tâches

- name: Generate an OpenSSL private key.
  openssl_privatekey:
    path: "{{ key_file }}"
  notify: restart nginx

- name: Generate an OpenSSL CSR.
  openssl_csr:
    path: "{{ csr_file }}"
    privatekey_path: "{{ key_file }}"
    common_name: "{{ ansible_fqdn }}"
  notify: restart nginx

- name: Generate a Self Signed OpenSSL certificate.
  openssl_certificate:
    path: "{{ cert_file }}"
    privatekey_path: "{{ key_file }}"
    csr_path: "{{ csr_file }}"
    provider: selfsigned
  notify: restart nginx

- name: "fix right on key file"
  file:
    name: "{{ key_file }}"
    mode: 0600
  notify: restart nginx

Pour générer un fichier Diffie-Helman (DH) :

- name: "generate a DH key"
  openssl_dhparam:
    path: "{{ dh_file }}"
    size: 2048

Fichier de configuration du vhost HTTPS par défaut

A l’installation du groupe “Web Server” sous Centos7/RHEL7, un fichier /etc/httpd/conf.d/ssl.conf active par défaut un vhost HTTPS (yum install -y mod_ssl), celui sert par défaut les pages en HTTPS.

grep -v '^$\|^\s*\#' /etc/httpd/conf.d/ssl.conf
Listen 443 https
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300
SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
<VirtualHost _default_:443>
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
    SSLOptions +StdEnvVars
</Files>
<Directory "/var/www/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

On peut le désactiver en renommant ce fichier autrement qu’en .conf, ce qui n’est pas nécessaire dans notre exercice.

mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf.bak

Nouveau vhost HTTPS

Par rapport à une configuration HTTP simple, quelques directives comme SSLCertificateFile, SSLCertificateKeyFile ainsi que d’autres paramètres comme le port d’écoute TCP 443 sont à ajouter/adapter. On ajoutera cette entrée dans le fichier de configuration.

cat << EOF >> /etc/httpd/conf.d/host1.example.com.conf
<VirtualHost *:443>
ServerAdmin webmaster@host1.example.com
DocumentRoot /var/www/html/host1.example.com
ServerName host1.example.com
ErrorLog /var/log/httpd/host1.example.com-error_log
CustomLog /var/log/httpd/host1.example.com-access_log common
    SSLEngine on
    # 128-bit mini anti-beast
    #SSLCipherSuite !EDH:!ADH:!DSS:!RC2:RC4-SHA:RC4-MD5:HIGH:MEDIUM:+AES128:+3DES
    # 128-bit mini PFS favorisé
    #SSLCipherSuite !EDH:!ADH:!DSS:!RC2:HIGH:MEDIUM:+3DES:+RC4
    # 128-bit securité maximale
    SSLCipherSuite !EDH:!ADH:!DSS:!RC4:HIGH:+3DES
    SSLProtocol all -SSLv2 -SSLv3
    SSLCertificateFile /etc/pki/tls/certs/host1.example.com.crt
    SSLCertificateKeyFile /etc/pki/tls/private/host1.example.com.key
</VirtualHost>
EOF

Vérifier la configuration.

apachectl configtest

Redémarrer le service et adapter le pare-feu.

apachectl restart
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

Vérifications

httpd -D DUMP_VHOSTS
VirtualHost configuration:
*:80                   host1.example.com (/etc/httpd/conf.d/host1.example.com.conf:1)
*:443                  is a NameVirtualHost
         default server host1.example.com (/etc/httpd/conf.d/host1.example.com.conf:9)
         port 443 namevhost host1.example.com (/etc/httpd/conf.d/host1.example.com.conf:9)
         port 443 namevhost 192.168.122.38 (/etc/httpd/conf.d/ssl.conf:56)

Vérification client/serveur HTTP.

curl http://host1.example.com
host1.example.com test page

Vérification client/serveur HTTPS.

curl -k https://host1.example.com
host1.example.com test page

Vérification du certificat.

openssl s_client -connect host1.example.com:443 -state
...

Script create_vhost_httpds.sh

Source : https://gist.github.com/goffinet/935c79afaffb6860386880e8bbfb7287

bash -x create_vhost_httpds.sh host1.example.com
#!/bin/bash
#create_vhost_httpds.sh in Centos7
#Variables
host=$1
port="443"
location="/var/www/html"
error_log="/var/log/httpd/${host}-error_log"
access_log="/var/log/httpd/${host}-access_log common"
#Résolution de nom locale
echo "127.0.0.1 ${host}" >> /etc/hosts
#Création du dossier et des pages Web
mkdir -p ${location}/${host}
echo "${host} test page" > ${location}/${host}/index.html
#Restauration de la policy Selinux sur le dossier créé
restorecon -Rv ${location}/${host}
#Création du dossier et des fichiers pour les logs
mkdir -p /var/log/httpd
touch ${error_log}
touch ${access_log}
#Configuration du vhost HTTPS
cat << EOF >> /etc/httpd/conf.d/${host}.conf
<VirtualHost *:${port}>
ServerAdmin webmaster@${host}
DocumentRoot ${location}/${host}
ServerName ${host}
ErrorLog ${error_log}
CustomLog ${access_log} common
    SSLEngine on
    SSLCipherSuite !EDH:!ADH:!DSS:!RC4:HIGH:+3DES
    SSLProtocol all -SSLv2 -SSLv3
    SSLCertificateFile /etc/pki/tls/certs/${host}.crt
    SSLCertificateKeyFile /etc/pki/tls/private/${host}.key
</VirtualHost>
EOF
#Génération du certificat auto-signé
openssl req -nodes -x509 -newkey rsa:4096 \
-out /etc/pki/tls/certs/${host}.crt \
-keyout /etc/pki/tls/private/${host}.key \
-days 365 \
-subj "/C=BE/ST=Brussels/L=Brussels/O=webteam/CN=${host}"
#Activation et lancement du service
systemctl enable httpd
systemctl start httpd
systemctl restart httpd
#Diganostic
curl https://${host}
httpd -D DUMP_VHOSTS

Redirection HTTP vers HTTPS

Voir Let’s Encrypt.

Script vhost-creator

Pour la curiosité.

Source : https://github.com/mattmezza/vhost-creator.

2.4. Let’s Encrypt en Centos 7 pour Apache

Source : https://certbot.eff.org/all-instructions/#centos-rhel-7-apache

Installation du logiciel

yum install epel-release
yum install python2-certbot-apache

Démarrage rapide

certbot --apache
certbot --apache certonly
certbot renew --dry-run

Fonction Let’s Encrypt pour une installation silencieuse

https_installation() {
site_name="www.mondomainepublic.fr"
# Three times if DNS failure
certbot --apache --register-unsafely-without-email --agree-tos -d "${site_name}" -n || \
certbot --apache --register-unsafely-without-email --agree-tos -d "${site_name}" -n || \
certbot --apache --register-unsafely-without-email --agree-tos -d "${site_name}" -n
(crontab -l 2>/dev/null; echo "0 0,12 * * * python -c "import random; import time; time.sleep(random.random() * 3600)" && certbot renew") | crontab -
}

2.5. Activation de HTTP/2

La disponibilité de HTTP2 dans HTTPd Server dépend du modulemod_http2 :

LoadModule http2_module modules/mod_http2.so

On déclarera l’utilisation de HTTP/2 avec la directive Protocols dans la configuration globale ou dans un conteneur <VirtualHost ...>.

  • h2 correspond à HTTP/2 sur TLS (négociation de protocole via ALPN).
  • h2c correspond à HTTP/2 sur TCP.

L’ordre des protocoles a son importance !

Protocols http/1.1
<VirtualHost ...>
    ServerName test.example.org
    Protocols h2 http/1.1 h2c
</VirtualHost>

Dans cet exemple, Protocols h2 http/1.1 h2c désigne dans l’ordre HTTP/2 sur TCP, HTTP/1.1 et enfin HTTP/2 sur TLS.

Source : Guide HTTP/2

Plus détaillé : Setting up HTTP/2 on your web server

3. Nginx

Nginx Beginner’s Guide

4. Bases de données

4.1. MariaDB SQL Server

  • Install and configure MariaDB.
  • Backup and restore a database.
  • Create a simple database schema.
  • Perform simple SQL queries against a database.

Installation et configuration de Mariadb

Installation de MariaDB

yum install -y mariadb mariadb-server
systemctl start mariadb && systemctl enable mariadb

Il s’agit de profiter de l’absence de mot de passe sur le compte root pour créer la base et l’utilisateur de la base de données.

dbuser=user
dbuser_password=testtest
dbroot_password=testtest
database_creation() {
# Create dbuser
mysql -e "CREATE USER ${dbuser}@localhost IDENTIFIED BY '${dbuser_password}';"
# Create database
mysql -e "CREATE DATABASE javatest;"
mysql -e "USE javatest; CREATE table testdata (id int not null auto_increment primary key,foo varchar(25),bar int); INSERT into testdata values(null, 'hello', 12345);"
# Fix dbuser rights on wp_database
mysql -e "GRANT ALL ON javatest.* TO ${dbuser}@localhost;"
# Make our changes take effect
mysql -e "FLUSH PRIVILEGES"
}

Sécurisation de type mysql_secure

mysql_secure() {
# mysql_secure_installation as model
# Make sure that NOBODY can access the server without a password
mysql -e "UPDATE mysql.user SET Password = PASSWORD('${dbroot_password}') WHERE User = 'root'"
# Kill the anonymous users
mysql -e "DROP USER ''@'localhost'"
# Because our hostname varies we'll use some Bash magic here.
mysql -e "DROP USER ''@'$(hostname)'"
# Kill off the demo database
mysql -e "DROP DATABASE test"
# Make our changes take effect
mysql -e "FLUSH PRIVILEGES"
}

4.2. PostgreSQL

4.3. Oracle SQL Server

4.4. Redis

4.5. MongoDB

4.6. Apache Derby