Try   HackMD

Configurer un serveur NGINX

Déployer une application Javascript avec un reverse-proxy

© Julien Noyer - All rights reserved for educational purposes only


Introduction

NGINX est un logiciel libre de gestion de serveur Web ainsi qu'un proxy inverse écrit par Igor Sysoev, dont le développement a débuté en 2002 pour les besoins d'un site russe à très fort trafic. NGINX est un système asynchrone par opposition aux serveurs synchrones où chaque requête est traitée par un processus dédié.

Au lieu d'exploiter une architecture parallèle et un multiplexage temporel des tâches par le système d'exploitation, NGINX utilise les changements d'état pour gérer plusieurs connexions en même temps ; le traitement de chaque requête est découpé en de nombreuses mini-tâches et permet ainsi de réaliser un multiplexage efficace entre les connexions.

Afin de tirer parti des ordinateurs multiprocesseurs, plusieurs processus peuvent être démarrés. Ce choix d'architecture se traduit par des performances très élevées, mais également par une charge et une consommation de mémoire particulièrement faibles comparativement aux serveurs HTTP classiques, tels qu'Apache.

Source Wikipedia, en savoir plus

Solution d'hébergement

Les explications qui vont suivre sont basé sur l'utilisation des services Digital Ocean car ils présentent certaines options avantageuses au niveau de la gestion, comme la gestion de la montée en charge - la fameuse "scalabilité" - ou le fait de pouvoir sélectionner des serveurs européens qui permettent la mise en conformité avec la législation RGPD.

En revanche, il n'est pas obligatoire de choisir ce service pour suivre les explications de ce document, car elles définissent une mise en place classique qui est répercutable sur n'importe quel hébergeur.


Configuration du Droplet (VPS) Digital Ocean

Build Faster, Scale Easier. DigitalOcean's Optimized Droplets Saves Your Team Time

Sélection de l'offre Digital Ocean

L'outil proposé par Digital Ocean s'appelle un Droplet, il faut se rendre dans la section Create > Droplet du site qui permet de les configurer et de suivre les étapes. Pour ce tutorel la configuration suivante est utilsée :

  • Distribution : Ubuntu 18.04.3 (LTS)x64
  • Plan : 5 dollars/mo Standrad
  • Datacenter : Amsterdam
  • Authentication : One time passord

Il est possible d'associer une clef SSH à votre VPS, nous conseillons de ne pas le faire pour pouvoir l'ajouter en ligne de commande pendant la configuration du serveur.

Une fois les étapes de configurations passées, un mail est envoyé par Digital Ocean contenant les informations pour se connecter au Droplet créé. Nous allons à présent utiliser ces identifiants pour nous connecter et configurer le Droplet.

Première connexion au Droplet (VPS)

Comme dit précédemment peu importe l'hébergeur selectionner, les différentes commandes que nous allons utiliser sont applicables sur n'importe quel serveur Linux.

La connexion au serveur est faite en Secure Shell (SSH) via un invite de commande avec la commande suivante :

ssh root@ip.du.droplet

Un message s'affiche alors dans le terminal vous demandant d'accepter la connexion au serveur :

The authenticity of host 'ip.du.droplet (ip.du.droplet)' can't be established.
ECDSA key fingerprint is SHA256:ucLbhJljBojqwF2c/py/GABOdltQo7c6N53B+VFL3ZU.
Are you sure you want to continue connecting (yes/no)?

Il faut accepter la connexion pour ensuite indiquer le mot de passe reçu par mail :

Warning: Permanently added 'ip.du.droplet' (ECDSA) to the list of known hosts.
root@ip.du.droplet's password:

À la première connexion sur le serveur avec l'identifiant root, il est demandé de changer le mot de passe. C'est une première étape de sécurité qui impose de ne pas garder le mot de passée généré par Digital Ocean.

Changing password for root.
(current) UNIX password:
Enter new UNIX password:
Retype new UNIX password:

Les mots de passe ne s'affichent pas, il faut veiller à bien les renseigner.

Une fois la connexion établie sur le serveur il faut avant toute chose s'assurer qu'il est à jour en tapant les commandes suivantes :

sudo apt-get install software-properties-common
sudo apt-get update
apt-get upgrade
apt-get install

Création du compte "admin"

