Administration Serveur angularforall.com

- Déployer Angular SSR sur Nginx avec PM2

Angular Ssr Pm2 Nginx Node.js Deploiement Production Reverse Proxy Linux
Déployer Angular SSR sur Nginx avec PM2

Mettez en production Angular Universal sur Linux : build SSR, cluster PM2, reverse proxy Nginx, cache statique, logs rotatifs et zero-downtime deploy avec pm2 reload.

Pourquoi deployer Angular en SSR

Une application Angular classique fonctionne en mode SPA (Single Page Application). Le navigateur recoit un fichier HTML quasi vide, telecharge le bundle JavaScript, puis Angular construit l'interface cote client. Ce modele est efficace, mais il a deux limites visibles en production : le First Contentful Paint reste long sur reseau lent et les robots d'indexation interpretent moins bien le contenu genere apres l'execution du JS.

Le rendu cote serveur (SSR), via Angular Universal, change cette equation. Chaque requete est traitee par un processus Node.js qui assemble la page complete, l'envoie au navigateur, puis Angular reprend la main cote client (hydration). Le visiteur voit un contenu structure quasi instantanement et les moteurs de recherche disposent d'un HTML complet a indexer.

Cote infrastructure, cela transforme une simple SPA en application avec runtime permanent. Vous ne servez plus uniquement des fichiers statiques : il faut un serveur Linux capable de faire tourner Node.js de maniere stable, et un reverse proxy comme Nginx pour absorber le trafic HTTPS, gerer les fichiers statiques et faire tampon devant le processus SSR.

A retenir : Angular SSR demande une vraie strategie d'exploitation. Le bon stack en 2026 reste Node.js geres par PM2 derriere Nginx, sur une distribution Linux LTS (Ubuntu 24.04 ou Debian 12).

Cet article reprend le meme cadre que Nginx en reverse proxy pour APIs et l'automatisation Linux, mais applique au cas concret du rendu serveur Angular.

Preparer le serveur Linux

Avant de toucher Angular, le serveur doit etre propre, a jour et minimal. Sur Ubuntu 24.04 LTS, commencez par mettre a jour les paquets et creer un utilisateur dedie a l'application. Ne deployez jamais une application Node.js sous root.

# Connexion sudo et mise a jour systeme
sudo apt update && sudo apt upgrade -y

# Installation des dependances de base
sudo apt install -y curl git build-essential ufw

# Creation d'un utilisateur dedie a l'app
sudo adduser --disabled-password --gecos "" angularapp
sudo usermod -aG sudo angularapp

Installez ensuite Node.js via le PPA officiel NodeSource. Pour Angular 18+, utilisez Node.js 20 LTS minimum. Evitez le paquet Debian/Ubuntu par defaut, souvent retarde de plusieurs versions majeures.

# Installation Node.js 20 LTS via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Verification
node -v   # v20.x.x
npm -v    # 10.x.x

Activez ensuite le firewall UFW pour limiter les ports exposes. Seuls SSH (22), HTTP (80) et HTTPS (443) doivent etre accessibles depuis l'exterieur. Le port Node (4000) doit rester strictement local.

# Configuration UFW
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

# Verification
sudo ufw status verbose
Bonne pratique : creer un utilisateur dedie evite que l'app Angular n'ait acces aux fichiers du systeme. C'est aussi indispensable pour le hardening SSH et fail2ban.

Construire l'application Angular SSR

Cote projet Angular, activez SSR au moment de la creation ou via la commande dediee. Depuis Angular 17, Universal est integre directement au CLI sous la forme du nouveau builder application.

# Nouveau projet avec SSR active
ng new mon-app --ssr --style=scss

# Sur un projet existant
cd mon-app
ng add @angular/ssr

Cette commande genere un fichier server.ts a la racine, ajoute un script serve:ssr dans package.json et configure le builder approprie. Le build produit deux dossiers dans dist/ : browser/ (fichiers statiques cote client) et server/ (entry point Node).

# Build production
ng build

# Structure typique du resultat
# dist/mon-app/
#   ├── browser/        ← assets statiques (servi par Nginx)
#   ├── server/         ← bundle Node SSR (servi par PM2)
#   └── prerendered-routes.json

Sur le serveur, clonez le projet, installez les dependances et lancez le build. Faites toujours le build sur la machine de production (ou un environnement strictement equivalent) pour eviter les ecarts de versions Node.

# Sur le serveur, en tant qu'utilisateur angularapp
sudo -iu angularapp
cd /home/angularapp
git clone https://github.com/votre-org/mon-app.git
cd mon-app

