Comment déployer une application Node.js sur Ubuntu 26.04

En cours d’exécution node app.js sur un ordinateur portable de développeur, c’est une chose ; obtenir le même code pour rester actif sur un serveur de production, redémarrer après un crash, survivre à un redémarrage et répondre aux demandes sur les ports HTTPS standard en est une autre. Un déploiement Node.js fonctionnel sur Ubuntu 26.04 comporte trois parties mobiles : le runtime, un gestionnaire de processus qui maintient l’application en vie et un proxy inverse qui gère TLS et achemine le trafic vers l’application.

Ce guide explique comment déployer une application Node.js sur Ubuntu 26.04 en utilisant PM2 comme gestionnaire de processus et Nginx comme proxy inverse, avec un certificat Let’s Encrypt devant.

Conditions préalables

Avant de commencer il vous faut :

  • Ubuntu 26.04 avec un utilisateur qui a sudo privilèges
  • Un nom de domaine avec un enregistrement A pointant vers l’IP publique du serveur
  • Ports 80 et 443 ouverts dans le pare-feu

Nous utiliserons example.com et une application qui écoute sur le port 3000. Remplacez vos vraies valeurs.

Étape 1 : Installer Node.js

Ubuntu 26.04 inclut Node.js dans ses référentiels, mais NodeSource facilite l’installation d’une version LTS en amont spécifique. Les commandes ci-dessous installent Node.js 24.x, la ligne LTS actuelle au moment de la publication.

Installez les packages requis et importez la clé de signature NodeSource :

Terminal

sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL  | \
 sudo gpg --dearmor --yes -o /etc/apt/keyrings/nodesource.gpg

Ajoutez le dépôt Node.js 24.x :

Terminal

NODE_MAJOR=24
echo "deb (signed-by=/etc/apt/keyrings/nodesource.gpg) https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | \
 sudo tee /etc/apt/sources.list.d/nodesource.list

Mettez à jour l’index du package et installez Node.js :

Terminal

sudo apt update
sudo apt install -y nodejs

Confirmez que les deux binaires sont en place :

Terminal

node --version
npm --version

sortir

v24.16.0
11.16.0

Les versions exactes des correctifs changeront à mesure que les mises à jour de Node.js et npm seront publiées. Pour d’autres méthodes d’installation, consultez notre guide sur l’installation de Node.js et npm sur Ubuntu 26.04.

Étape 2 : préparer un utilisateur et un répertoire de déploiement

Les applications de production doivent s’exécuter en tant que compte non root possédant uniquement ses propres fichiers. Créez un utilisateur dédié :

Terminal

sudo adduser --system --group --home /var/www/app --shell /bin/bash app

Le --system flag crée un compte avec la connexion par mot de passe désactivée, ce qui est approprié pour un compte de service. Les administrateurs peuvent toujours exécuter des commandes de déploiement en tant qu’utilisateur via sudo.

Configurez le répertoire de déploiement :

Terminal

sudo mkdir -p /var/www/app
sudo chown -R app:app /var/www/app

Étape 3 : Installez l’application sur le serveur

La plupart des déploiements extraient le code de Git. Clonez le référentiel en tant que app utilisateur:

Terminal

sudo apt install -y git
sudo -H -u app git clone  /var/www/app

Installez les dépendances dans ce répertoire :

Terminal

sudo -H -u app bash -c 'cd /var/www/app && npm ci --omit=dev'

npm ci est la bonne commande pour les déploiements : elle lit package-lock.json et refuse de reculer lorsque le fichier de verrouillage est désynchronisé. --omit=dev ignore les dépendances de développement uniquement, ce qui réduit la taille de l’installation de production.

Si l’application comporte une étape de génération qui dépend des packages de développement, installez d’abord toutes les dépendances, créez le projet, puis supprimez les packages de développement uniquement :

Terminal

sudo -H -u app bash -c \
 'cd /var/www/app && npm ci && npm run build && npm prune --omit=dev'