Il va de soi que l'utilisation d'un compte nommé root est une faille de sécurité dans la mesure où il sera le premier à être testé dans le cadre d'une attaque. C'est pourquoi la première étape qu'il faut suivre dans la configuration d'un serveur distant et l'ajout d'un compte sudo et la suppression du compte root.

Pour créer un nouvel utilisateur, il faut taper les commandes suivantes :

adduser mainAdmin
usermod -aG sudo mainAdmin
su - mainAdmin

C'est 3 commandes permettent de créer un profil, de l'ajouter au groupe sudo et de changer de profil utilisateur.

La dernière commande permettant de se changer de profil, il est à présent possible d'associer une clef SSH au nouveau profil pour sécuriser la connexion au serveur avec cette utilisateur. Dans un premier temps il faut créer un dossier et un fichier pour enregister la clef sur le serveur :

mkdir ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys

La commande chmod permet de changer les droits en lectur/écriture sur un fichier ou un dossier.

La dernière commande ouvre l'éditeur Nano dans lequel nous allons coller la clef SSH de notre compte. Dans un autre invite de commande nous allons tous d'abord créer une nouvelle clef si aucune n'est présente sur la machine :

ssh-keygen -t rsa

Surr Mac pout vérifier si une clef est présente sur une machine il faut téperr la commande cat ~/.ssh/id_rsa.pub.

Un message s'affiche demandant d'indiquer le chemin vers la clef .../.ssh/id_rsa, attention car si une clef existe déjà elle sera remplacée.

L'ajout d'une passphrase est recommandé pour sécuriser la clef.

Nous pouvons maintenant copier la clef que nous venons de créer avec la commande suivante :

pbcopy < ~/.ssh/id_rsa.pub

Une fois la clef copiée il suffi de la coller dans la fenêtre Nano ouverte précédemment pour l'associer au profil mainAdmin créé sur le serveur. Nous enregistrons le fichier puis nous modifions les permissions sur le dossier .ssh avec la commande suivante :

chmod 600  ~/.ssh/authorized_keys

NB : les commandes présentées pour gérer les clefs SSH correspondent à l'OS Machintosh, si elles ne fonctionnent pas pour Windows il est possbile d'utiliser Putty.

Vérification du profil mainAdmin

Une fois l'utilisateur mainAdmin créé, il est primordial de s'assurer que la connexion SSH soit correctement configurer avant de passer aux étapes suivantes. Tout en conservant la connexion avec le profil root actif, nous ouvrons une nouvelle fenêtre d'invite de commande pour nous connecter à présent avec le profil mainAdmin :

ssh mainAdmin@ip.du.droplet

Lorsque la connexion est établie nous sommes à présent connecté au serveur avec le profil mainAdmin, nous testons à présent que nous sommes bien dans le groupe sudo avec la commande suivante :

sudo ls

Le mot de passe nous est demandé et une fois renseigné aucun message d'erreur ne n'affiche, la configuration est correct nous poouvons donc passer à l'étape suivante.

NB : S'il y à un problème à l'une des étapes de vérification, il faut revoir soit vérifier la clef ssh soit le chmod du fichier authorized_keys.

Gestion du profil root

Nous allons à présent bloquer la possibilité de s'identifier avec l'utilisateur root et nous allons imposer la connexion via clef SSH. Le fichier de configuration sshd_config nous permet de gérer les méthode de connexion :

sudo nano /etc/ssh/sshd_config

Dans ce fichier il faut changer les valeur de PermitRootLogin et PasswordAuthentication puis sauvegarder le fichier :

PermitRootLogin no
PasswordAuthentication no

Une fois la configuration modifier il faut redémarrer le service SSH :

sudo service ssh restart

Il est à présent nécessaire de vérifier la configguration, il faut d'abord nous deconnecter pour ensuite relancer la connexion SSH avec le nouveau compte :

ssh mainAdmin@ip.du.droplet

NB : il ne faut surtout pas se déconnecter du profil root avant d'avoir vérifié la connexion ssh du profil mainAdmin au risque de ne plus pouvoir se reconnecter au serveur.


Configuration du VPS pour NGINX

Une fois la problématique de connexion sur le VPS passsée, nous pouvons à présent nous occuper d'installer les modules pour déployer notre site Internet ou notre application Web. Les dernières versions des Droplets Digital Ocean intégrent la commande Git, si ce n'est pas le cas, il faut l'installer aveec la commande :

