Vercel coûte cher dès que votre site dépasse les 100 000 visites mensuelles. Les serveurs de déploiement coûtent à partir de 5 €/mois et sont capables d'héberger 5 à 10 sites Next.js sans broncher. Voici le guide complet, testé et utilisé en production pour Romdev.
Pré-requis
- Un serveur de déploiement (Starter ou plus, Debian 12 ou Ubuntu 22.04)
- Un nom de domaine pointé vers l'IP du serveur
- Une app Next.js 14 en TypeScript prête à déployer
- Notions de base SSH + ligne de commande Linux
Étape 1 — Sécuriser le serveur
Connexion SSH initiale en root, puis création d'un utilisateur dédié, désactivation du login root, mise en place d'UFW (firewall) et de Fail2ban pour bloquer les attaques par brute force.
- Créer un user : `adduser deploy && usermod -aG sudo deploy`
- Désactiver le root SSH : `PermitRootLogin no` dans `/etc/ssh/sshd_config`
- UFW : `ufw allow 22 && ufw allow 80 && ufw allow 443 && ufw enable`
- Fail2ban : `apt install fail2ban` (jail SSH actif par défaut)
Étape 2 — Installer Docker + Docker Compose
Toujours via le script officiel Docker plutôt que les paquets APT, qui sont souvent en retard de version.
- Installer Docker : `curl -fsSL https://get.docker.com | sh`
- Ajouter votre user au groupe docker : `usermod -aG docker deploy`
- Vérifier : `docker compose version` (v2 ou +)
Étape 3 — Dockerfile multi-stage pour Next.js
Le secret d'un build Next.js efficace en Docker : un multi-stage qui sépare les dépendances de la build et du runtime. Image finale légère (~120 Mo), démarrage rapide, et standalone output activé dans `next.config.js`.
Étape 4 — docker-compose.yml minimal
Un service `app` pour Next.js, un service `nginx` qui sert de reverse proxy, et un network bridge partagé pour les faire communiquer. Variables d'env dans un `.env` à la racine.
Étape 5 — Configuration Nginx
Nginx écoute sur 80 et 443, redirige tout HTTP vers HTTPS, et fait du reverse proxy vers `http://app:3000` en interne au réseau Docker. On ajoute aussi les headers de sécurité essentiels et la compression Brotli.
- Reverse proxy avec `proxy_pass http://app:3000;`
- Headers de sécurité : `Strict-Transport-Security`, `X-Content-Type-Options`, `X-Frame-Options`
- Cache statique : `expires 30d` sur `/_next/static/`
- Compression : `gzip on;` + `brotli on;` si module installé
Étape 6 — HTTPS avec Certbot
Deux approches : Certbot standalone (arrêter temporairement Nginx) ou Certbot avec plugin Nginx (plus complexe à containeriser). Pour rester simple en Docker, on installe Certbot sur l'hôte et on monte le dossier `/etc/letsencrypt` dans le container Nginx.
- `docker compose stop nginx`
- `apt install certbot && certbot certonly --standalone -d romdev.cloud -d www.romdev.cloud`
- Monter le volume dans `docker-compose.yml` : `- /etc/letsencrypt:/etc/letsencrypt:ro`
- Activer le bloc HTTPS dans `default.conf` et `docker compose up -d`
- Cron de renouvellement : `0 3 * * * certbot renew --quiet && docker compose restart nginx`
Étape 7 — CI/CD avec GitHub Actions
Workflow simple : à chaque push sur `main`, GitHub Actions se connecte en SSH au serveur, fait un `git pull` et un `docker compose up -d --build`. Pas besoin de registry Docker privé pour démarrer.
Monitoring minimum
- UptimeRobot ou Better Stack pour la disponibilité externe (gratuit jusqu'à 50 monitors)
- Logs : `docker compose logs -f app` et `docker compose logs -f nginx`
- Métriques basiques : `htop` + `docker stats`
- Alertes : webhook Discord si UptimeRobot détecte un down
Coût total
Cette config tourne en production pour Romdev depuis 2024 sans incident majeur. Si vous voulez le repo template prêt à cloner, écrivez-moi : je vous l'envoie gratuitement.