Let’s Encrypt et nginx

Client

Client utilisé : acme.sh (dépôt Gihub).

Configuration http nginx

Pour utiliser le challenge http, on prépare la configuration de nginx. Même si on gère plusieurs sites (virtuels par exemple), on va utiliser le même répertoire /var/http/lets_encrypt pour réaliser le challenge. Ce répertoire doit être accessible au user qui va utiliser le script acme.sh.

On va également configurer nginx pour supprimer le www initial éventuel et pour rediriger http vers https. Par exemple http://www.chataignon.com va renvoyer vers https://chataignon.com.

Dans un premier temps, pour réaliser le challenge initial, seul http (pas de config ssl car on a pas de certificats) est utilisé avec la configuration suivante

server {
    listen 80;
    server_name  www.chataignon.com chataignon.com;
    location /.well-known {
        root /var/http/lets_encrypt;
    }
    location / {
        return 301 https://chataignon.com$request_uri;
    }
}

Initialisation

La configuration ci-dessus suffit pour créer un certificat pour les domaines chataignon.com et www.chataignon.com en utilisant la commande suivante

acme.sh --issue -d chataignon.com -d www.chataignon.com -w /var/http/lets_encrypt
  • Note 1 : lors des phases de test, utiliser l’option --test pour éviter de tomber sur les limites assez basses du nombre de certificats pouvant être générés.
  • Note 2 : pour passer outre le non-remplacement d’un certificat récent, ajouter --force. Cela peut être le cas quand, après avoir créer des certificats de test, on veut créer le vrai certificat. Il faut alors forcer le remplacement du certificat de test.

Certificats

Par défaut, les certificats sous créés dans ~/.acme.sh. On peut modifier l’emplacement avec l’option --certhome.

Pour copier les certificats vers leur emplacement définitif, on peut utiliser le script suivant

#!/bin/sh
domain=$1

acme.sh \
    --installcert -d $domain \
    --keypath /etc/ssl/private/$domain-key.pem \
    --capath  /etc/ssl/private/$domain-ca.pem \
    --fullchainpath /etc/ssl/private/$domain.pem

On lance le script avec

./install chataignon.com

Les certificats sont stockés sous /etc/ssl/private/.

Configuration ssl nginx

Maintenant que les certificats sont créés, on peut écrire la config ssl de nginx

server {
    listen 443;
    server_name  chataignon.com;
    add_header Strict-Transport-Security "max-age=2592000";

    ssl_certificate     /etc/ssl/private/chataignon.com.pem;
    ssl_certificate_key /etc/ssl/private/chataignon.com-key.pem;

    location / {
        root   /var/http/<vraie racine du site>;
        index  index.html;
    }
}

L’avantage de cette configuration est que le challenge http n’est pas réalisé dans l’arborescence du site. Cela facilite la gestion des droits d’accès puisqu’il faut accorder des droits en écriture pour le challenge.

Redirection

Il reste à faire la redirection de https://www.chataignon.com vers https://chataignon.com. Note : la redirection pour http est déjà faite avec le return 301 de la configuration http nginx.

server {
    listen 443 ssl;
    server_name www.chataignon.com;
    ssl_certificate     /etc/ssl/private/chataignon.com.pem;
    ssl_certificate_key /etc/ssl/private/chataignon.com-key.pem;
    return 301 https://chataignon.com$request_uri;
}

Pour que cette redirection fonctionne, il est important que le domaine www.chataignon.com soit présent dans le certificat.

Recharger le service nginx

Ne pas oublier:

$ service nginx reload

C’est terminé pour la configuration initiale. Comme le certificat est valide pendant 3 mois, il faut penser au renouvellement et à son automatisation via cron.

Renouveler le certificat

acme.sh --renew -d chataignon.com -w /var/http/lets_encrypt

Le premier nom de domaine suffit pour renouveler tous les domaines associés. Le challenge http va avoir lieu pour chaque domaine.

Script pour cron

On peut créer une tâche cron quotidienne pour tenter de renouveler le domaine, puis copier les certificats et relancer le serveur nginx si le code de retour est nul.

#!/bin/sh
domain=$1
acme.sh \
    --renew \
    -d $domain \
    -w /var/http/lets_encrypt

if [ $? -eq 0 ] ; then
    acme.sh \
        --installcert \
        -d $domain \
        --keypath /etc/ssl/private/$domain-key.pem \
        --capath  /etc/ssl/private/$domain-ca.pem \
        --fullchainpath /etc/ssl/private/$domain.pem \
        --reloadcmd "service nginx reload"
fi