Pour les référentiels privés, configurez une clé de déploiement SSH ou un jeton d’accès de courte durée pour le app compte. Ne stockez pas les informations d’identification du référentiel dans le répertoire de l’application.

Pour un test rapide sans véritable référentiel, écrivez plutôt une application Express minimale :

Terminal

sudo -H -u app bash -c 'cd /var/www/app && npm init -y && npm install express'
sudo -H -u app nano /var/www/app/server.js

/var/www/app/server.jsjs

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
 res.send("Hello from Node.js on Ubuntu 26.04");
});

app.listen(port, "127.0.0.1", () => {
 console.log(`App listening on http://127.0.0.1:${port}`);
});

Notez que l’appel d’écoute se lie à 127.0.0.1pas 0.0.0.0. Le proxy inverse atteindra l’application via un bouclage, et la liaison à localhost maintient entièrement l’application hors du réseau public.

Étape 4 : Installez PM2 et exécutez l’application

PM2 est un gestionnaire de processus Node.js qui gère les redémarrages, les journaux et le clustering. Installez-le globalement :

Terminal

sudo npm install -g pm2

Configurez toutes les variables d’environnement requises avant de démarrer le processus. Conservez les clés API, les mots de passe de base de données et autres secrets en dehors du référentiel Git et ajoutez des .env fichiers à .gitignore.

Démarrez l’application sous PM2 comme app utilisateur:

Terminal

sudo -H -u app pm2 start /var/www/app/server.js --name myapp --time

sortir

(PM2) Starting /var/www/app/server.js in fork_mode (1 instance)
(PM2) Done.
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┤
│ 0 │ myapp │ default │ 1.0.0 │ fork │ 12345 │ 0s │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┘

Vérifiez que l’application répond lors du bouclage :

Terminal

curl 

sortir

Hello from Node.js on Ubuntu 26.04

Pour que PM2 démarre l’application au démarrage, générez l’unité systemd et figez la liste des processus :

Terminal

sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u app --hp /var/www/app
sudo -H -u app pm2 save

La première commande écrit et active pm2-app.service; le second enregistre la liste des processus en cours afin que PM2 sache par où commencer. Confirmez que l’unité est activée :

Terminal

sudo systemctl status pm2-app

Étape 5 : Installer et configurer Nginx

Installez Nginx :

Terminal

sudo apt install nginx

Créez un bloc serveur qui transmet les requêtes à l’application Node.js :

Terminal

sudo nano /etc/nginx/sites-available/example.com

/etc/nginx/sites-available/example.comnginx

server {
 listen 80;
 listen (::):80;

 server_name example.com www.example.com;

 location / {
 proxy_pass ;
 proxy_set_header Host $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;
 }
}

Les en-têtes conservent l’hôte d’origine, l’adresse IP du client et le protocole de l’application. Si l’application utilise WebSockets, ajoutez les paramètres de mise à niveau du guide du proxy inverse Nginx.

Activez le site et testez la configuration :

Terminal

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Ouvrez le pare-feu :

Terminal

sudo ufw allow 'Nginx Full'

Visite et confirmez le rendu de la page. Les requêtes transitent désormais du navigateur vers Nginx sur le port 80, puis vers Node.js sur le port de bouclage 3000.

Étape 6 : ajouter HTTPS avec Certbot

Installez Certbot et le plugin Nginx :

Terminal

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

Certbot réécrit le bloc serveur pour mettre fin à TLS, ajoute une redirection HTTP vers HTTPS et enregistre un minuteur de renouvellement. Vérifier:

Terminal

curl -I 
sudo certbot renew --dry-run

La première commande doit renvoyer un statut HTTP réussi sur HTTPS. L’essai de renouvellement confirme que Certbot peut renouveler le certificat avant son expiration.

Étape 7 : Gérer l’application avec PM2

Une fois le déploiement opérationnel, les opérations quotidiennes passent toutes par PM2 :

Terminal

sudo -H -u app pm2 ls
sudo -H -u app pm2 logs myapp
sudo -H -u app pm2 restart myapp
sudo -H -u app pm2 stop myapp

