Prérequis
- Un serveur sous Ubuntu, Debian, AlmaLinux, Rocky, CentOS, Fedora, Alpine ou openSUSE : voir nos VPS au Canada
- Une connexion SSH ouverte en root : Se connecter en SSH à votre VPS
Node.js exécute du JavaScript côté serveur. Ce guide installe Node.js 24 (la version LTS), crée une petite application de test, la fait tourner en permanence avec PM2, puis la place derrière Nginx. Choisissez votre système ci-dessus. Copiez la commande avec le bouton Copier, collez-la dans votre terminal, et comparez avec le résultat attendu.
1Mettre à jour le système et installer Node.js 24
Mettez le système à jour d'abord : une ou deux minutes.
apt update && apt upgrade -y... 212 upgraded, 8 newly installed, 0 to remove and 4 not upgraded. (les nombres dépendent de l'âge de l'image)
dnf upgrade -y... Complete!
dnf upgrade -y... Complete!
apk update && apk upgrade && reboot... OK: 158 MiB in 209 packages (les nombres dépendent de l'image ; la connexion SSH se coupe au redémarrage)
Alpine redémarre après la mise à jour : quand elle remplace le noyau, les modules du noyau en cours disparaissent et le pare-feu de l'étape 5 ne peut plus se charger (« Couldn't determine iptables version »). Reconnectez-vous en SSH après une minute.
zypper -n refresh && zypper -n updateAll repositories have been refreshed. ...
Le dépôt NodeSource fournit la version LTS à jour, que les dépôts du système n'ont pas.
Le dépôt NodeSource fournit la version LTS à jour, que les dépôts du système n'ont pas.
Le dépôt NodeSource fournit la version LTS à jour, que les dépôts du système n'ont pas.
curl -fsSL https://deb.nodesource.com/setup_24.x | bash -... Repository configured successfully. ... To install Node.js, run: apt install nodejs -y
curl -fsSL https://rpm.nodesource.com/setup_24.x | bash -... Repository is configured and updated. ... Run 'dnf install nodejs -y' to complete the installation.
curl -fsSL https://rpm.nodesource.com/setup_24.x | bash -... Repository is configured and updated. ... Run 'dnf install nodejs -y' to complete the installation.
apt install -y nodejsdnf install -y nodejsdnf install -y nodejsapk add nodejs npmzypper -n install nodejs24 npm24node -v && npm -vv24.21.0 11.19.0 (les numéros exacts changent avec les mises à jour : l'important est le 24 en tête)
2Créer une application de test
Une application Express minimale, dans /var/www/monapp, qui répond en JSON sur le port 3000. Elle servira à vérifier chaque étape suivante.
mkdir -p /var/www/monapp && cd /var/www/monapp
npm init -y
npm install express... found 0 vulnerabilities (la ligne -added N packages- juste avant varie selon la version)
cat > /var/www/monapp/app.js << 'EOF'
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({ message: 'Bienvenue sur mon API Node.js!', timestamp: new Date().toISOString() });
});
app.get('/health', (req, res) => {
res.json({ status: 'OK' });
});
app.listen(PORT, () => {
console.log('Serveur démarré sur le port ' + PORT);
});
EOF3Faire tourner l'application avec PM2
PM2 garde l'application en vie : il la relance si elle plante et la redémarre avec le serveur. Sans lui, l'application s'arrête dès que vous fermez la session SSH.
npm install -g pm2cd /var/www/monapp && pm2 start app.js --name monappUn tableau PM2 avec une ligne monapp, colonne status : online
pm2 save && pm2 startup[PM2] Successfully saved in /root/.pm2/dump.pm2 [PM2] Init System found: systemd (ou openrc sur Alpine) ... (pm2 startup installe le service et l'affiche)
curl http://127.0.0.1:3000/{"message":"Bienvenue sur mon API Node.js!","timestamp":"2026-09-14T22:22:20.571Z"}4Les commandes PM2 du quotidien
pm2 listpm2 logs monapppm2 restart monapppm2 reload monapppm2 stop monapppm2 delete monappPour utiliser tous les processeurs du serveur, PM2 peut lancer une instance par cœur (mode cluster). Le fichier ci-dessous remplace la commande pm2 start.
cat > /var/www/monapp/ecosystem.config.js << 'EOF'
module.exports = {
apps: [{
name: 'monapp',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env_production: { NODE_ENV: 'production', PORT: 3000 },
max_memory_restart: '500M'
}]
};
EOF
cd /var/www/monapp && pm2 delete monapp; pm2 start ecosystem.config.js --env production && pm2 savepm2 list affiche autant de lignes monapp que le serveur a de cœurs, toutes en ligne
5Mettre Nginx devant l'application (port 80)
Nginx reçoit les visiteurs sur le port 80 et les transmet à l'application sur le port 3000. Remplacez monapp.exemple.ca par votre nom de domaine.
apt install -y nginx && systemctl enable --now nginxdnf install -y nginx && systemctl enable --now nginxdnf install -y nginx && systemctl enable --now nginxapk add nginx && rc-update add nginx default && rc-service nginx startzypper -n install nginx && systemctl enable --now nginxcat > /etc/nginx/sites-available/monapp << 'EOF'
server {
listen 80;
server_name monapp.exemple.ca;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOF
ln -sf /etc/nginx/sites-available/monapp /etc/nginx/sites-enabled/monapp
rm -f /etc/nginx/sites-enabled/defaultcat > /etc/nginx/conf.d/monapp.conf << 'EOF'
server {
listen 80;
server_name monapp.exemple.ca;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOFcat > /etc/nginx/conf.d/monapp.conf << 'EOF'
server {
listen 80;
server_name monapp.exemple.ca;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOFcat > /etc/nginx/http.d/monapp.conf << 'EOF'
server {
listen 80;
server_name monapp.exemple.ca;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOF
rm -f /etc/nginx/http.d/default.confcat > /etc/nginx/vhosts.d/monapp.conf << 'EOF'
server {
listen 80;
server_name monapp.exemple.ca;
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-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOFsetsebool -P httpd_can_network_connect 1setsebool -P httpd_can_network_connect 1apt install -y ufw && ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw --force enable... Firewall is active and enabled on system startup
dnf install -y firewalld && systemctl enable --now firewalld && firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reload... success success
dnf install -y firewalld && systemctl enable --now firewalld && firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reload... success success
apk add ufw && ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw --force enable && rc-update add ufw default... Firewall is active and enabled on system startup * service ufw added to runlevel default
systemctl enable --now firewalld && firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reloadsuccess success
nginx -t && systemctl reload nginxnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx -t && systemctl reload nginxnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx -t && systemctl reload nginxnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx -t && rc-service nginx reloadnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful * Reloading nginx configuration ... [ ok ]
nginx -t && systemctl reload nginxnginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
curl -H 'Host: monapp.exemple.ca' http://127.0.0.1/{"message":"Bienvenue sur mon API Node.js!","timestamp":"..."}6Activer HTTPS avec Let's Encrypt
À faire une fois que votre nom de domaine pointe vers l'adresse IP du serveur. Certbot obtient le certificat et modifie le site Nginx pour servir en HTTPS.
apt install -y certbot python3-certbot-nginxdnf install -y epel-release && dnf install -y certbot python3-certbot-nginxdnf install -y certbot python3-certbot-nginx python3-pyparsingapk add certbot certbot-nginxzypper -n install python313-certbot-nginxcertbot --nginx -d monapp.exemple.ca7Garder la configuration dans un fichier .env
Le port, les accès à une base de données ou une clé secrète n'ont rien à faire dans le code. Le paquet dotenv les lit dans un fichier .env au démarrage.
cd /var/www/monapp
cat > .env << 'EOF'
NODE_ENV=production
PORT=3000
EOF
npm install dotenvrequire('dotenv').config();cd /var/www/monapp && node -e "require('dotenv').config(); console.log('PORT lu =', process.env.PORT)"PORT lu = 3000
Autre façon d'installer : NVM
NVM installe Node.js dans le dossier de l'utilisateur et permet de changer de version sans toucher au système. Pratique pour un poste de développement, moins pour un serveur de production.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc
nvm install 24 && nvm use 24 && nvm alias default 24
node -vNode.js en production
Votre application tourne avec PM2, redémarre toute seule et répond derrière Nginx. Pour aller plus loin : une base de données MongoDB ou PostgreSQL, et un déploiement automatique depuis Git.
Erreurs fréquentes
L'image du serveur a été construite sur un autre disque et GRUB demande où se réinstaller : choisissez le disque de la machine (celui que lsblk affiche, en général /dev/sda) ; la mise à jour continue ensuite.
Ouvrez une nouvelle session SSH, ou vérifiez que le paquet vient bien du dépôt attendu (apt-cache policy nodejs, dnf info nodejs, apk info nodejs ou zypper info nodejs24).
SELinux empêche Nginx de joindre le port 3000 : lancez la commande setsebool de l'étape 5, puis rechargez Nginx.
Une autre application occupe déjà le port 3000. pm2 list montre ce qui tourne ; changez le PORT dans le fichier .env, ou arrêtez l'autre application.
L'application n'est pas démarrée. pm2 list doit afficher monapp en ligne ; sinon, pm2 logs monapp dit pourquoi elle s'arrête.
Le site par défaut est encore là (sites-enabled/default ou http.d/default.conf), ou le server_name du site ne correspond pas au nom de domaine appelé.