Technologies Web

Mise en production projet node.js

Présentation

Après un temps d’abscence, me revoici pour vous présenter comment mettre en production votre projet Node.js au sein de votre serveur de production. Personnellement, j’utilise NGinx pour faire le lien avec le serveur http de node.JS.

Sachez que j’utilise un serveur Ubuntu x64 14.04 LTS pour cet article. Il se peut que selon votre distribution, certaines commandes changent.

Prérequis

Avant de commencer, sachez que je n’utilise pas les versions de node.js et de npm fournis par ubuntu car elles ne sont pas mise à jour régulièrement et que la mise à jour de npm par lui même ne marche pas, De même pour NGinx. De plus, pour gérer comme il faut mon projet Node.JS, j’utilise monit et upstart. Voici donc toutes les commandes à rentrer pour être prêt à commencer :

# avant de commencer, mettre à jour Ubuntu
sudo apt-get update && sudo apt-get upgrade
# installation de paquets nécessaires disponibles dans ubuntu
sudo apt-get install imagemagick libicu-dev libgd2-xpm-dev python-software-properties software-properties-common build-essential upstart monit
# installation de nginx et de node.js
sudo add-apt-repository ppa:nginx/stable
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nginx nodejs
Attention : Avec cette installation de Node.JS nous nous retrouvons en 0.10.X. De plus, la commande de base n’est pas node mais nodejs

Utilisateur webuser

De base, l’utilisateur exécutant la partie web chez moi ne doit pas avoir les accès sudo. Je créée donc un nouvel utilisateur avec pour nom webuser :

sudo useradd -d /home/webuser -m webuser
sudo passwd webuser
su webuser
# on est chez webuser
cd
mkdir public_html
exit

NGinx

Maintenant voici le fichier NGinx à créer pour pouvoir faire le lien entre le port 80 (ou 443 si vous passez via https) et votre processus node (les 3/4 du temps sur le port 3000). Le fichier sera à placer dans /etc/nginx/sites-available/

upstream app_nodenomunique {
        server 127.0.0.1:3000;
}

