NGINX mode reverse-proxy avec Let's Encrypt 🔒

NGINX mode reverse-proxy avec Let's Encrypt 🔒

NGINX est un serveur web open-source très performant, également utilisé comme serveur proxy inverse, équilibrage de charge, et serveur de cache. Conçu pour gérer de manière efficace un grand nombre de connexions simultanées, NGINX est réputé pour sa faible consommation de ressources et sa rapidité, ce qui en fait un choix populaire pour améliorer les performances des sites web.

Let's Encrypt est une autorité de certification qui offre des certificats SSL/TLS gratuits et automatisés, permettant aux sites web de sécuriser leurs connexions HTTPS de manière accessible. Les certificats ont une durée de validité de 90 jours, et l'organisation encourage l'automatisation du processus de renouvellement.


J'utilise principalement NGINX en tant que reverse proxy lorsque je dois rendre accessible un container Docker hébergeant une application WEB que je ne souhaite pas mettre en HA (Haute-disponibilité). Dans le cas contraire, je m'orienterai plutôt vers un reverse-proxy/loadbalancer du type Traefik (je vous ferrai un article dessus 😉)

Commençons !

Lancement d'un service Docker

Dans le cadre de cette article, je vais choisir un service Web simple dans un container Docker qui sera PrivateBin. Une image officielle docker est disponible sur Docker Hub.

Prérequis : Un serveur avec Docker d'installé (cf: la doc📝)

Il suffit de lancer la commande suivant pour avoir le service Up !

gael@lab-reverse-nginx:~# sudo mkdir -p /opt/privatebin/privatebin-data
gael@lab-reverse-nginx:~# sudo docker run -d --restart="always" --read-only -p 127.0.0.1:8080:8080 -v /opt/privatebin/privatebin-data:/srv/data privatebin/nginx-fpm-alpine
  • -d : Mode démon (processus en arrière plan).
  • --restart="alway" : Redémarre le container à chaque redémarrage de la machine automatiquement.
  • --read-only : Monte le FS du container en read-only, on ne peut pas écrire dans le container sauf dans le volume monté.
  • -p 127.0.0.1:8080:8080 : On fait écouter le port 8080 de notre container sur l'interface localhost, port 8080 de notre machine.
  • -v /opt/privatebin/privatebin-data:/srv/data : Notre dossier pour rendre persistant les données créé dans privatebin

Maintenant nous avons bien notre container Up et qui réponds aux appels local

gael@lab-reverse-nginx:~# sudo docker ps
CONTAINER ID   IMAGE                         COMMAND                  CREATED         STATUS        PORTS                      NAMES
693d0bc24fa2   privatebin/nginx-fpm-alpine   "/etc/init.d/rc.local"   2 seconds ago   Up 1 second   127.0.0.1:8080->8080/tcp   inspiring_easley

# Vous pouver tester depuis votre serveur avec la commande curl
gael@lab-reverse-nginx:~# curl localhost:8080

Maintenant que notre service est Up, on veut le rendre sécurisé

Installation & configuration de NGINX

NGINX est initialement un service permettant d'héberger un site Web tout comme Apache. Les fonctions loadbalacing & reverse-proxy l'on rendu plus polyvalent.

