Comment héberger une application Node.js sur un VPS
De la création du serveur au déploiement automatique : Node.js, PM2, Nginx et GitHub Actions sur un VPS Ubuntu en moins de 2 heures.
Un VPS coûte 5€ par mois. En deux heures, vous pouvez y déployer une application Node.js accessible via HTTPS avec déploiement automatique sur chaque push. Voici exactement comment faire.
Choisir un VPS
Pour une application Node.js avec moins de 10 000 visites par mois, un VPS à 4-6€/mois suffit : 1 vCPU, 1-2 Go RAM, 25 Go SSD. Providers qui fonctionnent bien : DigitalOcean, Hetzner (meilleur rapport qualité/prix en Europe), OVH, Scaleway.
Choisissez Ubuntu 22.04 LTS comme OS. Toutes les commandes de ce guide s'y appliquent.
Sécuriser l'accès SSH
La première connexion se fait en root avec le mot de passe fourni par le provider. Première étape : créer un utilisateur non-root et configurer l'auth par clé. Le guide SSH complet couvre tout ça — résumé rapide ici :
# Depuis votre machine locale — copier votre clé publique
ssh-copy-id root@IP_DU_VPS
# Sur le serveur — créer un utilisateur
adduser william
usermod -aG sudo william
# Copier les clés autorisées au nouvel utilisateur
rsync --archive --chown=william:william ~/.ssh /home/william
# Désactiver le login root et mot de passe
nano /etc/ssh/sshd_config
# PermitRootLogin no
# PasswordAuthentication no
systemctl reload sshdDéconnectez-vous et reconnectez-vous avec ssh william@IP_DU_VPS. Si ça marche, la sécurité de base est en place.
Configurer le pare-feu
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw statusUFW est simple et suffisant pour un VPS solo — pas besoin de iptables directement.
Installer Node.js avec nvm
Évitez apt install nodejs — la version est souvent ancienne et très difficile à mettre à jour. nvm (Node Version Manager) permet de basculer entre versions facilement.
# Installer nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
# Installer Node.js LTS
nvm install --lts
nvm use --lts
nvm alias default node
# Vérification
node -v # v22.x.x
npm -v # 10.x.xDéployer l'application
# Installer git et cloner votre repo
sudo apt install git -y
git clone https://github.com/vous/votre-app.git /home/william/app
cd /home/william/app
# Installer les dépendances
npm ci --production
# Variables d'environnement
cp .env.example .env
nano .env # Remplir DATABASE_URL, JWT_SECRET, etc.Testez que l'app démarre :
node src/index.js
# Listening on port 3000
# Ctrl+C pour arrêterPM2 : garder l'app active
Node.js plante, le VPS redémarre, vous voulez que l'app survive. PM2 est le gestionnaire de processus standard.
# Installer PM2 globalement
npm install -g pm2
# Démarrer l'application
pm2 start src/index.js --name "mon-app"
# Ou avec un fichier de config (recommandé)
pm2 start ecosystem.config.jsmodule.exports = {
apps: [{
name: 'mon-app',
script: 'src/index.js',
instances: 'max', // Un process par CPU
exec_mode: 'cluster', // Load balancing entre instances
env: {
NODE_ENV: 'production',
PORT: 3000,
},
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
restart_delay: 3000, // 3s entre les redémarrages
max_restarts: 10,
min_uptime: '10s', // Considéré stable si tient 10s
}],
}pm2 start ecosystem.config.js
# Démarrer PM2 au boot du serveur
pm2 startup
# Copier-coller la commande affichée (sudo env PATH=...)
pm2 save
# Commandes utiles
pm2 status # État des apps
pm2 logs mon-app # Logs en temps réel
pm2 restart mon-app
pm2 reload mon-app # Zero-downtime restart (cluster mode)
pm2 monit # Dashboard interactifNginx : reverse proxy HTTPS
L'application tourne sur le port 3000 en local. Nginx reçoit les requêtes sur les ports 80/443 et les transmet.
Installez Nginx et configurez-le — le guide Nginx complet détaille toutes les options. Configuration minimale pour une app Node.js :
sudo apt install nginx -y
sudo nano /etc/nginx/sites-available/mon-appserver {
listen 80;
server_name mondomaine.fr www.mondomaine.fr;
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;
}
}sudo ln -s /etc/nginx/sites-available/mon-app /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxSSL avec Let's Encrypt
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d mondomaine.fr -d www.mondomaine.fr
# Suivre les instructions — email, accepter les CGU
# Certbot modifie nginx.conf et recharge Nginx automatiquement
# Vérifier le renouvellement automatique
sudo certbot renew --dry-runVotre app est maintenant accessible via HTTPS.
Variables d'environnement en production
Ne jamais commiter le .env dans git. Deux approches :
Approche simple — fichier .env sur le serveur, hors git :
# Sur le serveur uniquement
echo "DATABASE_URL=postgres://..." >> /home/william/app/.env
echo "JWT_SECRET=$(openssl rand -hex 32)" >> /home/william/app/.envApproche CI/CD — secrets GitHub Actions injectés à chaque déploiement :
- name: Create .env
run: |
echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> .env
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .envDéploiement automatique avec GitHub Actions
À chaque push sur main, le code est déployé automatiquement sur le VPS.
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to VPS
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /home/william/app
git pull origin main
npm ci --production
pm2 reload mon-appDans GitHub → Settings → Secrets, ajoutez :
VPS_HOST: l'IP du VPSVPS_USER:williamSSH_PRIVATE_KEY: le contenu de~/.ssh/id_rsa(clé privée locale)
Le guide GitHub Actions complet couvre les tests, les environnements staging et les stratégies de déploiement plus avancées.
Monitoring de base
# Uptime et charge
uptime
htop
# Espace disque
df -h
# Logs Nginx
sudo tail -f /var/log/nginx/error.log
# Logs app
pm2 logs mon-app --lines 50
# Statut de tous les services
pm2 status
sudo systemctl status nginx# Script de health check (optionnel — ajouter en crontab)
#!/bin/bash
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health)
if [ "$response" != "200" ]; then
pm2 restart mon-app
echo "App redémarrée — $(date)" >> /home/william/logs/health.log
fiUn VPS + PM2 + Nginx couvre 95% des besoins d'une application Node.js jusqu'à quelques dizaines de milliers de visites quotidiennes. Quand vous atteignez les limites d'un seul serveur, Docker et un orchestrateur deviennent nécessaires — Docker simplifie le packaging et garantit que l'app se comporte identiquement en dev et en prod.