sudo apt-get install git-all

Cette commande vous permet également de mettre tous les outils Git à jour.

Installation et activation de NGINX

Avant d'installer NGINX nous devons nous assurer qu'aucune autre technologie serveur n'est installée sur le VPS, en l'occurence nous allons supprimer toute la configuration Apach2 en tapant les commmandes suivante :

sudo service apache2 stop sudo update-rc.d apache2 disable sudo apt-get purge apache2

Afin d'utliser NGINX sur notre VPS, nous allons l'installer en tapant la commande suivante afin de configurer un reverse-proxy qui nous permettra de gérer les URLS de notre VPS :

sudo apt-get install nginx

Nous pouvons à présent activer NGINX et définir son comportement par defaut pour indiquer que nous redirigeons toutes les requêtes HTTP en HTTPS que nous configurerons plus tard avec LetsEncrypt.

Pour commencer nous ajoutons dans le fichierdefault la configuration de NGINX en l'ouvrant dans Nano :

sudo nano /etc/nginx/sites-enabled/default

Une fois Nano ouvert, nous remplaçons le code affiché par le suivant avant de fermer et d'enregistrer le fichier :

# HTTP — redirect all traffic to HTTPS
server {
    listen 80;
    listen [::]:80 default_server ipv6only=on;
    return 301 https://$host$request_uri;
}

Cryptage des requêtes HTTPS

Nous allons à présent crypter les requêtes grâce à la commande dhparam afin de gérer les reqêtes HTTPS :

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Nous devons maintenant créer un fichier de configuration SSL, afin de rendre les requêtes HTTPS valident. Pour cela nous crééons un fichier ssl-params.conf :

sudo nano /etc/nginx/snippets/ssl-params.conf

Et nous ajoutons le code suivant avant d'enregister le fichier :

# See https://cipherli.st/ for details on this configuration
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

# Add our strong Diffie-Hellman group
ssl_dhparam /etc/ssl/certs/dhparam.pem;

Pour finir la configuration de NGINX nous devons autoriser certains type de connexion avec les commandes suivantes :

sudo ufw allow OpenSSH
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

Valider la configuration NGINX

Nous pouvons à présent démarrer le service NGINX pour finir notre configuration, dans un premier temps nous devons redémarrer notre VPS :

sudo reboot

Il faut ensuite nous reconnecter pour lancer le service NGINX :

sudo systemctl start nginx

La commande sudo systemctl status nginx.service permet de verifier le status de NGINX


Publier un site ou une application statique

La configuration serveur que nous venons de réaliser permet d'héberger des fichiers statiques et de les rendre accessible via des URLs. Le projet que nous souhaitons publier n'est pas connecté à une base de données ni à un serveur NodeJS qui nous imposerait une configuration supplémentaire qui est définie plus bas dans ce document.

Nous considérons donc que vous disposez à cette étape d'un projet qui correspond à la définition ci-dessus, avant de continuer la lecture des étapes suivantes.

Gestion des certificats SSL

Les certificats SSL nous permettent de configurer l'accés HTTPS à nos noms de domaines. Avant de commencer cette configuration sur le VPS nous avons dans un premier temps acheté un nom dee domaine que nous avons fait pointé sur l'adresse IP de notre Droplet.

Une fois le nom de domaine correctement configuré, nous devons dans un premier installer Certbot pour générer les clef SSL :

sudo apt-get install certbot
sudo apt-get install python3-certbot-nginx

Puis nous lancons la commande qui permet de configurer une nouvelle URL en HTTPS :

sudo certbot certonly --standalone -d <nom.de.domaine>

Nous pouvons renouveler les certificats à la main de cette façon sudo certbot renew --nginx.

Nous suivons les instruction de LetsEncrypt pour nous identifier et une fois le nom de domaine enregistré un message de validation affiche l'endroit ou sont stockées les clef SSL :

Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/<nom.de.domaine>/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/<nom.de.domaine>/privkey.pem

Les clef que nous venons de créer vont nous permettre à présent d'ajouter un fichier de configuration dans NGINX afin d'associer correctement les cleefs SSL à notre nom de domaine. Nous ouvons donc un nouuveau fichier dans Nano :

sudo nano /etc/nginx/sites-enabled/<nom.de.domaine>

Il est recommander de nommer le fichier par le nom de domaine.