Prérequis: Avoir un nom de domaine qui pointe vers votre serveur. (J'utiliserai privatebin.inframinds.fr)

gael@lab-reverse-nginx:~# sudo apt update && sudo apt install nginx

On va faire un peu de nettoyage sur la configuration par défaut.

# On supprime le site default .. 
gael@lab-reverse-nginx:~# sudo rm /etc/nginx/sites-available/default
gael@lab-reverse-nginx:~# sudo rm /etc/nginx/sites-enabled/default

# On met le token Nginx en prod pour éviter d'afficher notre version à tout le monde
gael@lab-reverse-nginx:~# sudo /etc/nginx/nginx.conf
# il faut décommenter la ligne suivante
server_tokens off 

On va créer notre propre vHost (fichier de configuration nginx)

# J'ai l'habitude de créer un fichier par vhost 
gael@lab-reverse-nginx:~# sudo vim /etc/nginx/sites-available/privatebin.inframinds.fr

server {
  listen 80;
  # Nom de domaine que vous allez utiliser
  server_name privatebin.inframinds.fr;

  location / {
    # proxy_set_header permettent d'envoyer des informations sur la requete initial au serveur back (ici notre docker)
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    # C'est l'élément le plus important car il indique ou ce situe le serveur sur lequel nous devons transférer la requête.
    proxy_pass http://127.0.0.1:8080/;
  }
}

Il ne reste plus qu'à activer le site et vérifier que cela fonctionne.

# On active notre site en créant un lien symbolique dans le dossier sites-enabled
gael@lab-reverse-nginx:~# sudo ln -s /etc/nginx/sites-available/privatebin.inframinds.fr /etc/nginx/sites-enabled/

# Test de la syntax de la configuration
gael@lab-reverse-nginx:~# sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

# Chargement de la nouvelle configuration
gael@lab-reverse-nginx:~# sudo systemctl reload nginx

A ce niveau, nous avons un service Nginx qui fait reverse proxy, qui est accessible publiquement mais uniquement de manière non sécurisée 🔓 (HTTP) sur votre domaine http://privatebin.votredomain.fr

Nous avons un jolie message nous informant que l'on doit passer en HTTPS 🔒 pour que ça fonctionne bien 😅

Heureusement, Let's encrypt est la, et cela ne nous coutera rien de plus de sécuriser notre site 💃

Let's Encrypt

L'intégration de let's Encrypt a largement était facilité dans les nouvelles version linux. L'utilitaire le plus connue pour gérer ces certificats est "Certbot". C'est un script qui permet la génération de certificat mais qui peut également gérer le renouvellement de manière automatique de ceux-ci.

# On install certbot & le module certbot pour nginx
gael@lab-reverse-nginx:~# sudo apt install certbot python3-certbot-nginx

# On lance la commande suivante en répondant aux questions du prompt .. 
gael@lab-reverse-nginx:~# sudo certbot --nginx -d privatebin.inframinds.fr

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): votremail@gmail.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N
Account registered.
Requesting a certificate for privatebin.inframinds.fr

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/privatebin.inframinds.fr/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/privatebin.inframinds.fr/privkey.pem
This certificate expires on 2024-03-21.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for privatebin.inframinds.fr to /etc/nginx/sites-enabled/privatebin.inframinds.fr
Congratulations! You have successfully enabled HTTPS on https://privatebin.inframinds.fr

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Et voila 🎉, si vous regardez de nouveau votre fichier de configuration de votre vHost Nginx, vous verrez que celui-ci a été modifier par Certbot afin d'utiliser du HTTPS 🔒 et de rediriger le traffic du port 80 vers le 443 (HTTPS).

Certbot a également installé un service sur votre serveur (un cron) qui va vérifier plusieurs fois par jours que votre certificat ne va pas expiré. Si c'est le cas, alors il va automatiquement le renouvelé 💪

# Voici le service pour info :)
gael@lab-reverse-nginx:~# sudo systemctl status certbot.timer

Vous avez maintenant accès à votre application en HTTPS sur https://privatebin.votredomain.fr

Un peu plus de sécurité

Si comme moi vous aimez les notes 💯, il y a un site qui permet de voir le niveau de sécurité de votre configuration HTTPS: https://www.ssllabs.com/ssltest/index.html

Dans l'état actuel, sans rien changer, vous devriez avoir un note de A ce qui est déjà très bien. Mais on peut faire mieux et très simplement.

Pour cela, il suffit d'ajouter la ligne d'activation du HSTS dans votre vHost /etc/nginx/sites-available/privatebin.inframinds.fr juste avant les configurations Certbot.

    ...
    # Activation du HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    listen 443 ssl; # managed by Certbot
    ...

HSTS est une politique de sécurité web qui force les navigateurs à communiquer uniquement avec un site web via une connexion chiffrée (HTTPS). Cela réduit le risque d'attaques de type man-in-the-middle et améliore la sécurité en assurant que les communications avec le site sont toujours cryptées.

Puis relancer Nginx et faire un test sur SSLLabs.

gael@lab-reverse-nginx:~# sudo systemctl reload nginx

On a enfin la meilleur note possible 💪

Et une architecture telle que si dessous

0:00
/0:03