# Installation des dependances
npm ci

# Build production
npm run build

# Test rapide du serveur SSR
node dist/mon-app/server/server.mjs

Si le serveur ecoute correctement sur le port 4000, vous pouvez quitter et passer a PM2.

Installer et configurer PM2

PM2 est un gestionnaire de processus Node.js qui apporte plusieurs choses essentielles : redemarrage automatique sur crash, mode cluster pour exploiter plusieurs cores, gestion des logs avec rotation, et integration native avec systemd pour survivre aux reboots.

# Installation globale
sudo npm install -g pm2

# Verification
pm2 --version

Plutot que de lancer PM2 a la main, declarez l'application dans un fichier ecosystem.config.js. Ce fichier devient la source unique de verite pour les variables d'environnement, le mode d'execution, le nombre d'instances et les chemins de logs.

// /home/angularapp/mon-app/ecosystem.config.js
module.exports = {
  apps: [{
    name: 'angular-ssr',
    script: './dist/mon-app/server/server.mjs',
    instances: 'max',           // Une instance par CPU
    exec_mode: 'cluster',        // Mode cluster pour le load balancing
    env: {
      NODE_ENV: 'production',
      PORT: 4000
    },
    max_memory_restart: '500M',  // Restart si depasse 500 Mo
    error_file: '/var/log/angular-ssr/error.log',
    out_file: '/var/log/angular-ssr/out.log',
    time: true                   // Timestamp dans les logs
  }]
};

Creez le dossier de logs et lancez l'application :

# Creation du dossier de logs
sudo mkdir -p /var/log/angular-ssr
sudo chown angularapp:angularapp /var/log/angular-ssr

# Demarrage
pm2 start ecosystem.config.js

# Verification de l'etat
pm2 status
pm2 logs angular-ssr --lines 50

Pour que PM2 redemarre automatiquement au boot du serveur, generez le script systemd :

# Generation du script de demarrage
pm2 startup systemd -u angularapp --hp /home/angularapp

# La commande affiche une ligne sudo a copier-coller, puis :
pm2 save
Verification : redemarrez le serveur (`sudo reboot`). Apres reconnexion, `pm2 status` doit montrer l'application active sans intervention manuelle.

Configurer Nginx en reverse proxy

Nginx joue trois roles : terminer le TLS, servir directement les fichiers statiques (plus rapide que Node) et faire passer les requetes dynamiques au cluster PM2. Cette separation est ce qui permet d'absorber un trafic important sans saturer Node.js.

# Installation
sudo apt install -y nginx

# Verification
sudo systemctl status nginx

Creez un virtual host dedie a l'application :

# /etc/nginx/sites-available/angular-ssr
upstream angular_ssr {
    server 127.0.0.1:4000;
    keepalive 64;
}

server {
    listen 80;
    server_name votre-domaine.com www.votre-domaine.com;

    # Logs dedies
    access_log /var/log/nginx/angular-ssr.access.log;
    error_log /var/log/nginx/angular-ssr.error.log;

    # Fichiers statiques servis directement
    root /home/angularapp/mon-app/dist/mon-app/browser;

    # Cache long pour les assets versionnes
    location ~* \.(js|css|woff2|webp|svg|jpg|png)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        try_files $uri @ssr;
    }

    # Tout le reste passe au SSR
    location / {
        try_files $uri @ssr;
    }

    location @ssr {
        proxy_pass http://angular_ssr;
        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;
        proxy_read_timeout 30s;
    }
}

Activez le site et rechargez Nginx :

# Activation du site
sudo ln -s /etc/nginx/sites-available/angular-ssr /etc/nginx/sites-enabled/

# Test de la configuration
sudo nginx -t

# Reload sans coupure
sudo systemctl reload nginx

Visitez le domaine : Nginx doit servir la page generee par SSR. Pour aller plus loin sur la securisation Nginx, l'article Nginx : configuration et securisation couvre les headers HTTPS et la durcissement.

Optimiser cache et fichiers statiques

Une app Angular SSR genere beaucoup de fichiers statiques avec des hash de contenu (`main-XXXXX.js`, `styles-XXXXX.css`). Ces fichiers ne changent jamais une fois deployes : c'est le cas typique d'usage du header Cache-Control: immutable.

# Bonus : compression Brotli/Gzip dans Nginx
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;

# Si module brotli disponible
brotli on;
brotli_types text/plain text/css application/json application/javascript;

Pour le HTML genere par SSR (qui peut contenir des donnees personnalisees), ajoutez un cache court via Nginx pour absorber les pics :

