Pourquoi déployer Node.js sur un VPS plutôt que sur une plateforme managée ?
Les plateformes serverless et PaaS sont pratiques au démarrage mais leur coût grimpe avec le trafic, et elles imposent des contraintes (timeouts, cold starts, limites de connexions WebSocket). Un VPS vous donne un process Node.js persistant, des connexions longues (WebSocket, SSE) sans limite artificielle, des ressources dédiées et un coût fixe prévisible. Vous décidez de la version de Node, du gestionnaire de processus, du reverse proxy et de la stratégie de mise à jour, sans dépendre des conventions d'un fournisseur.
Le modèle asynchrone non bloquant de Node.js permet à un seul processus de tenir un grand nombre de connexions simultanées : c'est ce qui en fait un bon candidat pour les API REST, le temps réel et les microservices, à condition que ce processus reste vivant. C'est justement ce que la plupart des hébergements mutualisés refusent, en interdisant les processus persistants ou les WebSocket. Sur un VPS, vos dépendances npm, vos variables d'environnement et votre configuration PM2 ne sont partagées avec aucun autre compte.
Ce que vous gagnez avec un VPS pour Node.js
- Process Node.js persistant, idéal pour WebSocket, SSE et tâches longues sans cold start
- Redémarrage automatique en cas de crash et au reboot du serveur grâce à PM2
- Mode cluster pour exploiter tous les cœurs CPU du VPS sans changer votre code
- Reverse proxy Nginx devant Node pour le HTTPS, la compression et les fichiers statiques
- Workers de files d'attente (BullMQ, Agenda) et tâches planifiées qui tournent à côté de l'API, sur la même machine
- Plusieurs applications sur un seul VPS, chacune sur son port interne (3000, 3001…) et son sous-domaine derrière Nginx
- Rendu serveur de frameworks comme Nuxt ou Next.js, servis par le même socle Node.js et PM2
- Coût fixe et prévisible, sans facturation à la requête ni surprise de scaling
- Contrôle total de la version de Node.js et des dépendances système
Prérequis
Une application Node.js standard (API Express, Nest, Fastify) tourne confortablement sur un VPS de 1 à 2 vCPU et 1 à 2 Go de RAM ; prévoyez davantage de RAM si vous compilez un front lourd au build ou exécutez des workers. Visez 2 vCPU et 2 Go dès que l'API partage la machine avec un rendu SSR ou une base PostgreSQL.
Choisissez une ligne LTS encore maintenue : Node.js 20 ne reçoit plus de correctifs depuis le 30 avril 2026, Node.js 24 est passé en maintenance le 20 octobre 2026 et Node.js 26 est la LTS active depuis le 28 octobre 2026. Installez-la via nvm ou le dépôt NodeSource pour la figer, ainsi que PM2 comme gestionnaire de processus et Nginx comme reverse proxy. Il vous faut un domaine pointant vers l'IP du VPS et les ports 80/443 ouverts.
Partir du template Node.js Stack
Le template Node.js Stack du Marketplace ServOrbit prépare un VPS Ubuntu 24.04 avec Node.js dans la ligne LTS courante du dépôt NodeSource, npm, PM2 installé globalement, Nginx et PostgreSQL. Il vous dispense de la première étape ci-dessous ; le reste du guide s'applique tel quel.
Ce n'est pas une application avec un écran de connexion mais un environnement d'exécution : on y entre en SSH (ssh root@<ip-du-vps>) pour déposer son code. Au premier accès, Nginx sert sa page d'accueil par défaut sur le port 80, car aucun virtual host n'est encore écrit pour votre domaine, et Certbot n'est pas installé : les étapes Nginx et HTTPS restent à faire. PostgreSQL n'écoute qu'en local et authentifie l'utilisateur système postgres par la méthode peer : sudo -u postgres psql ouvre la console sans mot de passe.
Déployer une application Node.js en production
Préparer le VPS et installer Node.js
Sur un VPS Ubuntu 24.04, mettez le système à jour et installez une version LTS de Node via nvm (
nvm install --lts) ou le dépôt NodeSource. Vérifiez :node -vetnpm -v. Créez un utilisateur non-root dédié à l'application plutôt que de tout exécuter en root : c'est lui qui possédera le code, le fichier.envet les processus PM2. Avec le template Node.js Stack, Node.js, npm et PM2 sont déjà installés : ne gardez que la création de l'utilisateur.Récupérer le code et builder
Clonez votre dépôt sur le VPS, installez les dépendances de production (
npm ci --omit=dev) et lancez le build si nécessaire (npm run build).Placez les variables sensibles dans un fichier
.envnon commité, lisible par le seul utilisateur de l'application (chmod 600 .env). Inutile d'ajouter une bibliothèque pour le lire : depuis Node.js 20.6, l'option--env-filecharge ce fichier dansprocess.envau démarrage.Préparer la base PostgreSQL
Si l'application a besoin d'une base, créez un rôle et une base dédiés plutôt que de travailler avec le superutilisateur :
sudo -u postgres createuser --pwprompt monapp sudo -u postgres createdb --owner=monapp monappRenseignez ensuite
DATABASE_URL=postgres://monapp:<mot-de-passe>@127.0.0.1:5432/monappdans le.env. Comme PostgreSQL n'écoute qu'en local, aucun port de base de données n'est à ouvrir dans le pare-feu.Lancer l'application avec PM2
Installez PM2 globalement (
npm install -g pm2, déjà fait sur le template) puis démarrez l'app depuis le dossier du projet, en demandant à Node de charger le.env:pm2 start app.js --name monapp -i max --node-args="--env-file=.env"Le flag
-i maxactive le mode cluster sur tous les cœurs. PM2 relance automatiquement le process en cas de crash.Activer le démarrage automatique au boot
Générez le script systemd avec
pm2 startup, lancé par l'utilisateur de l'application, exécutez avec sudo la commande affichée, puis figez l'état actuel avecpm2 save. Au prochain redémarrage du VPS, votre application sera relancée automatiquement, sans intervention.Configurer Nginx en reverse proxy
Installez Nginx s'il n'est pas déjà présent et créez
/etc/nginx/sites-available/monapp, un virtual host qui proxifie vers le port local de Node. Les en-têtesUpgradeetConnectionservent aux WebSocket,X-Forwarded-Protoindique à l'application que le client est en HTTPS :server { listen 80; server_name votre-domaine.com; location / { proxy_pass http://127.0.0.1:3000; 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-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }Activez le site, retirez la page par défaut, testez la configuration puis rechargez :
ln -s /etc/nginx/sites-available/monapp /etc/nginx/sites-enabled/ rm /etc/nginx/sites-enabled/default nginx -t && systemctl reload nginxSécuriser en HTTPS avec Let's Encrypt
Installez Certbot et son plugin Nginx, puis demandez le certificat :
apt install certbot python3-certbot-nginx certbot --nginx -d votre-domaine.comCertbot obtient le certificat, configure la redirection HTTP→HTTPS et programme le renouvellement automatique. Votre application Node est désormais servie en HTTPS.
Centraliser la configuration dans ecosystem.config.js
Dès que le VPS porte plus d'une application, ou qu'une API s'accompagne d'un worker, les options passées en ligne de commande deviennent difficiles à retrouver. PM2 lit un fichier ecosystem.config.js qui décrit chaque processus : script, dossier, nombre d'instances, limite mémoire et variables non sensibles.
module.exports = {
apps: [
{
name: 'api',
cwd: '/home/monapp/app',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
node_args: '--env-file=.env',
max_memory_restart: '500M',
env: { NODE_ENV: 'production', PORT: 3000 }
},
{
name: 'worker',
cwd: '/home/monapp/app',
script: 'worker.js',
node_args: '--env-file=.env'
}
]
}pm2 start ecosystem.config.js démarre l'ensemble, pm2 reload ecosystem.config.js le met à jour et l'option --only api cible une seule application. L'API tourne ici en cluster sur tous les cœurs, le worker en un seul processus. Versionnez ce fichier avec le code ; les secrets, eux, restent dans le .env hors dépôt.
Journaux : les lire, puis les faire tourner
PM2 capture la sortie standard et la sortie d'erreur de chaque processus dans ~/.pm2/logs/, avec un fichier -out.log et un fichier -error.log par application. pm2 logs monapp les suit en direct, pm2 logs monapp --lines 100 affiche les dernières lignes.
Sans rotation, ces fichiers grossissent jusqu'à remplir le disque. Le module pm2-logrotate s'en charge ; par défaut, il fait tourner un fichier au-delà de 10 Mo et en conserve 30, des seuils que l'on adapte facilement :
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7Côté proxy, une erreur 502 se lit dans /var/log/nginx/error.log : elle signifie presque toujours que le processus Node.js est arrêté ou qu'il écoute sur un autre port que celui du proxy_pass.
Pour des déploiements sans interruption, combinez PM2 en mode cluster avec pm2 reload monapp plutôt que restart : PM2 redémarre les workers un par un, gardant toujours au moins une instance disponible pendant la mise à jour. Surveillez ensuite la mémoire avec pm2 monit et fixez une limite de redémarrage automatique (--max-memory-restart 500M) pour prévenir les fuites mémoire en production.
La documentation officielle
Pour les options propres à chaque outil et les changements de version, référez-vous à la documentation officielle de Node.js, au calendrier des versions LTS de Node.js et à la documentation de PM2. Ce guide couvre la mise en production sur un VPS ; la documentation éditeur reste la référence pour les réglages fins.