Dans le fichier qui vient de s'ouvir nous collons le code suivant pour gérer les clef SSL pour ce nom de domaine :

# HTTPS proxy all requests to the Node app
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name <nom.de.domaine>;

    # Use the LetsEncrypt certificates
    ssl_certificate /etc/letsencrypt/live/<nom.de.domaine>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<nom.de.domaine>/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;
    
    # Path to your static files
    root /home/mainAdmin/project/project_name;
}

Nous prenons soins de bien modifier les informations pour qu'elles correspondent à notre configuration :

  • nom.de.domaine : le domaine que nous avons fait poointer sur le serveur

Pour vérifier notre configuration NGINX nous tapons la commande sudo nginx -t qui noous affiche en résultat :

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Notre configuration est à présent terminé, nous pouvons pour la finaliser et activer le nom de domaine sur notre VPS, redemmarer le service NGINX avec la commande suivante :

sudo systemctl start nginx.service

Renouveler le certificat automatiquement avec CertBot

Le certificat SSL que nous avons généré n'est valable que pour 90 jours, c'est à dire qu'il à besoin d'être renouveler avant la fin de cette prériode pour que notre nom de domaine conserve sa certification. Pour ne pas avoir à renouveler le certificat manuellement nous allons mettre en place un CRON sur le serveur pour qu'il se renouvel automatiquement.

Pour gérer automatiquement la mise à jour des certificats, nous allons créer une tâche en CRON en tapant la commande suivante pour ouvrir le fichier crontab :

sudo crontab -e

Il est demandé à cette étape de sélectionner un éditeur.

Puis nous ajoutons à la fin du fichier le code suivant :

# Certbot auto-renew
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

0 0 1 * * mainAdmin certbot -q renew --nginx

Le code de renouvellement est exécuter le 1er de chaque mois.

Nous fermons et enregistrons le fichier crontab puis nous tapons la commande suivante pour testeer notre configuration :

sudo openssl x509 -noout -dates -in /etc/letsencrypt/live/<nom.de.domaine>/cert.pem

Cette commande affiche la date du futur renouvellmement et nous pouvons a présent pour nous assurer que Nginx continue de fonctionner correctement en reedémarrant le service :

sudo systemctl restart nginx.service

Déployer des fichiers statiques vers le VPS

La méthode la plus évidente pour déployer des fichiers d'une machine locale à un serveur distant, dans notre cas le VPS, est celle induite par la technologie serveur utilisée. Dans le cadre de notre VPS, nous avons configurer notre connexion via des cléfs SSH qui nous permet de sécuriser les échangent avec le serveur, nous allons donc utiliser le même principe pour déployer nos fichier.

Déploiement via une répertoire Git

Si vous avez veillez à avoir un répertoire GitLab ou GitHub dans lequel se trouvent les fichiers que vous souhaitez déployer sur le VPS, il est possible de l'utiliser pour pourvoir directement faire un pull de la banche souhaitée depuis le VPS.

Il faut dans un premier temps créer le dossier dans lequel vous souhaitez déployer les fichiers sur le VPS, a l'adresse que nous avons défini dans le fichier de configuration du nom de domaine :

sudo mkdir /home/mainAdmin/project/project_name

Nous nous plaçons ensuite dans le dossier pour y configurer la gestion de Git :

cd /home/mainAdmin/project/project_name
sudo git init
sudo git remote add origin <URL_DU_REPO>

Une fois cette configuration terminée notre VPS est connecté à un répertoire Git distant, la mise à jour ce fait alors simplement avec la commande suite :

sudo git pull origin master

Déploiement via un script sur la machine locale

