Site Web sur Raspberry Pi, partie 5 : HTTPS

Les certificats

Sur la route du tant convoité HTTPS, nous allons maintenant nous faire certifier.
Je vais là encore suivre des tutoriels, mais sachez qu’il existe des certificats autosignés et des certificats signés par une autorité reconnue.
Il va sans dire que les premiers sont beaucoup moins considérés comme valides, là où les deuxièmes sont le standard de fait (quelle est la valeur de la certification si tout le monde peut la faire, s’pas?).

Si vous êtes passés par un site payant ou DNSExit pour obtenir votre domaine, sachez que ces sites peuvent vous proposer des certificats tout faits.
Nous, comme on mange des guêpes frites dans l’huile de boîte de vitesses, on va faire ça à l’ancienne avec l’ami Certbot.

Oui, mais attends, tu dis qu’on fait ça nous-mêmes, alors quelle est la valeur de ces certificats?

Très juste, Auguste, mais Certbot obtient des certificats signés auprès d’une autorité reconnue, il n’autosigne pas les certificats, et la différence est cruciale.

Les choses ont bien changé depuis mes premières tentatives de HTTPS, merci donc à cet excellent tuto pour la simplicité de la méthode (de mon temps, il fallait toucher à la config du site dans nginx pour que les challenges nécessaires à la création des certifs fonctionnent…).

Lorsque vous en serez à Modifiez votre virtual host en fonction de votre serveur Nginx ou Apache, revenez ici 🙂

Configuration SSL dans nginx

Nous avons donc notre certificat en poche (ça a fonctionné du premier coup en suivant pas à pas son tuto, dans mon cas), il va donc falloir modifier notre descripteur de site en conséquence.

sudo nano /etc/nginx/sites-available/monsite

Nous allons créer un deuxième bloc server {} qui ne va contenir que la redirection en HTTPS. Pourquoi? Parce que tous les navigateurs, selon leurs réglages, n’interrogent pas d’abord sur le port 443 (SSL, donc sécurisé, donc bien), mais sur le port 80 (celui que nous avons utilisé jusqu’à présent, qui est le port HTTP, et pas HTTPS).
L’idée va donc être d’accepter les communications sur port 80, mais seulement pour les renvoyer vers le port 443, en mode beau gosse. Vous allez voir, ça se fait comme qui rigole. Voici notre descripteur de site avec ses modifs en gras :

server {
    listen 80;
    listen [::]:80;
    server_name domaine.com www.domaine.com;
    # Renvoi vers le port 443
    location / {
        return 301 https://$server_name$request_uri;
    }
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name domaine.com www.domaine.com;
    index index.php index.html;
    root /var/www/html;
    access_log /var/www/logs/access.log;
    error_log  /var/www/logs/error.log;
    # En avant pour SSL :)
    ssl_certificate     /etc/letsencrypt/live/domaine.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domaine.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/domaine.com/chain.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers         ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
    ssl_ecdh_curve      secp384r1;
    ssl_session_cache   shared:SSL:4m;
    ssl_session_timeout 1440m;
    ssl_stapling        on;
    ssl_stapling_verify on;
    resolver        8.8.8.8 8.8.4.4;
    add_header      Strict-Transport-Security max-age=31536000;
    # Hop fini !
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
    set $cache_uri $request_uri;
    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
        set $cache_uri 'null cache';
    }
    if ($query_string != "") {
        set $cache_uri 'null cache';
    }
    # Don't cache uris containing the following segments
    if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-..php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(index)?.xml|[a-z0-9-]+-sitemap([0-9]+)?.xml)") {
        set $cache_uri 'null cache';
    }
    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~ "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
        set $cache_uri 'null cache';
    }
    include /etc/nginx/fcgiwrap.conf;
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ .php$ {
    # FASTCGI CACHE
    set $skip_cache 1;
    if ($cache_uri != "null cache") {
        add_header X-Cache-Debug "$cache_uri $cookie_nocache $arg_nocache$arg_comment $http_pragma $http_authorization";
        set $skip_cache 0;
    }
    fastcgi_cache_bypass $skip_cache;
    fastcgi_cache microcache;
    fastcgi_cache_key $scheme$host$request_uri$request_method;
    fastcgi_cache_valid any 8m;
    fastcgi_cache_use_stale updating;
    fastcgi_cache_bypass $http_pragma;
    fastcgi_cache_use_stale updating error timeout invalid_header http_500;
    # /FASTCGI CACHE
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    # fastcgi_pass 127.0.0.1:9000;
    fastcgi_split_path_info ^(.+.php)(/.+)$;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    fastcgi_read_timeout 300;
    }
}

Au terme de la modification du descripteur, comme d’habitude, procédez à un petit :

sudo service nginx reload

Et s’il n’y a pas de raté, tout devrait se passer comme sur des roulettes! Vous devriez maintenant pouvoir accéder à votre site depuis l’extérieur, avec un nom de domaine (aussi glorieux – ou non – qu’il puisse être) ET le tout avec le petit cadenas du HTTPS! Elle est pas belle, la vie ?

Ceci fait, n’oubliez pas de procéder à l’ouverture du port 443 au même titre que vous l’avez fait pour le port 80 (durant cette partie du tuto)!

Renouvellement et mot de la fin

Les certificats émis par Certbot sont renouvelables une fois par mois pour un domaine.
Attendu que ces certificats ont une validité (90 jours), il faut donc les renouveler.
Fort heureusement, Certbot dispose d’une commande pour ne faire que ça, et comme Linux est un système qu’il est fort bien, il dispose d’un planificateur de tâche qui fait peur de prime abord, mais qui fait le café quand on l’a un peu apprivoisé.
Je ne vais pas me creuser la soupière tout en sachant que le même tuto (celui-ci, partie 4) le traite.

Le planificateur de tâches s’appelle Cron et la commande crontab -e (sans sudo devant!!) permet d’éditer le planificateur pour l’utilisateur courant.
Cependant, comme nous allons utiliser Certbot qui a besoin des autorisation root, nous allons utiliser :

sudo crontab -e

qui édite le planificateur pour root (si vous voulez en savoir plus sur Cron, commencez donc par là).
Si c’est la première fois que vous lancez Cron, il vous sera demandé de choisir un éditeur; personnellement, je préfère nano, mais les hardcore du Nord préfèrent vi (standard mais abscons comme pas deux).
Ajoutez la ligne :

@weekly /usr/bin/certbot renew >> /var/log/certbot-renew.log

Notez ici qu’en bon fainéant, j’utilise @weekly au lieu de la ligne indiquée dans le tuto. La raison à cela est qu’il n’existe de toute façon pas de moyen de planifier Cron pour un nombre de jours spécifique. Toute commande doit être liée au système calendaire grégorien (jour, semaine, mois, année), et toute autre intervalle temporel doit être géré via script (appelé périodiquement via Cron, vous l’aurez compris).
Partant du principe que Certbot ne renouvelle pas s’il n’y a pas besoin et ne permet le renouvellement que lorsque le certificat arrive à 10 jours avant sa date d’expiration, la période @monthly nous expose dans le pire cas à 21 jours de certificat invalide.
La période immédiatement précédente étant @weekly, nous aurons donc 8 tentatives de renouvellement refusées et la 9ème réussira car arrivera dans la période de 10 jours avant l’expiration.
Notez enfin que la partie >> /var/log/certbot-renew.log est purement optionnelle et permet d’avoir le retour des tentatives de renouvellement, sachant que vous aurez en plus des mails de certbot pour vous indiquer que vous arrivez à expiration, normalement, c’est bordé.

Leave a Reply

Your email address will not be published. Required fields are marked *