Dans cet article, nous allons voir comment déployer une application Node.js sur un serveur dédié. L'objectif est de partir d'un serveur vierge et d'installer tout ce qui est nécessaire pour faire fonctionner notre application sous un nom de domaine.
Avant de commencer il est important d'avoir un plan d'action et nous allons faire ce déploiement en 5 étapes :
- Configuration de base (mise à jour du système, création d'un utilisateur)
- Installation de l'application (installation de Node.js et PM2 et déploiement du code via rsync)
- Mise en place d'un serveur web (installation et configuration de caddy)
- Sécurisation du serveur (installation du pare feu UFW)
- Installation et configuration de la base de données (Mariadb dans notre cas)
L'idée est de proposer une méthode simple et efficace pour mettre votre application en ligne rapidement et de manière sécurisée. Méthode que l'on pourra automatiser par la suite avec des outils comme ansible ou via des systèmes de conteneur.
1. Configuration de base du serveur
Pour le serveur nous allons utiliser un VPS avec une distribution Debian (mais ce qui suit fonctionnera très bien sur Ubuntu) sur lequel on se connectera via SSH à l'aide de la clef publique fournie à l'hébergeur (accès root par défaut).
Création du compte utilisateur
Dès la première connection nous allons commencer par mettre à jour le système
apt update && apt upgrade -y
apt install rsync curl
Puis, pour des raisons de sécurité nous allons créer un nouvel utilisateur qui nous servira à lancer notre application NodeJS sur le serveur avec des droits plus limités que le super administrateur.
adduser USER
usermod -aG sudo USER # Ajout aux sudoers
# Si vous voulez copier les clefs déjà autorisées vers l'utilisateur
cp -R ~/.ssh /home/USER/.ssh
chown USER:USER -R ~/.ssh /home/USER/.ssh
Ensuite, après avoir vérifié que l'on peut se connecter avec notre nouvel utilisateur, on modifie la configuration SSH /etc/ssh/sshd_config
pour être plus restrictif :
PermitRootLogin no
PasswordAuthentication no
Et on redémarre le service SSH :
sudo systemctl restart sshd
2. Installation de l'application & NodeJS
Maintenant on va chercher à faire fonctionner notre application NodeJS sur le serveur.
2.1 Installation de NVM et Node.js
Pour installer NodeJS il existe plusieurs approche mais nous allons utiliser celle qui est proposée par défaut sur le site de NodeJS : nvm. nvm permet de gérer facilement la version de NodeJS que l'on veut utiliser sur le serveur mais la méthode d'installation de NodeJS importe peu pour la suite.
Ensuite, nous installons PM2 qui permettra de gérer notre application en arrière plan et de gérer son redémarrage en cas de problème :
npm install -g pm2
pm2 startup systemd -u USER --hp /home/USER # pour enregistrer le service au démarrage
2.2 Copie des fichiers sur le serveur
En local, on va construire notre projet (si nécessaire) et l'envoyer sur le serveur à l'aide de la commande rsync
:
npm run build # Si le projet a besoin d'une compilation
rsync -avz ./build/ USER@IP:/home/USER/monapp/
Côté serveur, on va installer les dépendances nécessaire au fonctionnement du projet (il faudra adapter en fonction du type de projet).
cd ~/monapp
npm ci --omit=dev
Pour démarrer automatiquement l'application via pm2 on créea un fichier ecosystem.config.cjs
. Vous pouvez aussi utiliser ce fichier pour définir les variables d'environnements
module.exports = {
apps: [
{
name: 'monapp',
script: './server.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
env: {
"NODE_ENV": "production",
}
},
],
}
On peut ensuite enregistrer notre application auprès de pm2 et s'assurer que l'application fonctionne convenablement (en utilisant curl
par exemple).
pm2 start ecosystem.config.js
pm2 save
2.3 Automatisation
Pour automatiser l'envoie d'une nouvelle version sur le site vous pouvez créer un fichier Makefile
qui vous permettra en une seule commande d'effectuer l'envoie et le redémarrage.
.PHONY: deploy
deploy:
npm run build
rsync -avz -e 'ssh -i ~/.ssh/maclef' ./build/ USER@IP:~/monapp/
ssh -i ~/.ssh/maclef USER@IP "source ~/.nvm/nvm.sh && cd monapp && npm ci --omit=dev && node ace migration:run --force && pm2 reload monapp"
3. Configuration du serveur web
Pour le serveur web nous allons utiliser Caddy car c'est l'outil qui offre le minimum de configuration et qui permet aussi de gérer les certificats SSL automatiquement. Pour l'installer on suivra les instructions de la documentation (cela permet d'ajouter les dépôts de Caddy).
sudo apt install caddy
Le serveur sera automatiquement démarré avec un service enregistré auprès de systemd. On modifiera la configuration par défaut /etc/caddy/Caddyfile
pour correspondre à notre site. La configuration minimale est la suivante :
monapp.mondomaine.com {
reverse_proxy localhost:3333
}
On recharge ensuite le service
sudo systemctl restart caddy
Et caddy se chargera de récupérer auprès de Let's Encrypt un certificat et dès que c'est fait, noptre application sera accessible via https://monapp.mondomaine.com
.
4. Sécurisation du serveur avec UFW
Avant d'installer de nouvelles application nous allons activer un parefeu logiciel qui permettra de bloquer les accès à notre serveur depuis l'extérieur (pratique pour éviter d'exposer une base de données à l'extérieur). Pour ce parefeu nous allons utiliser ufw qui a déjà été traité sur la chaine.
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow "SSH"
sudo ufw allow "WWW Full"
sudo ufw enable
Attention à bien comprendre ce que vous faites car un parefeu mal configuré peut rapidement vous enfermer dehors.
5. Installation et configuration de la base de données
Pour la base de données le site en question utilise MariaDB.
sudo apt install mariadb-server
On sécurise ensuite notre installation à l'aide de la commande
sudo mariadb-secure-installation
Et on crée une base de données et un utilisateur associé :
CREATE DATABASE monapp;
CREATE USER 'monapp'@'localhost' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON monapp.* TO 'monapp'@'localhost';
FLUSH PRIVILEGES;
On modifie ensuite les variables d'environnements de notre application pour qu'elle puisse se connecter à la base de données. Si votre application dispose d'un système de migration on peut le lancer à cette étape afin de remplir notre base de données.
pm2 reload monapp
C'est fini !
Et voila ! nous avons déployé une application Node.js sur un serveur dédié en quelques commandes. Si vous souhaitez aller plus loin, vous pouvez essayer d'automatiser les choses à l'aide de scripts ou en utilisant des outils comme Ansible. Vous pouvez aussi explorer le principe des conteneur si vous voulez vraiment isoler vos applications.