Introduction
Node.js seul est mono-process. En prod, on veut :
- Plusieurs workers (cluster) pour utiliser tous les CPU
- Restart automatique en cas de crash
- Demarrage au boot
- Logs centralises et rotates
- Monitoring (CPU, RAM, latence)
- Zero-downtime reload
PM2 est l'outil de reference pour tout ca. Open-source, mature, riche en plugins.
Prerequis
- VPS Linux Debian / Ubuntu
- Node.js 18+ installe
- Acces root
- Une app Node.js (Express, NestJS, Next.js, Fastify, etc.)
Etape 1 : Installation Node.js (NodeSource)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node --version
npm --version
Etape 2 : Installation PM2
sudo npm install -g pm2
pm2 --version
Etape 3 : Demarrer une app
Imaginons /var/www/monapp/index.js :
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello'));
app.listen(3000, () => console.log('Listening on 3000'));
Demarrer avec PM2 :
cd /var/www/monapp
pm2 start index.js --name monapp
Voir :
pm2 list
Status, CPU, RAM, restarts.
Etape 4 : Cluster mode
Pour utiliser tous les CPU :
pm2 start index.js --name monapp -i max
-i max lance autant d'instances que de cores. Ou nombre fixe :
pm2 start index.js --name monapp -i 4
PM2 lance 4 workers Node, distribue les requetes en round-robin. Chaque worker tourne sur un core different.
Etape 5 : Demarrage au boot
pm2 startup
PM2 affiche une commande a executer en root, type :
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u admin --hp /home/admin
Executez-la.
Puis sauvegardez la liste des apps en cours :
pm2 save
Au prochain reboot, PM2 redemarrera toutes vos apps automatiquement.
Etape 6 : Logs
pm2 logs # tous les logs
pm2 logs monapp # une app
pm2 logs --lines 100 # 100 dernieres lignes
Localisation des fichiers :
~/.pm2/logs/monapp-out.log # stdout
~/.pm2/logs/monapp-error.log # stderr
Rotation automatique (recommandee) :
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 100M
pm2 set pm2-logrotate:retain 30
pm2 set pm2-logrotate:compress true
Etape 7 : Configuration via ecosystem.config.js
Plutot que des arguments CLI, centralisez la config :
nano /var/www/monapp/ecosystem.config.js
module.exports = {
apps: [{
name: 'monapp',
script: './index.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_memory_restart: '500M',
env: {
NODE_ENV: 'production',
PORT: 3000,
DATABASE_URL: 'postgres://localhost/monapp'
},
error_file: '/var/log/pm2/monapp-error.log',
out_file: '/var/log/pm2/monapp-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
}]
}
Lancer :
pm2 start ecosystem.config.js
pm2 save
Etape 8 : Zero-downtime reload
pm2 reload monapp
PM2 redemarre les workers un par un, sans perdre une seule requete. Beaucoup mieux que restart (qui kill tout d'un coup).
Utilisez-le pour les deploiements :
git pull
npm install
pm2 reload monapp
Etape 9 : Reverse proxy Nginx devant
upstream monapp_backend {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 443 ssl http2;
server_name monapp.fr;
location / {
proxy_pass http://monapp_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
}
Etape 10 : Monitoring temps reel
pm2 monit
Interface TUI : CPU, RAM, logs, par instance. Pratique pour surveiller plusieurs apps.
Ou PM2 Plus (SaaS) pour monitoring distance :
pm2 link <secret_key> <public_key>
Etape 11 : Variables d'environnement
Plusieurs facons :
// ecosystem.config.js
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
env_staging: {
NODE_ENV: 'staging',
PORT: 3001
}
pm2 start ecosystem.config.js --env production
Ou via .env file et dotenv dans votre app.
Etape 12 : Memory leaks
Si votre app fuit de la memoire :
max_memory_restart: '500M'
PM2 restart automatiquement le worker des qu'il depasse 500 Mo. Workaround temporaire en attendant de fixer la fuite.
Pour identifier :
pm2 reload monapp --update-env
pm2 show monapp
Voir Heap snapshots via Chrome DevTools, ou utilisez clinic.js.
Depannage
App crash en boucle
pm2 logs monapp --err --lines 50
Identifiez l'erreur. Souvent : module manquant, port deja utilise, variable d'env manquante.
"ENOMEM" out of memory
Le worker depasse max_memory_restart. Augmentez ou identifiez la fuite.
Cluster mode ne fonctionne pas
L'app doit pouvoir tourner en cluster :
- Pas d'etat partage en memoire (utilisez Redis)
- WebSockets : utilisez
socket.io-redisou un mode sticky
PM2 ne demarre pas au boot
pm2 unstartup
pm2 startup
pm2 save
Logs trop volumineux
pm2 set pm2-logrotate:max_size 50M
pm2 flush # vider les logs
Commandes utiles
pm2 list # toutes les apps
pm2 show monapp # detail une app
pm2 logs monapp --lines 100 # logs
pm2 monit # TUI temps reel
pm2 restart monapp # restart hard
pm2 reload monapp # restart zero-downtime
pm2 stop monapp # stop
pm2 delete monapp # supprimer
pm2 save # sauvegarder la liste
pm2 resurrect # restaurer depuis sauvegarde
pm2 flush # vider tous les logs
pm2 startup # auto-start au boot
pm2 update # MAJ PM2 sans downtime
pm2 ecosystem # generer un ecosystem.config.js
Conclusion
PM2 vous donne :
- Cluster mode pour exploiter tous les CPU
- Restart automatique sur crash ou memoire excessive
- Zero-downtime deployments via reload
- Logs centralises et rotates
- Demarrage au boot
Pour aller plus loin :
- Utilisez PM2 Plus pour le monitoring distance
- Migrez vers systemd + Node.js cluster module pour une approche plus systeme
- Pour les architectures serverless, considerez AWS Lambda ou Cloudflare Workers
Ressources
- Documentation officielle PM2 : https://pm2.keymetrics.io/docs/usage/quick-start/
- Source : https://github.com/Unitech/pm2
- Cluster Node.js : https://nodejs.org/api/cluster.html
- Clinic.js : https://clinicjs.org



