Si vous avez utiliser un fichier package.json pour la configuration de votre projet (dans le cadre d'un développement avec un framework par exemple), vous pouvez y ajouter un script de déploiement afin de le faire directement en invite de commande.

Pour ce faire vous devez éditer le fichier package.json au niveau du tableau des scripts pour y ajouter le suivant :

"deploy": "scp -r ./path-to-project/ mainAdmin@<IP_DU_VPS>:/home/mainAdmin/project/project_name"

Pensez à éditer ./path-to-project/ et <IP_DU_VPS> avant d'enregistrer le fichier.

Le déploiement ce fait alors simplememnt avec la commande suivante :

npm run deploy

Avant de déployer une nouvelle version vous devez d'abord supprimer le dossier project_name du VPS.


Publier une application NodeJS

Nous allons aborder à présent la publication d'une application NodeJS sur notre VPS. Les principes sont différents de la publication d'un projet statique dans le mesure ou nous devons configurer la gestion d'un systeme d'information. En effet, un projet NodeJS s'oriente très souvent dans la mise en place d'une API connectée à une base de données NoSQL, c'est pourquoi les étapes qui vont suivre vous présente ces principes de bases que vous pourrez adapter à votre projet et que nous allons partir du principe que le système d'information choisi est MongoDB.

Installation des modules serveurs

Pour commencer nous allons installer les modules nous permettant d'utiliser un environement - Javascrip sur notre serveur, à savoir NodeJS avec les commandes suivantes :

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install nodejs

Activation du service MongoDB

Nous allons à présent installer MongoDB qui nous permettra de gérer les données de notre application NodeJS :

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927
echo "deb http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
sudo apt-get install -y mongodb

Pour configurer MongoDB en tant que service nous allons créer un fichier qui nous permettra de le configurer :

sudo nano /etc/systemd/system/mongodb.service

Nous allons coller le code suivant avant d'enrigistrer le fichier :

[Unit]
Description=High-performance, schema-free document-oriented database
After=network.target

[Service]
User=mongodb
ExecStart=/usr/bin/mongod --quiet --config /etc/mongod.conf

[Install]
WantedBy=multi-user.target

Nous pouvons à présent lancer le service MongoDB avec la commande suivante :

sudo systemctl start mongodb

Pour vérifier le statut du service il faut taper la commande sudo systemctl status mongodb.

Déployer l'application NodeJS sur le VPS

Les méthodes de déploiement vers le VPS sont les mêmes que celles évoquées au point Déploiement via une répertoire Git, bien que vous êtes libre de créer un script de déploiement. Nous préférons utiliser cette méthode car elle nous permet de concerver la logique de Git sur le VPS, ce qui peut s'avérer utile pour réaliser des modifications directement sur le VPS.

Nous partons donc du principe que votre application NodeJS est présente dans le VPS dans le dossier que vous aurez défini pour l'héberger.

Il est fortement déconseillé de placer l'application NodeJS dans le dossier home.

La différence majeur pour publier une application NodeJS se trouve dans la gestion du nom de domaine, car contrairement à un projet statique, une application NodeJS fonctionne sur le principe d'un serveur, c'est pourquoi la configuration du nom de domaine doit intégrer la gestion d'un port.

Pour ajouter un nom de domaine la commande CertBot reste la même :

sudo certbot --nginx -d <nom.de.domaine>

Mais pour configurer le nom de domaine, au lieu de configurer le dossier root il faut configurer la location de la manière suivante :

# HTTPS proxy all requests to the Node app
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name <nom.de.domaine>;

    # Use the LetsEncrypt certificates
    ssl_certificate /etc/letsencrypt/live/<nom.de.domaine>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<nom.de.domaine>/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:<port>/;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
    }
}

Nous prenons soins de bien modifier les informations pour qu'elles correspondent à notre configuration :

  • nom.de.domaine : le domaine que nous avons fait poointer sur le serveur
  • port : le port qui corrrespond à notre application

Pour vérifier notre configuration NGINX nous tapons la commande sudo nginx -t qui noous affiche en résultat :

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Activation du service PM2

Le module PM2 permet d'écouter l'activité du VPS pour capter le moment ou il est relancé, ce qui arrive très souvent pour des raisons de maintenance par exemple. Nous allons donc utiliser npm que nous avons intallé plus haut pour installer ce module en global sur le VPS :

sudo npm i -g pm2
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Nous allons à présent configurer PM2 pour qu’il puisse redémarrer automatiquement nos application NodeJS en cas de redémarage du VPS :

pm2 startup systemd

Cette dernière commande permet d’afficher un code à taper pour valider la configuration qui ressemble au code suivant :

sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u dws --hp /home/adminuser

Tout est prêt sur notre VPS pour configurer un nom de domaine en HTTPS qui pointee sur un port spécifique. Nous allons donc à présent utiliser PM2 pour lancer notre application NodeJS en tapant la commande suivante dans le dossier racine de notre application :

pm2 start server.js --name APPname

Ressources

La liste ci-dessous contient les liens utiles cité dans ce document