PM2 écrit la sortie de l’application sous /var/www/app/.pm2/logs. Installez le module de rotation des journaux pour que ces fichiers ne grossissent pas sans limite :

Terminal

sudo -H -u app pm2 install pm2-logrotate
sudo -H -u app pm2 set pm2-logrotate:max_size 10M
sudo -H -u app pm2 set pm2-logrotate:retain 7

Pour déployer une nouvelle version, effectuez uniquement les modifications rapides, installez les dépendances et redémarrez le processus :

Terminal

sudo -H -u app bash -c \
 'cd /var/www/app && git pull --ff-only && npm ci --omit=dev'
sudo -H -u app pm2 restart myapp --update-env
sudo -H -u app pm2 save

Ce guide démarre l’application en mode fork, donc pm2 restart interrompt brièvement les demandes. Aucun temps d’arrêt pm2 reload nécessite le mode cluster avec au moins deux instances :

Terminal

sudo -H -u app pm2 delete myapp
sudo -H -u app pm2 start /var/www/app/server.js --name myapp -i 2 --time
sudo -H -u app pm2 save
sudo -H -u app pm2 reload myapp

Le mode cluster fonctionne bien pour les applications HTTP sans état. Les applications qui conservent les sessions, les tâches planifiées ou l’état de WebSocket en mémoire nécessitent un magasin externe ou une coordination supplémentaire avant d’exécuter plusieurs instances.

Dépannage

502 Bad Gateway de Nginx

L’application Node.js n’est pas en cours d’exécution, n’écoute pas sur le port attendu ou est liée à la mauvaise adresse. Vérifier sudo -H -u app pm2 ls et confirmez que le processus est en ligne, puis exécutez sudo ss -ltnp | grep 3000 pour confirmer qu’il écoute en boucle.

PM2 ne démarre pas au démarrage

L’unité systemd n’était pas activée, ou pm2 save a été ignoré. Vérifier sudo systemctl status pm2-appréexécutez la commande de démarrage, puis exécutez sudo -H -u app pm2 save.

Certbot ne peut pas valider le domaine

Confirmez que les enregistrements A et AAAA du domaine pointent vers ce serveur, que le port 80 est accessible et sudo ufw status montre Nginx Full autorisé. Si un enregistrement AAAA incorrect pointe ailleurs, la validation Let’s Encrypt peut échouer même lorsque l’enregistrement A est correct.

FAQ

Pourquoi utiliser Nginx devant Node.js ?

Nginx gère les ports publics et le certificat TLS tandis que le processus Node.js reste sur un port local non privilégié. Il vous offre également un emplacement unique pour les limites de requêtes, les fichiers statiques, les journaux d’accès et le routage de plusieurs applications par domaine.

Puis-je exécuter plusieurs applications Node.js sur le même serveur ?

Oui. Donnez à chaque application son propre port, sa propre entrée PM2 et son propre bloc de serveur Nginx. Le proxy inverse achemine par nom d’hôte afin que chaque application reçoive les requêtes pour son domaine uniquement.

Dois-je utiliser PM2 ou systemd directement ?

Les deux fonctionnent. PM2 ajoute des contrôles de processus, un clustering et des rechargements spécifiques à Node.js, tandis que systemd est plus simple lorsque vous n’avez besoin de superviser qu’un seul processus. Dans cette configuration, systemd démarre PM2 au démarrage et PM2 gère l’application.

Conclusion

Un déploiement de production Node.js sur Ubuntu 26.04 utilise PM2 pour maintenir l’application en cours d’exécution et Nginx pour gérer le trafic public HTTP et HTTPS. Gardez l’application liée au bouclage, faites pivoter ses journaux et testez la procédure de mise à jour avant que le serveur ne transporte le trafic de production.

Pour une configuration associée, consultez nos guides sur l’installation de Node.js sur Ubuntu 26.04 et la configuration de Nginx en tant que proxy inverse.