# Dans le bloc location @ssr
proxy_cache_path /var/cache/nginx/ssr levels=1:2 keys_zone=ssr_cache:10m max_size=500m inactive=5m;

location @ssr {
    proxy_pass http://angular_ssr;
    proxy_cache ssr_cache;
    proxy_cache_valid 200 1m;
    proxy_cache_use_stale error timeout updating http_500;
    proxy_cache_lock on;
    add_header X-Cache-Status $upstream_cache_status;
    # ... headers proxy_set_header habituels
}

Verifiez le statut cache via curl : la valeur de X-Cache-Status doit passer de MISS a HIT apres la premiere requete.

curl -I https://votre-domaine.com/
# X-Cache-Status: MISS

curl -I https://votre-domaine.com/
# X-Cache-Status: HIT
Attention : si vos pages SSR contiennent des donnees specifiques a l'utilisateur (panier, session), excluez ces routes du cache via `proxy_cache_bypass` ou `proxy_no_cache`.

Monitorer PM2 et les logs

Une fois l'application en production, le monitoring devient prioritaire. PM2 propose plusieurs outils integres tres utiles avant meme d'installer un APM externe.

# Dashboard temps reel (CPU, RAM, requetes)
pm2 monit

# Liste detaillee
pm2 list

# Logs en streaming
pm2 logs angular-ssr

# Logs derniere heure uniquement
pm2 logs angular-ssr --lines 200 --raw

Pour la rotation automatique des logs (sans quoi le disque se remplit en quelques semaines) :

# Installation du module
pm2 install pm2-logrotate

# Configuration
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 14
pm2 set pm2-logrotate:compress true

Cote Nginx, surveillez les codes d'erreur 5xx qui indiquent un probleme cote SSR :

# Nombre de 5xx aujourd'hui
grep "$(date '+%d/%b/%Y')" /var/log/nginx/angular-ssr.access.log | awk '{print $9}' | grep -c "^5"

# Top 10 des URLs en erreur
awk '$9 ~ /^5/ {print $7}' /var/log/nginx/angular-ssr.access.log | sort | uniq -c | sort -rn | head

Pour un suivi durable, l'article monitoring serveur Linux detaille comment combiner journalctl et logs applicatifs.

Deploiement zero-downtime

Avec PM2 en mode cluster, vous pouvez deployer une nouvelle version sans coupure. Le secret est la commande pm2 reload : elle redemarre les workers un par un, ce qui maintient toujours au moins une instance disponible pendant la transition.

#!/usr/bin/env bash
# /home/angularapp/deploy.sh
set -euo pipefail

APP_DIR="/home/angularapp/mon-app"
LOG_FILE="/var/log/angular-ssr/deploy.log"

log() {
  printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a "$LOG_FILE"
}

cd "$APP_DIR"

log "Pull du code"
git pull --ff-only

log "Installation des dependances"
npm ci --omit=dev=false

log "Build production"
npm run build

log "Reload PM2 (zero-downtime)"
pm2 reload angular-ssr

log "Deploiement termine"

Rendez le script executable et associez-le a un alias ou a un webhook GitHub :

chmod +x /home/angularapp/deploy.sh

# Test
/home/angularapp/deploy.sh

Pour aller plus loin, branchez ce script sur un pipeline CI/CD (voir l'article dedie sur GitHub Actions). Le principe : push sur main → action sur GitHub → execution distante via SSH du script `deploy.sh`.

Astuce production : testez toujours `pm2 reload` une fois apres le premier deploiement pour valider que les workers redemarrent proprement. Si une instance crash, PM2 garde l'ancienne tant que la nouvelle n'est pas prete.

Conclusion

Deployer Angular SSR sur un serveur Linux n'est pas plus complique qu'une SPA classique, a condition d'avoir le bon decoupage : Nginx en frontale pour le TLS et les statiques, PM2 en cluster pour le rendu Node, et une procedure de build/deploy reproductible.

Cette architecture coche toutes les cases d'une production solide : performance grace au cache Nginx et au mode cluster PM2, resilience grace aux redemarrages automatiques, observabilite grace aux logs centralises et zero-downtime grace au `pm2 reload`. Elle reste simple a faire evoluer : passer de 1 a 4 instances PM2 ne demande qu'une ligne de config.

Si vous demarrez aujourd'hui, suivez l'ordre de cet article : preparez le serveur, faites un build local pour valider, puis ajoutez Nginx une fois que PM2 sert correctement la page sur le port 4000. C'est la sequence la plus rapide pour atteindre une production stable.

Partager