Relayd et les entêtes
Une gestion fine des entêtes (headers) peut vous intéresser. Cela peut notamment servir pour indiquer aux navigateurs de garder en cache plus longtemps les fichiers téléchargés et alléger la charge du serveur, ou encore régler des questions de sécurité.
httpd n'est pas capable de gérer les entêtes. Heureusement, tout est prévu : nous allons utiliser relayd et le placer avant httpd.
Inutile d'installer quoi que ce soit, relayd est déjà présent dans OpenBSD. Elle est pas belle la vie ? 😁
Pour tester les entêtes de votre site, vous voudrez peut-être visiter securityheaders.com.
Configuration de relayd
La configuration de relayd est écrite dans le fichier /etc/relayd.conf que nous allons éditer.
À l'intérieur, et à titre d'exemple, nous allons mettre les lignes suivantes :
http protocol "http" { match request header remove "Proxy" match response header set "X-Xss-Protection" value "1; mode=block" return error pass } relay "www" { listen on 192.0.2.2 port 80 protocol "http" forward to 127.0.0.1 port 80 }
Voici ce que ces lignes signifient :
- http protocol "http" { : On ouvre la configuration pour tout ce qui concerne le protocole http, qu'on appelle justement "http".
- match request header remove "Proxy" : On retire un entête qui peut poser des soucis de sécurité. Cela se produit à l'arrivée de la requête et permet de ne pas envoyer de mauvais entêtes au serveur httpd.
- match response header set "X-Xss-Protection" value "1;... " : On ajouter un entête pour protèger le site d'attaques XSS.
- return error : On renvoie une erreur s'il y a eu le moindre souci.
- pass : S'il n'y a pas eu de problèmes, on laisse passer.
- relay "www" { : On va définir ici la redirection vers le serveur http.
- listen on 192.0.2.2 : on écoute sur le port 80 pour votre adresse IP publique.
- protocol "http" : On utilise la configuration énoncée plus haut.
- forward to localhost port 80 : On renvoie vers le serveur qui doit initialement recevoir cette requête, c'est à dire httpd.
Justement, afin que httpd prenne la suite de relayd, il doit maintenant écouter en local sur le port 80. On devra donc avoir cette ligne dans la configuration de httpd :
# configuration de httpd listen on localhost port 80
Si on résume, les choses se passent désormais ainsi :
1. Un visiteur demande à voir votre site web, il se présente sur le port 80.
2. relayd modifie quelques entêtes et redirige le tout à httpd qui retourne la page web demandée comme il le faisait d'habitude.
Après avoir réalisé vos modifications, n'oubliez pas d'activer relayd et de redémarrer les services :
# rcctl enable relayd # rcctl restart httpd # rcctl start relayd
Notez que cela va modifier l'apparence des journaux pour httpd qui montreront une origine venant de 127.0.0.1, l'adresse locale de relayd.
Vous préférerez peut-être utiliser le format "forwarded":
log style forwarded
Vous pouvez consulter un exemple de configuration à la fin du document.
TLS ou https
Si votre site propose un accès chiffré avec une adresse https://..., (c'est bien ! 😉), la configuration de relayd peut-être déroutante.
Ci-dessous, voici un exemple de configuration de relayd correspondante. Notez les mentions de tls :
http protocol "https" { match request header remove "Proxy" match response header set "X-Xss-Protection" value "1; mode=block" return error pass tls keypair chezmoi.tld tls keypair ici.tld } relay "tlsforward" { listen on 192.0.2.2 port 443 tls protocol "https" forward with tls to 127.0.0.1 port 443 }
Prêtez attention aux lignes commençant par "tls keypair". Elles permettent de définir les certificats et clés à utiliser pour le chiffrement TLS. Dans l'exemple ci-dessus, on précise deux certificats possibles pour deux domaines différents. Vous pouvez ajouter une ligne pour chaque domaine géré par votre serveur.
Toutefois, il est indispensable que ces certificats soient placés comme on l'a présenté dans la partie sur acme-client. Autrement dit, vos certificats et clés seront les fichiers suivants :
/etc/ssl/private/chezmoi.tld.key /etc/ssl/chezmoi.tld.crt
De plus, le fichier /etc/ssl/chezmoi.tld.crt doit être le certificat "full chain".
Le plus simple sera peut-être de modifier votre configuration pour acme en conséquence. Par exemple, dans acme.conf:
domain chezmoi.tld { domain key "/etc/ssl/private/chezmoi.tld.key" domain certificate "/etc/ssl/chezmoi.tld-cert.crt" domain chain certificate "/etc/ssl/chezmoi.tld-chain.crt" domain full chain certificate "/etc/ssl/chezmoi.tld.crt" sign with letsencrypt }
Inutile de préciser quoi que ce soit en plus dans la configuration de relayd ou httpd, tout fonctionne normalement comme prévu avec l'utilisation de vos certificats 😉
Renouvellement des certificats
Si vous renouvelez vos certificats avec acme-client, pensez à recharger relayd pour qu'il tienne compte des changements. Par exemple :
/usr/sbin/acme-client -v chezmoi.tld && \ /usr/sbin/rcctl reload relayd
IPv6
Si vous voulez proposer un accès IPv4 et IPv6 avec relayd, vous devrez configurer les 2.
Tout d'abord, assurez-vous d'avoir dans le fichier "/etc/hosts":
127.0.0.1 localhost ::1 localhost
Vous avez ainsi l'ipv4 et l'ipv6 correspondant à "localhost", ce qui sera utile ensuite.
Maintenant, créez dans la configuration de relayd 2 entrées :
relay "http" { listen on $ext_ip4 port 80 protocol "http" forward to 127.0.0.1 port 80 } relay "http6" { listen on $ext_ip6 port 80 protocol "http" forward to ::1 port 80 }
La configuration de httpd pourra être plus simple en profitant de "localhost" :
listen on localhost port 80
Gestion des entêtes
Entêtes de sécurité
Vous pouvez ajouter d'autres règles pour améliorer la sécurité de votre site en modifiant les entêtes suivantes. C'est surtout utile si vous héberger de grosses applications web (inutile dans le cas d'un site statique).
match request header remove "Proxy" match response header set "X-Xss-Protection" value "1; mode=block" match response header set "Frame-Options" value "SAMEORIGIN" match response header set "X-Frame-Options" value "SAMEORIGIN" match response header set "X-Robots-Tag" value "index,nofollow" match response header set "X-Permitted-Cross-Domain-Policies" value "none" match response header set "X-Download-Options" value "noopen" match response header set "X-Content-Type-Options" value "nosniff" match response header set "Permissions-Policy" value "interest-cohort=()"
Si vous n'hébergez qu'un seul nom de domaine, vous devriez ajouter ceci :
match response header set "Access-Control-Allow-Origin" value "chezmoi.tld"
En apprendre plus sur le site de mozilla
Optimisation du cache et de la bande passante
Que vous ayez une bande passante performante ou non, je vous conseille vivement d'optimiser le nombre de requêtes qu'un visiteur réalisera lorsqu'il visitera votre site. Pour cela, vous pouvez indiquer à son navigateur de garder les ressources (images, feuilles de style...) en cache pendant un temps assez long (21 jours dans l'exemple : 21 jours = 1814400 secondes).
Voici les éléments à ajouter dans la section "protocol" juste avant le mot clé "pass" :
match request path "/*.css" tag "CACHE" match request path "/*.js" tag "CACHE" match request path "/*.atom" tag "CACHE" match request path "/*.rss" tag "CACHE" match request path "/*.xml" tag "CACHE" match request path "/*.jpg" tag "CACHE" match request path "/*.png" tag "CACHE" match request path "/*.svg" tag "CACHE" match request path "/*.gif" tag "CACHE" match request path "/*.ico" tag "CACHE" match response tagged "CACHE" header set "Cache-Control" value "max-age=1814400"
L'idée est très simple, à chaque fois qu'un visiteur demande un fichier se terminant par l'une des extensions ".css, .js, .atom, ... , .ico", on colle sur la requête une étiquette "CACHE". À la fin, lorsque relayd détecte une requête avec cette étiquette, il ajoute un entête "Cache-Control" avec une valeur assez grande pour que le navigateur ne tente pas de télécharger à nouveau ce fichier de sitôt.
Définir l'encodage par défaut
Pour être sûr qu'un texte avec accents s'affiche bien, on peut préciser l'encodage. Pour tous les fichiers html et les URL se terminant avec "/", on applique l'étiquette "UTF8" puis on ajoute un entête:
match request path "/*.html" tag "UTF8" match request path "*/" tag "UTF8" match response tagged "UTF8" header set "Content-Type" value "text/html;charset=UTF-8"
Note à propos des étiquette
Vous ne pouvez pas appliquer plusieurs étiquettes à la fois. Si vous voulez ajouter plusieurs entêtes, alors vous devrez le faire au fur et à mesure. Par exemple, si je veux augmenter le cache pour une page html et préciser l'encodage, alors j'applique d'abord le tag "CACHE", définit l'entête "Cache-Control", puis plus loin applique le tag "UTF8" et définit le "Content-Type" :
match request path "/*.html" tag "CACHE" match response tagged "CACHE" header set "Cache-Control" value "max-age=1814400" match request path "/*.html" tag "UTF8" match response tagged "UTF8" header set "Content-Type" value "text/html;charset=UTF-8"