Configuration d'Apache
Apache est un serveur web, que nous utilisons sur certains de nos serveurs. Une autre solution populaire est Nginx. Les deux sont très bien, répondant à des logiques similaires et adapté à de nombreuses situations. Dans le cas des ordinateurs les moins puissants (type Raspberry), on préférera tout de même des logiciels plus léger comme Lighttpd.
Apache est un composant de première importance pour les sites web. Son paramétrage correct et l'attention à certaines options améliorent la sécurité globale du serveur ; à l'inverse, oublier certains détails peut amener des failles exploitables par des attaquants.
Apache a un avantage dans le cas d'une architecture “pare-feu qui protège des serveurs”, il est assez facile d'avoir une communication mixte entre le pare-feu et les serveurs, avec et sans chiffrement. Certains logiciels ont besoin que toutes les communications soient protégés ; par exemple Teampass ne fonctionne pas sans https sur le serveur où il est installé (même si le pare-feu, lui, sert l'accès à l'internaute en https).
Pour l'installation, sur Debian et dérivées :
sudo apt install apache2
Pour connaître sa version d'apache :
apache -v
Tester la configuration et relancer le service
C'est une manipulation à refaire après avoir modifié les fichiers, alors autant donner les commandes dès le début…
Pour vérifier avant tout que la syntaxe est propre :
sudo apachectl -t
Pour relancer le serveur apache :
sudo apachectl graceful
Cette commande redémarre le démon Apache httpd en douceur. Si le démon n'est pas en cours d'exécution, il est démarré. À la différence d'un redémarrage normal, les connexions en cours ne sont pas fermées. Comme effet de bord, les anciens fichiers journaux ne seront pas fermés immédiatement. Cela signifie que si l'on utilise un script de rotation des journaux, un délai suffisant sera nécessaire afin d'être sûr que les fichiers journaux seront bien fermés avant leur traitement par le script de rotation. Cette option vérifie automatiquement les fichiers de configuration (de la même manière que l'option configtest ) avant de lancer le redémarrage, afin d'être sûr que le fonctionnement du démon ne sera pas compromis. Équivalent à apachectl -k graceful.
- Source : doc d'Apache (en français !)
Renseigner les vhosts de son site
Pour chaque domaine et sous-domaine, on crée un fichier conf
dans /etc/apache2/sites-available/
. Pour s'y retrouver, mieux vaut donner le nom du sous-domaine au fichier en question… Il y a toujours deux fichiers à faire : celui pour “http” et celui pour “https”, qu'on appelle vhosts. Dans les faits, le http renvoie directement sur https, aussi il va être très sobre.
Cela ressemblera à quelque chose comme ça :
txt /etc/apache2/sites-available/monsite-org.conf
<VirtualHost *:80>
ServerName monsite.org
DocumentRoot /var/www/monsite
RewriteEngine On
RewriteCond %{REQUEST_URI} !.well-known/acme-challenge
RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [R=301,L]
</VirtualHost>
VirtualHost *:80
: indique le port concerné, 80 c'est http (et ça ne se bidouille pas !). Toutes les informations concernant le site sont entre ces deux balises “VirtualHost”.ServerName
: à renseigner obligatoirement. C'est le nom de domaine qui permet d'accéder au site.DocumentRoot
: nécessaire aussi ! Indique où sont les fichiers du site web sur le serveur. Astuce “bonne pratique”, créez un dossier dans /var/www au nom de votre domaine/sous-domaines.RewriteEngine On
: indique d'utiliser la réécriture des URL (voir plus bas)- Les deux lignes suivantes sont là pour rediriger en https ; la première est lié à l'usage de let_s_encryptcertbot et s'adapte suivant quel sorte de certificat SSL vous utilisez.
Le vhosts en https a un port différent, et c'est là qu'on configurera toutes les options : alias, etc.
txt /etc/apache2/sites-available/monsite-org-ssl.conf
<VirtualHost *:443>
ServerName monsite.org
DocumentRoot /var/www/monsite
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/monsite.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/monsite.org/privkey.pem
Alias /dokuwiki /var/www/monsite/undossier/unautredossier/dokuwiki
<Directory /var/www/monsite/ >
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
- Le port, cette fois, est 443.
- Il faut renseigner à nouveau
ServerName
etDocumentRoot
, comme pour le 80. SSLEngine on
: active la prise en charge du certificat SSL, ce qui est un peu obligatoire (ceci dit, quand le module est actif, oublier cette option dans le vhost ne semble pas gêner la prise en charge du certificat…).SSLCertificateFile
etSSLCertificateKeyFile
: indique le chemin des deux fichiers du certificat. Il faut évidement adapter le chemin au nom de domaine, et avoir généré le certificat (on voit ça plus bas).Alias
: permet de faire des URL plus élégantes. Une option parmi d'autres… Ici, sans alias, le dokuwiki serait accessible avec le lien “monsite.org/undossier/unautredossier/dokuwiki” ce qui est longuet ; l'alias permet que le lien “monsite.org/dokuwiki” serve le dokuwiki. On peut même pointer un dossier hors de/var/www
(par exemple/home/moi/unboutdesite
. Il y a parfois des bonnes raisons de le faire ;). Voir plus bas le détail !Directory
: va permettre de déclarer diverses options, rendant le dossier (et donc le site web associé) utilisable pour la navigation web, en tirant partie par exemple des possibilités de php, mais aussi en indiquant ce qui est permis et interdit et contribue donc un peu à la sécurité. Ici, ce sont des options classiques qui fonctionnent dans 90% des cas. Mais il faut adapter parfois suivant les dossiers :Options
: attention à déclarer uniquement ce qui est utile.Indexes
permet de lister les fichiers dans un répertoire si aucun fichier index (comme index.html ou index.php) n'est présent, ce qui peut poser des problèmes de sécurité. Donc on peut éviter ?FollowSymLinks
: Autorise Apache à suivre les liens symboliques (symlinks) dans le répertoire. Voir aussi la doc surSymLinksIfOwnerMatch
(usage plus spécifique).MultiViews
: Permet à Apache de servir différentes versions d'un même fichier selon la requête du client (langue, type de contenu, etc.)ExecCGI
,Includes
,IncludesNOEXEC
sont intéressants mais allez voir la doc officielle, parce que c'est assez pointu comme usage.None
: pour interdire toutes les options dans un répertoire.
AllowOverride All
permet l'utilisation de fichiers .htaccess ; cela peut avoir un impact sur les performances. Mais pas mal de CMS utilisent les htaccess.Require all granted
: Remplace les anciennes directivesOrder allow,deny
etallow from all
. Cela autorise toutes les requêtes à accéder à ce répertoire.Require all denied
pour interdire l'accès (utile pour s'assurer que certains dossiers ne seront pas du tout accessibles)Require ip
: Permet de restreindre l'accès à des adresses IP spécifiques ou à des plages d'adresses IP.Require host
: Permet d'autoriser l'accès basé sur le nom d'hôte de la requête.Require user
etRequire valid-user
: Permet d'accorder l'accès à des utilisateurs spécifiques ce qui demande d'utiliser des mécanismes d'authentificationRequire env
: Permet d'accorder l'accès en fonction d'une variable d'environnement, ça commence à être assez pointu comme usage.Require expr
: Permet d'utiliser une expression conditionnelle pour contrôler l'accès. Par exemple toutes les ip du réseau interne.
Après chaque modification de ces fichiers, afin que ce soit pris en compte, vérifiez la configuration et relancez le service apache
sudo apachectl -t && sudo apachectl graceful
Modifier les urls pour aller aux dossiers (Alias)
Avec une configuration basique, Apache indique qu'il faut lire le répertoire renseigné dans DocumentRoot
comme répertoire de base du site, chaque dossier se rajoutant à l'adresse. Par exemple si l'option est DocumentRoot /var/www/monsite
et que votre dossier a la hiérarchie suivante :
- var
- www
- monsite
- dossier1
- dossier2
- index.html
Alors pour accéder via le web à page1
il faudra mettre dans la barre d'adresse du navigateur monsite.org/dossier1/dossier2/index.html
On change ça en faisant des alias dans le fichier /etc/apache2/sites-enable/000-default.conf
, de cette façon :
Alias /adresse /var/www/monsite/dossier1/dossier2
Changez /adresse
par ce que vous voulez. Ici, dans cet exemple, notre page “index.html” sera à présent accessible à l'adresse monsite.org/adresse/index.html
Vous pouvez aussi pointer vers des adresses hors de /var/www
, par exemple pointer vers home/user/monsite
, ce qui vous permet de travailler dans un répertoire avec des droits utilisateurs basique.
Droits sur www
Plusieurs possibilités pour permettre, en tant qu'utilisateur Lambda1), de modifier ce qui se trouve dans le dossier /var/www.
Le plus simple et rapide est d'attribuer les droits de ce dossier au groupe www-data, et de mettre lambda dans le groupe www-data.
sudo adduser lambda www-data chown -R www-data: /var/www
Méthode alternative :
Pour ajouter l'utilisateur lambda à www-data, il y a aussi la commande
usermod -a -G www-data lambda
Les deux sont similaires.
Relancer la session pour que les droits soient pris en compte pour l'utilisateur en cours.
Il vaut mieux laisser le groupe www-data gérer les droits, de base, parce que sinon c'est un beau bazar. Ajouter l'utilisateur “lambda” dans ce groupe permet de modifier tout sans se prendre la tête.
Si certains cms posent problèmes, la suite de commande suivante sur le dossier en question peut réattribuer les droits à www-data et permettre de les résoudre :
sudo chgrp -R www-data Dossier sudo chown -R www-data Dossier sudo chmod -R g+w Dossier
chgrp
pour réaffecter le groupe propriétairechown
pour changer le propriétaire tout court (moins important, en théorie chgrp devrait déjà régler la plupart des soucis)chmod
pour donner les bonnes permissions de lecture/écriture sur le dossier (g
pour groupe,+
pour ajouter,w
pour write, donc “écrire”).- L'option
-R
permet la récursivité (que le changement s'applique dans les sous-dossiers).
Cacher la version d'apache
Ceci est une option améliorant la sécurité.
En principe nos serveurs sont à jours, hein. Mais en cas d'oubli, ne facilitons pas la tâche des observateurs :
nano /etc/apache2/conf-available/security.conf
# Cacher la version d'Apache2 ServerTokens Prod ServerSignature Off
service apache2 restart
À refaire sur chacun de ses serveurs !
On peut aussi paramétrer (et modifier) ces options dans /etc/apache2/apache2.conf
mais c'est moins élégant.
Il faut activer le fichier, non ? Cette partie du tuto demande à être vérifiée.
Activation et paramétrage des modules
Par défaut, Apache est assez “sobre”. Il faut activer divers modules pour bénéficier de certaines fonctionnalités. Certains sont nécessaires pour la sécurité, d'autres sont juste tellement utiles qu'on s'en passe rarement.
Dans les modules à activer quoi qu'il arrive (voir plus bas le détail) :
sudo a2enmod headers ssl
Module SSL
Aujourd'hui, rien ne permet de justifier la navigation non chiffrée. SSL est une mesure de sécurité, qui ne vous coûte rien en tant que sysadmin (grâce à Let's Encrypt) et qui peut éviter un certain nombre de soucis. Alors, par défaut, vos sites doivent être en https. C'est tout.
Pour connaître sa version d'apache et d'openssl :
apache -v openssl version
À utiliser sur Mozilla SSL Configuration Generator pour générer les options de base à mettre dans sa configuration, ce sera probablement plus à jour que ce tutoriel au fil du temps.
Activer le module ssl dans Apache si ce n'est pas déjà fait :
a2enmod ssl
Puis modifiez le fichier /etc/apache2/mods-available/ssl.conf
suivant ces informations :
- Enlever le protocole SSL3 et SSLv2 qui ne sont plus considérés comme sûrs (notez le “-” devant SSLv3 et SSLv2)
- Interdire la compression d'échanges chiffrés (oui oui cela introduit une possibilité d'attaque)
- Lister la liste des algorithmes de chiffrement autorisés et interdits
- Imposer de négocier ces protocoles dans l'ordre, donc du plus sûr au moins sûr (notez le “!” devant certains nom d'algorithme pour les interdire, par exemple : !PSK, !RC4, etc… et le + devant ceux à favoriser)
- Le dernier morceau concerne OCSP qui accélère un peu les échanges en https, voir aussi Accélérer votre réponse SSL/TLS avec l’OCSP Stapling
SSLProtocol +TLSv1.2 SSLCompression off SSLCipherSuite HIGH:!aNULL:!eNULL:!LOW:!MEDIUM:!EXP:!RC4:!3DES:!MD5:!PSK:!kRSA:!SRP:-DH:+ECDH SSLHonorCipherOrder On # OCSP Stapling, only in httpd 2.3.3 and later SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off SSLStaplingCache shmcb:/var/run/ocsp(128000)
Pour la liste SSLCipherSuite
, consulter les préconisations de Mozilla SSL Configuration Generator et lire tranquillement l'explication si dessous avant de modifier la proposition mise à jour le 29 novembre 2017.
À partir de la version 2.4.11 d'apache, vous pouvez ajouter dans le fichier /etc/apache2/mods-available/ssl.conf
:
SSLSessionTickets Off
Explications
Ce qui suit est extrait d'une conversation avec TychoBrahe ; j'ai conservé son style fleuri si savoureux.
— zatalyz 2016/12/30 13:27
Une ciphersuite est un ensemble de 4 algorithmes différents, chacun servant à un rôle distinct :
- 1 pour faire un échange de clés
- 1 pour faire du chiffrement asymétrique
- 1 pour faire du chiffrement symétrique
- 1 pour le contrôle
Un exemple : DHE-RSA-AES256-SHA256
- DHE : diffie hellman, c'est l'échange de clés
- RSA pour l'asymétrique, en particulier pour la signature
- AES avec une clé de 256 bits pour le chiffrement symétrique
- et enfin sha256 pour calculer les empreintes des sommes de contrôle
On pourrait croire qu'il y a 5 algorithmes, par exemple avec ECDHE-RSA-AES128-GCM-SHA256. En fait, GCM est un des modes de fonctionnement d'AES, donc AES128-GCM désigne de l'AES en mode GCM avec une clé de 128 bits. Pour info, les EC devant ECDHE et parfois ECDSA c'est pour elliptic curve, donc l'utilisation de courbes elliptiques au lieu de nombres premiers.
SSL et TLS permettent d'utiliser non pas une seule combinaison, mais plusieurs, ce qui fait que ces protocoles intègrent une phase de négociation de la cipher suite. Chaque version de SSL ou TLS autorise ou non certaines cipher suites etc, bref c'est le bordel, sachant qu'il faut, avant ça, négocier la version de SSL ou TLS utilisée. Soit dit en passant, il existe une cipher suite NULL qui dit qu'il n'y a aucun chiffrement, du coup cette phase de négociation a été attaquée, un MITM2) permettant de forcer une cipher suite (genre NULL ou une faible).
Afin d'éviter les ennuis, on va dire au serveur de n'utiliser que certaines cipher suites et pas d'autres : c'est l'option SSLCipherSuite. Chaque cipher suite est séparée par :
et s'il y a un !
devant son nom, c'est pour explicitement l'interdire.
Le site de Mozilla cite toutes les ciphersuites, c'est sans doute bien, mais ils ont juste oublié un truc : à tout citer explicitement, il faut faire évoluer la liste avec les avancées en matière de recherche. Personnellement j'utilise et recommande d'utiliser des familles. Ces familles sont définies par la librairie SSL/TLS utilisée :
- ALL ← on autorise tout
- !aNULL:!eNULL ← on interdit les familles de NULL
- !LOW:!MEDIUM ← on interdit les cipher suites disposant d'une clé de 128 bits (MEDIUM) ou moins (LOW)
- !EXP ← ce sont les variantes d'exportation, donc fortement affaiblies, de certains algos
- !RC4 ← RC4 est un algo de chiffrement symétrique qui a été démoli mais un truc bien grave alors qu'il était très populaire
- !3DES ← pareil, on interdit cette merde
- !MD5 ← celui qui utilise encore md5 pour du checksum crypto est un grand malade
- !PSK ← pareil, une merde de plus de virée
- +HIGH ← et enfin on autorise la famille des cipher suites reconnues comme fortes
Du coup on fait confiance dans les familles définies dans les lib crypto, mais en imposant des restrictions sur certains trucs trop limite pour y être inclus mais qui ont des chances de tout de même s'y retrouver.
Les librairies ont un outil pour lister les familles, qui liste soit toutes les cipher suites supportées, soit, si on précise, la liste de ce qui est autorisé :
openssl ciphers openssl ciphers HIGH openssl ciphers 'HIGH:!AES'
Voir aussi
man 1 ciphers
L'échange de clefs
C'est un mécanisme permettant l'échange de clefs en toute confidentialité, sans qu'un tiers puisse avoir connaissance de celles-ci.
Le chiffrement a/symétrique
La différence entre le chiffrement symétrique et le chiffrement asymétrique est que dans le premier cas, il n'y a besoin que d'une seule clef, qui permet aussi bien de chiffrer un message que de le déchiffrer. Pour le chiffrement asymétrique, on utilise une clef pour le chiffrement, et une autre clef différente de la première pour le déchiffrement. C'est pour cela qu'on parle de clef dite publique (celle que tout le monde peut voir et avec laquelle on va chiffrer les messages qui nous sont destinés) et de clef dite privée (celle avec laquelle on va déchiffrer notre message ; si on n'a pas accès à cette clef privée, on ne peut pas déchiffrer le message).
Le contrôle
Afin de vérifier l'intégrité des messages que l'on transmet, on calcule une somme de contrôle que l'on envoie avec le message. Une fois le message et sa somme de contrôle réceptionnés, on peut recalculer la somme de contrôle du message et vérifier qu'elle correspond bien à celle qui a été transmise. Si elles diffèrent, c'est que le message a été altéré (ou qu'il y a une collision, c'est à dire que pour deux messages différents on obtient la même somme de contrôle, mais ce cas ne devrait quasiment presque jamais arriver).
Module header
Activer les headers dans Apache si ce n'est pas déjà fait :
sudo a2enmod headers
Puis modifiez le fichier /etc/apache2/mods-available/headers.conf
:
# Ce qui suit vient de # https://blog.adminrezo.fr/2016/12/securiser-serveur-apache-https-headers/ # Contrôler l’accès des bots de facon plus fine qu'avec robots.txt : Header set X-Robots-Tag "index,follow,noarchive" # Évite que le contenu soit interprété différemment que définit dans le mime Type Header set X-Content-Type-Options nosniff # Protection contre le clickjacking Header set X-Frame-Options "SAMEORIGIN" # Protection contre les failles X-XSS Header set X-XSS-Protection "1; mode=block" # Faille spécifique IE8, on espère que plus personne ne l'utilise, mais... Header set X-Download-Options noopen; # Interdire l'embarquement de tout ou partie de votre site dans un site ou logiciel tiers Header set X-Permitted-Cross-Domain-Policies none # X-Clacks, ça sert à rien, c'est donc vital. header set X-Clacks-Overhead "GNU Terry Pratchett" # Enfin, les CSP permettent de vérifier l'origine des éléments du site # CSP, pour éviter de charger des scripts d'ailleurs. /!\ partie complexe à gérer suivant vos CMS Header set Content-Security-Policy "default-src 'self' *.monsite.org 'unsafe-eval' 'unsafe-inline' "
Les explications :
- Header set X-Robots-Tag : http://robots-txt.com/x-robots-tag/
Content Security Policy (CSP)
Les CSP améliorent grandement la sécurité d'une installation, en interdisant à certaines ressources de s'exécuter, par exemple des scripts malicieux injectés dans vos sites webs.
Mais il est difficile de faire marcher les CMS tout en ayant une politique sécurisée sur les CSP.
Le site de référence est https://content-security-policy.com/. En anglais, mais il contient toute la documentation officielle sur le sujet.
- Premier cas : pas de politique CSP. Certains CMS permettent aux utilisateurs d'appeler “des bouts de web” venant d'ailleurs, généralement les images, mais dans certains cas aussi du code… Un attaquant peut se servir de ça pour appeler sur le serveur un code malicieux. Un CMS sécurisé réduit beaucoup les possibilités, mais le risque zéro n'existe pas, et la plupart des CMS ont des failles, c'est un fait.
- Second cas : une politique CSP stricte (paramétrée uniquement sur
self
). Ici, plus moyen d'appeler un truc d'ailleurs. Par contre cela va bloquer le fonctionnement légitime de certains CMS, entre autre ce qui concerne les scripts (pourquoi, je n'ai pas pas encore bien compris, mais c'est un fait). - Troisième cas : ajouter des règles comme
unsafe-eval
etunsafe-inline
. Cela va permettre aux scripts en question de fonctionner MAIS cela permet aussi à certains attaquant d'utiliser des failles : comme leur nom l'indique, cela est considéré comme “non sécurisé”. Ils autorisent explicitement certains trucs à marcher, sans plus de vérification. Cela ouvre la porte à des injections. Cependant, d'après mes tests, les scripts ayant une adresse externe ne sont PAS exécutés sur le domaine. Ne vous sentez pas en confiance pour autant. - Quatrième cas : exécuter localement uniquement les scripts validés explicitement. Cela demande de rajouter la variable
nonce
ouhash
, puis d'ajouter dans chacun des scripts de notre serveur la clé associée (un hash sur les scripts, ou bien une clé dans ces derniers). Cela veut donc dire : avoir la main sur tout… c'est assez irréaliste dans la majorité des cas, et entre autre pour les CMS qui embarquent trop de scripts et qui écraseront nos modifications à chaque mise à jour. Cela demande aussi un certain niveau de développement, or la plupart des sysadmin/webmestres sont surtout des bidouilleuses, pas des développeuses.
Quelques exemples
L'option suivante permet à Dokuwiki et Simple Machine Forum de marcher, mais pas à Etherpad, et ne vaut rien aux yeux de l'Observatoire Mozilla. Cependant, même l'etherpad de Mozilla ne fait pas mieux.
Header set Content-Security-Policy "default-src 'self' *khaganat.net; script-src 'self' 'unsafe-inline' *khaganat.net; style-src 'self' 'unsafe-inline'; img-src * "
img-src *
ici accepte tout, mais sans ça, on n'affiche plus les images en lien, par exemple dans le forum, ce qui demande une solution interne pour les héberger.
Pour onlyoffice, après de nombreuses galères : la solution a été la CSP frame-ancestors pour permettre l'accès à une autre instance Onlyoffice par plusieurs instances nextcloud. Dans ce cas sur nginx avec le module more_headers, ça a donné ça :
more_set_headers "Content-Security-Policy : frame-ancestors https://site1.example.com/nextcloud https://site2.example.com/ https://site3.example.com/nextcloud ";
La règle suivante, assez générique, va “fonctionner” pour la plupart des CMS. La mettre dans une règle sur le proxy, appelée par les diverses configurations :
add_header Content-Security-Policy "default-src 'self' *.monsite.org 'unsafe-eval' 'unsafe-inline'; ";
Activer la réécriture des URLs
Pour la ferme de wiki ou le pastebin (entre autre), il faut activer la réécriture des URLs.
Lancez la commande :
sudo a2enmod rewrite
Dans les vhosts (/etc/apache2/sites-available/monsite-ssl.conf
), mettez l'option AllowOverride
sur All
là où il y a besoin de réécriture d'url. Généralement, tout le dossier /var/www pour pas se compliquer la tâche.
txt /etc/apache2/sites-available/monsite-org-ssl.conf
<VirtualHost *:443>
ServerName monsite.org
DocumentRoot /var/www/monsite
<Directory /var/www/monsite/ >
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
[...]
</VirtualHost>
Options lorsqu'un proxy est actif
Le proxy permet d'avoir un intermédiaire qui relaie les requêtes aux serveurs cibles. Typiquement quand on a une seule ipv4 et des VM sur le réseau interne, c'est un peu obligé ; mais cela peut aussi s'appliquer dans d'autres cas, par exemple pour faire du load balancing, de la mise en cache, pour des aspects de sécurité, etc.
Il faut bien activer les modules apache correspondants :
a2enmod proxy a2enmod proxy_http
Les arguments proxy
ProxyPass
indique qu’Apache redirige toutes les requêtes du nom de domaine renseigné avecServerName
vers l'adresse ip et le port du serveur cible.ProxyPass [path] [url] [key=value …]
, par exempleProxyPass / http://backend_server:8080/
path
peut être un chemin, par exemple/app
; dans ce cas seules les requêtes àhttp://example.org/app
seront redirigées vers le serveur backend.- les key=value peuvent être
retry
,timeout
, etc.
ProxyPassReverse
ajuste les en-têtes HTTP (Location
,Content-Location
etURI
) pour que les liens dans les réponses du serveur backend soient corrects pour le client.ProxyPassReverse / http://backend_server:8080/
ProxyPreserveHost
permet de contrôler si le serveur Apache transmet l'en-têteHost
d'origine du client au serveur backend. Si c'est sur On, on aura donc l'ip/le domaine du visiteur disponible sur le serveur backend dans les logs, sinon l'ip/le domaine du proxy. C'est plutôt utile sur la modération.ProxyPreserveHost On
ProxyPassMatch
est similaire àProxyPass
, mais permet d'utiliser des expressions régulières pour définir les chemins à rediriger. Puissant mais pas toujours évident.ProxyPassMatch ^/api/(.*)$ http://backend_server/api/$1
ProxyErrorOverride
force Apache sur le proxy à renvoyer ses propres pages d'erreur au lieu de celles du serveur backendProxyErrorOverride On
ProxyVia
permet d'ajouter des en-têtes Via aux requêtes traitées par un serveur proxy. Utile au débogage mais a un impact sur la confidentialité (permet à des tiers de savoir qu'il y a un proxy).ProxyRequests
: permet (ou non) au serveur de servir de proxy à des clients externes.On
: proxy ouvert, ce qui peut poser des soucis de sécurité, il faut bien paramétrer <Proxy *> ensuite. En dehors de cas d'usages très spécifique, à éviter.Off
: mettez ça par défaut.
Les options concernant le cache et les buffers (absolument dispensable) :
ProxyTimeout
définit le temps d'attente maximum pour une connexion vers le serveur backend. Utile pour éviter les temps d'attente trop longs si le backend est lent.ProxyReceiveBufferSize
configure la taille du buffer de réception (des histoires de cache).ProxyIOBufferSize
contrôle la taille des buffers d'entrée/sortie.
Load Balancing (voir plus bas pour un exemple plus concret) :
- BalancerMember : adresses des serveurs qui serviront à répartir la charge
- ProxySet pour configurer des paramètres supplémentaires (timeout, retry, status, etc)
lbmethod=byrequests
distribue les requêtes équitablement entre les serveursstatus=+H
indique l’hôte principal
Sur le serveur même : servir un port particulier
Certains services sont accessibles via des ports particuliers. C'est ce que fait Etherpad par exemple : lors de son installation, il est accessible à l'adresse https://monserveur.org:9001
.
Pour qu'on puisse y accéder via l'adresse web https://monserveur.org/pad
, il faut mettre un proxy en place dans Apache.
Commencer par activer les modules de proxy :
sudo a2enmod proxy proxy_http
Puis ajouter ce genre d'information dans /etc/apache2/sites-availables/monsite.conf
:
<VirtualHost *:443> [...] ProxyVia On ProxyRequests Off ProxyPass /pad/ http://localhost:9001/ ProxyPassReverse /pad/ http://localhost:9001/ ProxyPreserveHost on <Proxy *> Options FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Proxy> [...] </VirtualHost>
Relancez le service apache
sudo apachectl -t && sudo apachectl graceful
Votre etherpad devrait être accessible à la bonne adresse !
Un serveur pare-feu et d'autres derrière
Dans certaines architectures (et entre autre chez Khaganat), nous fonctionnons avec un pare-feu. Toute communication entrante arrive au même endroit, est filtrée, puis redistribuée à diverses VM/containers afin d'isoler les services suivant leurs contraintes.
Dans ce cas, chaque vhost sur le serveur du pare-feu doit contenir ceci :
ServerName sousdomaine.monserveur.net # Proxy : permet de renvoyer vers l'adresse ip du serveur. # Ici l'exemple est dans le cas de VM Xen, c'est donc une adresse locale. ProxyPass / http://192.168.20.43/ ProxyPassReverse / http://192.168.20.43/ ProxyRequests off ProxyPreserveHost on <Proxy *> Options FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Proxy> # SSL SSLEngine on SSLCertificateFile /etc/letsencrypt/live/monsite.org/certificate.pem SSLCertificateFile /etc/letsencrypt/live/monsite.org/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/monsite.org/privkey.pem # HSTS (mod_headers requis) (15768000 seconds = 6 months)(63072000 = 24 mois) Header set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
HSTS (module Header) permet de déclarer au client directement dans la réponse HTTP qu'il faut communiquer en HTTPS. Cet en-tête permet d'éviter le vol de cookies et le downgrade SSL.
# Le paramètre suivant est valide si vous avez amélioré la clé Diffie Hellman SSLDHParametersFile /etc/letsencrypt/live/MONSITE.COM/dhparams.pem
Je n'ai sans doute pas tout compris, ou alors ce n'est pas compatible avec ma version d'apache, mais si je l'ajoute ça me fait une erreur.
— zatalyz 2017/01/01 18:33
Faire suivre les IP derrière les reverse proxy
Si vous avez une VM (A) qui sert de pare-feu avant de redistribuer le trafic aux autres VM (B) de votre serveur, il y a un petit souci : les VM B croient que tout le trafic vient de l'ip de la VM A. Ce qui pose un gros souci dans le cas où vous avez du spam et que votre CMS favori permet de bannir par IP… si vous bannissez la VM A, plus rien ne passera, même les utilisateurs légitimes.
Il faut donc activer le transfert des IP sur les VMs destinataires (pas toucher au pare-feu, ce n'est pas là que ça se joue).
Créer /etc/apache2/conf-available/remoteip.conf
et lui donner ceci :
RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 192.168.20.35
Remplacer 192.168.20.35
par l'IP interne de la VM pare-feu.
Activer le module remoteip qui fait ça :
a2enmod remoteip a2enconf remoteip apache2ctl configtest && service apache2 restart
Cela devrait marcher. À répeter sur chaque VM du réseau.
Load balancing
C'est utile pour les services critiques ou fortement sollicités. Je met la doc ici mais nous n'avons pas (encore) eu l'occasion de vraiment essayer ça.
Un fichier de conf sur le proxy ressemblera à ceci :
<VirtualHost *:80> ServerName example.org # Proxy vers un backend principal avec timeout ProxyPass /app http://backend_server/app retry=5 timeout=60 ProxyPassReverse /app http://backend_server/app # Configuration d'un cluster de load balancing <Proxy balancer://mycluster> BalancerMember http://backend1.example.org BalancerMember http://backend2.example.org status=+H ProxySet lbmethod=byrequests </Proxy> ProxyPass /cluster balancer://mycluster/ ProxyPassReverse /cluster balancer://mycluster/ # Ajustement des en-têtes ProxyPreserveHost On ProxyErrorOverride On </VirtualHost>
Lorsqu'une visiteuse arrive sur example.org
, elle est renvoyée aléatoirement vers le serveur backend1 ou backend2, afin d'éviter de surcharger. retry=5
pour la directive ProxyPass indique qu'Apache essaiera jusqu'à cinq fois de se reconnecter au serveur backend, et s'arrêtera après 60 secondes à chercher (ce qui est long !).
Configuration personnalisées
On peut se faire un fichier de configuration appelant diverses modifs sur tous les sites, par exemple dans /etc/apache2/conf-available/bidouilles.conf
.
Ensuite on peut l'appeler dans chaque config de site en ajoutant la ligne suivante (dans /etc/apache2/sites-enabled/monsite-ssl.conf
, entre les balises VirtualHost
) :
Include /etc/apache2/conf-available/bidouilles.conf
Cela évite de réécrire les mêmes règles partout.
Virer le tracker de Facebook
Facebook changeant régulièrement ses règles, vérifiez que cette bidouille est toujours pertinente.
Quand on partage un lien sur Facebook, et qu'on arrive sur le site, Facebook fait de l'injection pour suivre ses internautes. Vos visiteurs vont visiter vos pages avec un tracker collé à l'url, du type https://monsite.org/?fbclid=IwAR1RNFCx5Gu9SHRAbuj67ebqbu3Hc7YGgkOKh. C'est pas propre, et puis ça peut mettre le bazar dans certains sites.
On peut régler ça au niveau d'Apache et mettre Facebook dehors, en ajoutant cela dans un fichier de conf (par exemple dans /etc/apache2/conf-available/bidouilles.conf
comme expliqué juste avant) :
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{QUERY_STRING} ^(.*)(?:^|&)fbclid=(?:[^&]*)((?:&|$).*)$ [NC] RewriteCond %1%2 (^|&)([^&].*|$) RewriteRule ^(.*) $1?%2 [R=301,L] </IfModule>
Il faut bien sûr avoir le module rewrite activé.
Relancez apache ;)
Astuce tirée de ce site avec quelques aménagements.
Could not reliably determine the server's fully qualified domain name
À chaque modif du serveur, vous avez sans doute droit à ce message d'erreur :
apache2: Could not reliably determine the server's fully qualified domain name, using [IP]. Set the 'ServerName' directive globally to suppress this message
On va donc configurer ça… juste pour ne pas avoir ce message. Nos sites sont configurés par ailleurs, donc cette demande a peu de sens ; on peut l'ignorer, on peut aussi la supprimer. On va créer un fichier de conf globale pour ça !
sudo nano /etc/apache2/conf-available/full-qualified-domain-name.conf
Ajoutez uniquement la ligne suivante (sans rien changer) :
ServerName localhost
Puis activez tout cela :
sudo a2enconf full-qualified-domain-name sudo apachectl graceful
Et voilà.