server {
    listen 443 ssl;
    server_name api.testnode.com;
    ssl_certificate /etc/nginx/certificates/site.crt;
    ssl_certificate_key /etc/nginx/certificates/site.key;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    access_log /var/log/nginx/votreprojet.log;

    # supposedly prevents 502 bad gateway error;
    # ultimately not necessary in my case
    large_client_header_buffers 8 32k;

    client_max_body_size 10M;

    # pass the request to the node.js server with the correct headers and much more can be added, see nginx config options
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        # prevent 504
        proxy_read_timeout 600;

        # supposedly prevents 502 bad gateway error;
        # ultimately not necessary in my case
        proxy_buffers 8 32k;
        proxy_buffer_size 64k;

        proxy_pass http://app_nodenomunique/;
        proxy_redirect off;

        # the following is required as well for WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Comment ça marche exactement ici ? La liaison vers votre serveur node.JS est renseignée via cette partie du fichier :

upstream app_nodenomunique {
        server 127.0.0.1:3000;
}

Ensuite, nous indiquons dans la partie location /, qui correspond aux réglages de la racine de notre url (ici api.testnode.com) de passer par le proxy http://app_nodeunique/ qui correspond à notre redirection vers 127.0.0.1:3000. Pour l’utilisateur accédant à votre site, api, … c’est entièrement transparent.

Pour finir, vous devrez créer un lien symbolique pour placer le fichier dans le répertoire sites-enabled puis de relancer nginx :

sudo ln -s /etc/nginx/sites-available/api.testnode.com /etc/nginx/sites-enabled/
sudo service nginx restart
Si vous essayez d’accéder à votre site, vous devriez avoir, si bien entendu votre serveur node.JS est coupé, une erreur 502 voulant dire que Nginx ne peut réaliser la redirection.

Initialisation du projet depuis GIT

Cette partie vous concerne si vous avez votre projet hébergé chez git. Je donne ici les commandes à effectuer pour initialiser ce projet. De toute manière voici l’arborescence que vous devriez avoir :

/
˪ home
    ˪ webuser
        ˪ public_html
            ˪ votreprojet 

Et maintenant l’initialisation via git :

cd /home/webuser/public_html
sudo -u webuser -H git clone git@votreserveur:userougroupe/votreprojet.git
cd votreprojet
sudo -u webuser -H npm install

Upstart

Upstart va servir à démarrer notre serveur comme si c’étasit un service linux, avec le bon utilisateur comme propriétaire. Pour cela, vous devez créer le fichier /etc/init/votreprojet.conf avec le contenu suivant :

#/etc/init/votreprojet.conf
description "NodeServer init script"
author "throrin19"

start on startup # it's possible to use "net-device-up IFACE=eth0" for starting the process when the ethernet adapter is up
stop on shutdown

script
    cd /home/webuser/public_html/votreprojet
    exec sudo -u webuser NODE_ENV=production /usr/bin/nodejs /home/webuser/public_html/votreprojet/server.js >> /home/webuser/logs/nodeserver.log 2>&1
end script
Attention : Vous devrez impérativement créer le répertoire /home/webuser/logs.

Monit

Monit lui, va servir à redémarrer le serveur nginx s’il est en panne, redémarrer l’api si elle est innaccessible et envoyer un email d’erreur dès qu’il y en a. Pour cela, vous devrez créer deux fichiers :

  • /etc/monit/monitrc.d/votreprojet
  • /etc/monit/monitrc.d/email

Quand les fichiers sont crées et complétés, vous devrez faire un lien symbolique vers /etc/monit/conf.d de la manière suivante :

sudo ln -s /etc/monit/monitrc.d/email /etc/monit/conf.d/
sudo ln -s /etc/monit/monitrc.d/votreprojet /etc/monit/conf.d/
sudo ln -s /etc/monit/monitrc.d/nginx /etc/monit/conf.d/

votreprojet

check host nodeapp with address 127.0.0.1
    start "/sbin/start votreprojet"
    stop "/sbin/stop votreprojet"
    if failed port 3000 protocol HTTP
        request /
        with timeout 10 seconds
        then restart
        if 5 restarts within 5 cycles then timeout

email

set mailserver smtp.gmail.com port 587
    username "user@gmail.com" password "password"
    using tlsv1
    with timeout 30 seconds


set alert votremail@domain.com

set mail-format { 
    from:server@domain.net 
    subject: [production]monit alert -- $EVENT $SERVICE 
    message: $EVENT Service $SERVICE 
             Date: $DATE 
             Action: $ACTION 
             Host: $HOST 
             Description: $DESCRIPTION 
}

Start, Stop, Restart

Maintenant, si vous voulez lancer, arrêter et redémarrer l’api, vous n’aurez qu’à faire

sudo start votreprojet
sudo restart votreprojet
sudo stop votreprojet
Attention : Avec monit, si vous arrêtez l’API, elle se redémarrera automatiquement au bout de 30s.

Si vous voulez couper et relancer monit, faites juste :

sudo service monit stop
sudo service monit start

Script de mise en production

Lors de la mise à jour de l’API, tout comme pour l’installation, vous avez juste à lancer le script suivant :

#!/bin/sh
cd /home/webuser/public_html/votreprojet
sudo -u webuser -H git pull
sudo -u webuser -H npm install
sudo restart votreprojet

Le mot de la fin

Voilà. Maintenant vous êtes aptes à mettre en production votre projet NodeJS. Certains d’entre vous passeront par les tags plutôt que par la branche master pour les mises à jour de la production. Je suis bien preneur pour un script permutant ceci. De plus je n’ai pas parlé des scripts de migration pour mettre à jour la BDD, … Je me suis concentré sur l’essentiel. N’hésitez pas à me faire vos remarques.