Deployer une Application Next.js avec Docker et CI/CD en Production

Ce tutoriel vous guide pas a pas pour containeriser une application Next.js avec Docker, mettre en place un pipeline CI/CD avec GitHub Actions, et deployer automatiquement en production sur un VPS Linux. A la fin, chaque push sur votre branche principale declenchera un deploiement automatique.
Objectifs d'apprentissage
A la fin de ce tutoriel, vous serez capable de :
- Ecrire un Dockerfile optimise multi-stage pour Next.js
- Configurer Docker Compose pour le developpement local et la production
- Mettre en place un pipeline CI/CD complet avec GitHub Actions
- Deployer automatiquement sur un serveur VPS via SSH
- Gerer les variables d'environnement de maniere securisee
- Configurer un reverse proxy Nginx avec SSL
Prerequis
Avant de commencer, assurez-vous d'avoir :
- Node.js 20+ installe localement
- Docker Desktop installe et fonctionnel (installer Docker)
- Un compte GitHub avec un depot contenant une application Next.js
- Un VPS Linux (Ubuntu 22.04+ recommande) avec acces SSH
- Un nom de domaine pointe vers votre VPS (optionnel mais recommande)
- Des connaissances de base en Next.js et en ligne de commande
Ce que vous allez construire
Nous allons mettre en place une infrastructure de deploiement complete :
- Dockerfile multi-stage — Image Docker optimisee (~150 Mo au lieu de ~1 Go)
- Docker Compose — Orchestration des services (app + base de donnees + cache)
- Pipeline CI/CD — Tests automatiques, build et deploiement via GitHub Actions
- Reverse proxy — Nginx avec certificat SSL Let's Encrypt
- Monitoring — Healthchecks et logs structures
Etape 1 : Preparer le projet Next.js
Commencez par verifier que votre projet Next.js fonctionne correctement en local.
# Verifier la version de Node.js
node --version # v20.x.x requis
# Installer les dependances
npm install
# Tester le build de production
npm run build
# Verifier que le serveur demarre
npm startSi vous n'avez pas encore de projet Next.js, creez-en un rapidement avec npx create-next-app@latest mon-app --typescript. Ce tutoriel fonctionne avec Next.js 14 et 15.
Ajouter un script de healthcheck
Creez un fichier app/api/health/route.ts pour que Docker puisse verifier l'etat de votre application :
// app/api/health/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
}Ce endpoint sera utilise par Docker et votre pipeline CI/CD pour valider que l'application fonctionne.
Etape 2 : Ecrire le Dockerfile multi-stage
Le secret d'une image Docker performante pour Next.js est le build multi-stage. Cela permet de separer les outils de build (qui sont lourds) de l'image finale (qui est legere).
Creez un fichier Dockerfile a la racine de votre projet :
# =============================================================================
# Etape 1 : Image de base avec les dependances
# =============================================================================
FROM node:20-alpine AS base
# Installer libc6-compat pour les modules natifs
RUN apk add --no-cache libc6-compat
WORKDIR /app
# =============================================================================
# Etape 2 : Installer les dependances
# =============================================================================
FROM base AS deps
# Copier les fichiers de dependances
COPY package.json package-lock.json* ./
# Installer toutes les dependances (y compris devDependencies pour le build)
RUN npm ci
# =============================================================================
# Etape 3 : Build de l'application
# =============================================================================
FROM base AS builder
WORKDIR /app
# Copier les dependances installees
COPY --from=deps /app/node_modules ./node_modules
# Copier le code source
COPY . .
# Desactiver la telemetrie Next.js pendant le build
ENV NEXT_TELEMETRY_DISABLED=1
# Build de production
RUN npm run build
# =============================================================================
# Etape 4 : Image de production (legere)
# =============================================================================
FROM node:20-alpine AS runner
WORKDIR /app
# Mode production
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Creer un utilisateur non-root pour la securite
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copier les fichiers publics
COPY --from=builder /app/public ./public
# Copier le build standalone de Next.js
# Le mode standalone copie uniquement les fichiers necessaires
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Utiliser l'utilisateur non-root
USER nextjs
# Exposer le port
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Healthcheck Docker
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
# Demarrer l'application
CMD ["node", "server.js"]Configurer le mode standalone dans Next.js
Pour que le Dockerfile fonctionne, vous devez activer le output standalone dans votre configuration Next.js :
// next.config.js (ou next.config.mjs)
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
};
module.exports = nextConfig;Le mode standalone est essentiel pour Docker. Sans lui, l'image finale necessitera tout le dossier node_modules, ce qui augmentera considerablement sa taille. Avec standalone, Next.js copie uniquement les fichiers necessaires a l'execution.
Creer le fichier .dockerignore
Creez un fichier .dockerignore pour eviter de copier des fichiers inutiles dans l'image :
# .dockerignore
node_modules
.next
.git
.gitignore
*.md
docker-compose*.yml
.env*.local
.vscode
.idea
coverage
.huskyTester le build Docker en local
# Construire l'image
docker build -t mon-app-nextjs .
# Verifier la taille de l'image
docker images mon-app-nextjs
# REPOSITORY TAG SIZE
# mon-app-nextjs latest ~150MB
# Lancer le conteneur
docker run -p 3000:3000 mon-app-nextjs
# Tester dans un autre terminal
curl http://localhost:3000/api/healthSi vous obtenez {"status":"healthy"}, votre image Docker fonctionne correctement. La taille devrait etre entre 130 et 200 Mo selon vos dependances.
Etape 3 : Configurer Docker Compose
Docker Compose permet d'orchestrer plusieurs services. Nous allons configurer deux fichiers : un pour le developpement et un pour la production.
Docker Compose pour le developpement
Creez docker-compose.dev.yml :
# docker-compose.dev.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
target: deps # Utiliser seulement l'etape des dependances
command: npm run dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules # Exclure node_modules du volume
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:Docker Compose pour la production
Creez docker-compose.prod.yml :
# docker-compose.prod.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env.production
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
start_period: 40s
retries: 3
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
image: postgres:16-alpine
restart: unless-stopped
env_file:
- .env.production
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
memory: 256M
cache:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
deploy:
resources:
limits:
memory: 128M
volumes:
postgres_data:
redis_data:Lancer l'environnement de developpement
# Demarrer tous les services
docker compose -f docker-compose.dev.yml up -d
# Voir les logs
docker compose -f docker-compose.dev.yml logs -f app
# Arreter les services
docker compose -f docker-compose.dev.yml downEtape 4 : Configurer le pipeline CI/CD avec GitHub Actions
C'est la partie la plus importante. Nous allons creer un pipeline qui :
- Teste le code a chaque pull request
- Build l'image Docker
- Deploie automatiquement sur le VPS a chaque merge sur
main
Creer le workflow principal
Creez le fichier .github/workflows/deploy.yml :
# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# =====================================================
# Job 1 : Linting et tests
# =====================================================
test:
name: Tests et qualite
runs-on: ubuntu-latest
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Installer les dependances
run: npm ci
- name: Linting
run: npm run lint
- name: Tests unitaires
run: npm test -- --passWithNoTests
- name: Build de verification
run: npm run build
# =====================================================
# Job 2 : Build et push de l'image Docker
# =====================================================
build:
name: Build Docker
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Connexion au registre GitHub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extraire les metadonnees Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=raw,value=latest
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build et push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# =====================================================
# Job 3 : Deploiement sur le VPS
# =====================================================
deploy:
name: Deploiement production
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment:
name: production
url: https://${{ vars.DOMAIN_NAME }}
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Deployer via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
# Se placer dans le repertoire du projet
cd /opt/apps/mon-app
# Se connecter au registre GitHub
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
# Telecharger la derniere image
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Mettre a jour le service avec zero downtime
docker compose -f docker-compose.prod.yml up -d --no-deps --wait app
# Nettoyer les anciennes images
docker image prune -f
# Verifier le healthcheck
sleep 10
curl -f http://localhost:3000/api/health || exit 1
- name: Notification de succes
if: success()
run: echo "Deploiement reussi sur ${{ vars.DOMAIN_NAME }}"
- name: Notification d'echec
if: failure()
run: echo "Echec du deploiement - verifier les logs"Configurer les secrets GitHub
Rendez-vous dans Settings > Secrets and variables > Actions de votre depot GitHub et ajoutez :
| Secret | Description | Exemple |
|---|---|---|
VPS_HOST | Adresse IP ou domaine du VPS | 203.0.113.50 |
VPS_USER | Utilisateur SSH | deploy |
VPS_SSH_KEY | Cle privee SSH | Contenu de ~/.ssh/id_ed25519 |
Et dans les Variables :
| Variable | Description | Exemple |
|---|---|---|
DOMAIN_NAME | Nom de domaine | monapp.example.com |
Ne stockez jamais vos cles SSH ou tokens dans le code source. Utilisez exclusivement les secrets GitHub pour les informations sensibles. Generez une cle SSH dediee au deploiement avec ssh-keygen -t ed25519 -C "deploy@github-actions".
Etape 5 : Preparer le serveur VPS
Connectez-vous a votre VPS et preparez l'environnement.
Installer Docker sur le VPS
# Mise a jour du systeme
sudo apt update && sudo apt upgrade -y
# Installer Docker via le script officiel
curl -fsSL https://get.docker.com | sudo sh
# Ajouter l'utilisateur au groupe docker
sudo usermod -aG docker $USER
# Installer Docker Compose (inclus dans Docker Engine moderne)
docker compose version
# Redemarrer la session pour appliquer les permissions
exit
# Reconnectez-vousCreer la structure du projet
# Creer le repertoire de l'application
sudo mkdir -p /opt/apps/mon-app
sudo chown $USER:$USER /opt/apps/mon-app
cd /opt/apps/mon-app
# Creer le fichier d'environnement production
cat > .env.production << 'EOF'
NODE_ENV=production
DATABASE_URL=postgresql://postgres:VOTRE_MOT_DE_PASSE_FORT@db:5432/myapp
REDIS_URL=redis://cache:6379
POSTGRES_USER=postgres
POSTGRES_PASSWORD=VOTRE_MOT_DE_PASSE_FORT
POSTGRES_DB=myapp
EOF
# Proteger le fichier
chmod 600 .env.productionCopier le fichier Docker Compose
# Copier docker-compose.prod.yml sur le serveur depuis votre machine locale
scp docker-compose.prod.yml deploy@VOTRE_VPS:/opt/apps/mon-app/Creer un utilisateur dedie au deploiement
# Creer l'utilisateur deploy
sudo adduser --disabled-password deploy
sudo usermod -aG docker deploy
# Configurer la cle SSH pour le deploiement
sudo mkdir -p /home/deploy/.ssh
sudo cp ~/.ssh/authorized_keys /home/deploy/.ssh/
# Ajoutez la cle publique generee pour GitHub Actions
echo "VOTRE_CLE_PUBLIQUE_ED25519" | sudo tee -a /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keysEtape 6 : Configurer Nginx comme reverse proxy
Nginx se place devant votre application Next.js pour gerer le SSL, le cache et la compression.
Installer Nginx et Certbot
# Installer Nginx
sudo apt install -y nginx
# Installer Certbot pour Let's Encrypt
sudo apt install -y certbot python3-certbot-nginxConfigurer le virtual host
Creez le fichier de configuration Nginx :
# /etc/nginx/sites-available/mon-app
upstream nextjs_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name monapp.example.com;
# Redirection vers HTTPS (sera configure par Certbot)
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
server_name monapp.example.com;
# Les certificats SSL seront ajoutes par Certbot
# ssl_certificate /etc/letsencrypt/live/monapp.example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/monapp.example.com/privkey.pem;
# En-tetes de securite
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# Compression gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript
application/xml+rss application/atom+xml image/svg+xml;
# Cache des fichiers statiques de Next.js
location /_next/static {
proxy_pass http://nextjs_upstream;
proxy_cache_valid 60m;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Fichiers publics statiques
location /images {
proxy_pass http://nextjs_upstream;
proxy_cache_valid 60m;
add_header Cache-Control "public, max-age=86400";
}
# Proxy vers Next.js
location / {
proxy_pass http://nextjs_upstream;
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}Activer le site et le SSL
# Activer le site
sudo ln -s /etc/nginx/sites-available/mon-app /etc/nginx/sites-enabled/
# Verifier la configuration
sudo nginx -t
# Recharger Nginx
sudo systemctl reload nginx
# Obtenir le certificat SSL avec Certbot
sudo certbot --nginx -d monapp.example.com --non-interactive --agree-tos -m votre@email.com
# Verifier le renouvellement automatique
sudo certbot renew --dry-runCertbot modifiera automatiquement votre configuration Nginx pour ajouter les certificats SSL. Le renouvellement est automatique via un timer systemd.
Etape 7 : Deploiement zero-downtime
Pour eviter les interruptions lors des mises a jour, nous allons configurer un deploiement progressif.
Script de deploiement avance
Creez scripts/deploy.sh sur votre VPS :
#!/bin/bash
# scripts/deploy.sh - Deploiement avec zero downtime
set -euo pipefail
APP_DIR="/opt/apps/mon-app"
HEALTH_URL="http://localhost:3000/api/health"
MAX_RETRIES=30
RETRY_INTERVAL=2
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
check_health() {
curl -sf "$HEALTH_URL" > /dev/null 2>&1
}
cd "$APP_DIR"
log "Demarrage du deploiement..."
# Telecharger la nouvelle image
log "Telechargement de la nouvelle image..."
docker compose -f docker-compose.prod.yml pull app
# Demarrer le nouveau conteneur
log "Demarrage du nouveau conteneur..."
docker compose -f docker-compose.prod.yml up -d --no-deps app
# Attendre que le healthcheck passe
log "Verification du healthcheck..."
retries=0
until check_health; do
retries=$((retries + 1))
if [ "$retries" -ge "$MAX_RETRIES" ]; then
log "ERREUR: Le healthcheck a echoue apres $MAX_RETRIES tentatives"
log "Rollback en cours..."
docker compose -f docker-compose.prod.yml rollback app 2>/dev/null || true
exit 1
fi
log "En attente du healthcheck... ($retries/$MAX_RETRIES)"
sleep "$RETRY_INTERVAL"
done
log "Healthcheck OK"
# Nettoyer les anciennes images
docker image prune -f
log "Deploiement termine avec succes"# Rendre le script executable
chmod +x /opt/apps/mon-app/scripts/deploy.shEtape 8 : Monitoring et logs
Configurer les logs structures
Ajoutez la configuration de logging dans votre application Next.js :
// lib/logger.ts
type LogLevel = "info" | "warn" | "error" | "debug";
interface LogEntry {
level: LogLevel;
message: string;
timestamp: string;
[key: string]: unknown;
}
function log(level: LogLevel, message: string, meta?: Record<string, unknown>) {
const entry: LogEntry = {
level,
message,
timestamp: new Date().toISOString(),
...meta,
};
const output = JSON.stringify(entry);
if (level === "error") {
console.error(output);
} else if (level === "warn") {
console.warn(output);
} else {
console.log(output);
}
}
export const logger = {
info: (msg: string, meta?: Record<string, unknown>) => log("info", msg, meta),
warn: (msg: string, meta?: Record<string, unknown>) => log("warn", msg, meta),
error: (msg: string, meta?: Record<string, unknown>) => log("error", msg, meta),
debug: (msg: string, meta?: Record<string, unknown>) => log("debug", msg, meta),
};Commandes utiles pour le monitoring
# Voir les logs en temps reel
docker compose -f docker-compose.prod.yml logs -f app
# Voir les statistiques des conteneurs
docker stats
# Verifier l'etat des conteneurs
docker compose -f docker-compose.prod.yml ps
# Verifier l'utilisation disque de Docker
docker system df
# Nettoyer les ressources inutilisees
docker system prune -fAjouter un healthcheck avance
Enrichissez votre endpoint /api/health pour inclure plus d'informations :
// app/api/health/route.ts
import { NextResponse } from "next/server";
export async function GET() {
const healthData = {
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
unit: "MB",
},
version: process.env.npm_package_version || "unknown",
node: process.version,
};
return NextResponse.json(healthData);
}Etape 9 : Securiser l'ensemble
Variables d'environnement
Creez un fichier .env.example pour documenter les variables requises sans exposer les valeurs :
# .env.example - Variables d'environnement requises
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db:5432/dbname
REDIS_URL=redis://cache:6379
# Base de donnees
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changez_moi
POSTGRES_DB=myapp
# Application
NEXTAUTH_SECRET=generez_un_secret_fort
NEXTAUTH_URL=https://monapp.example.comBonnes pratiques de securite
Voici les points essentiels a respecter :
- Utilisateur non-root dans le conteneur (deja configure dans le Dockerfile)
- Secrets GitHub pour toutes les informations sensibles
- Certificat SSL via Let's Encrypt (renouvellement automatique)
- En-tetes de securite dans Nginx (HSTS, X-Frame-Options, etc.)
- Limites de ressources dans Docker Compose (memoire, CPU)
- Logs structures pour la detection d'anomalies
Changez toujours les mots de passe par defaut. Utilisez openssl rand -base64 32 pour generer des secrets forts. Ne repoussez jamais les fichiers .env dans votre depot Git.
Tester votre pipeline complet
Voici comment verifier que tout fonctionne de bout en bout :
1. Test local avec Docker
# Build et demarrage
docker compose -f docker-compose.dev.yml up --build -d
# Verifier les logs
docker compose -f docker-compose.dev.yml logs -f
# Tester le healthcheck
curl http://localhost:3000/api/health2. Test du pipeline CI/CD
# Creer une branche de test
git checkout -b test/cicd-pipeline
# Faire un changement mineur
echo "// test" >> lib/logger.ts
# Commit et push
git add . && git commit -m "test: verify CI/CD pipeline"
git push -u origin test/cicd-pipeline
# Creer une pull request sur GitHub
gh pr create --title "Test CI/CD pipeline" --body "Verification du pipeline"3. Verifier le deploiement
# Apres le merge sur main, verifier le deploiement
curl https://monapp.example.com/api/health
# Reponse attendue :
# {"status":"healthy","timestamp":"...","uptime":42,"memory":{"used":85,"total":128,"unit":"MB"}}Depannage
Le build Docker echoue
| Probleme | Solution |
|---|---|
COPY failed: file not found | Verifiez que .dockerignore n'exclut pas les fichiers necessaires |
npm ci echoue | Assurez-vous que package-lock.json est present et a jour |
| Out of memory pendant le build | Augmentez la memoire Docker Desktop ou ajoutez --max-old-space-size=4096 |
Le pipeline GitHub Actions echoue
| Probleme | Solution |
|---|---|
| Permission denied (SSH) | Verifiez que la cle SSH est correctement configuree dans les secrets |
| Image push refused | Verifiez les permissions packages: write dans le workflow |
| Healthcheck timeout | Augmentez start-period et verifiez les logs de l'application |
Le deploiement ne fonctionne pas
# Verifier les logs du conteneur
docker compose -f docker-compose.prod.yml logs app --tail 50
# Verifier que les ports ne sont pas utilises
sudo ss -tulnp | grep 3000
# Redemarrer les services
docker compose -f docker-compose.prod.yml restart
# Reconstruire completement
docker compose -f docker-compose.prod.yml up -d --build --force-recreateProchaines etapes
Maintenant que votre pipeline est en place, voici comment l'ameliorer :
- Ajouter des tests E2E avec Playwright dans le pipeline CI
- Configurer des notifications Slack ou Discord pour les deploiements
- Mettre en place un CDN (Cloudflare) devant Nginx pour le cache global
- Ajouter du monitoring applicatif avec Sentry ou Datadog
- Implementer des deploiements blue/green pour un zero-downtime garanti
- Configurer des backups automatiques de la base de donnees PostgreSQL
Conclusion
Vous disposez maintenant d'une infrastructure de deploiement complete et professionnelle pour votre application Next.js :
- Docker multi-stage pour des images legeres et securisees
- Docker Compose pour l'orchestration des services
- GitHub Actions pour l'integration et le deploiement continu
- Nginx + SSL pour un reverse proxy securise
- Monitoring avec des healthchecks et des logs structures
Cette architecture est utilisee en production par de nombreuses entreprises et startups. Elle est fiable, reproductible et facile a maintenir. Chaque push sur main declenche automatiquement un deploiement verifie par des healthchecks.
Le plus important est de commencer simple et d'iterer. Deployez d'abord une version basique, puis ajoutez progressivement les couches de monitoring, de securite et d'optimisation.
Discutez de votre projet avec nous
Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.
Trouvons les meilleures solutions pour vos besoins.
Articles connexes

Construire un Agent IA Autonome avec Agentic RAG et Next.js
Apprenez a construire un agent IA qui decide de maniere autonome quand et comment recuperer des informations depuis des bases de donnees vectorielles. Un guide pratique complet avec Vercel AI SDK et Next.js, accompagne d'exemples executables.

Guide d'Integration de Chatbot IA : Construire des Interfaces Conversationnelles Intelligentes
Un guide complet pour integrer des chatbots IA dans vos applications en utilisant OpenAI, Anthropic Claude et ElevenLabs. Apprenez a construire des chatbots textuels et vocaux avec Next.js.

Construire un chatbot RAG avec Supabase pgvector et Next.js
Apprenez à construire un chatbot IA qui répond aux questions en utilisant vos propres données. Ce tutoriel couvre les embeddings vectoriels, la recherche sémantique et le RAG avec Supabase et Next.js.