Réalisations
Blog
arrowPrendre rendez-vous
illustration de fond

19/03/2025

Déployer Payload CMS avec Next.js : Guide complet du local à la production (VPS, Docker & HTTPS)

Découvrez comment mettre en place un CMS moderne avec Payload et Next.js, de l'installation locale jusqu'au déploiement sécurisé sur un VPS avec Docker, Nginx et certificat SSL. Suivez notre tutoriel pas à pas pour maîtriser le déploiement, la gestion de contenu et l'automatisation du versionning avec Git.

Découvre comment mettre en place un CMS moderne avec Payload et Next.js, de l'installation locale jusqu'au déploiement sécurisé sur un VPS avec Docker, Nginx et certificat SSL. Suis notre tutoriel pas à pas pour maîtriser le déploiement, la gestion de contenu et l'automatisation du versionning avec Git.

Sommaire

  • Lancer Payload en local
  • Créer son premier post type sur Payload
  • Initialiser le repo Git pour le versionning
  • Configuration de Docker
  • Configurer le VPS
  • Configurer les DNS
  • Créer un certificat SSL pour passer en HTTPS

Lancer Payload en local

1. Pré-requis : Installer les outils de base

  • Installer Homebrew (le gestionnaire de paquets sur macOS) https://brew.sh/
  • Installer Node.js et npm via Homebrew :
1 brew install node
  • Vérifie les versions installées :
1 2 node -v npm -v

2. Installer & lancer MongoDB via Brew

  • Installer MongoDB Community Edition :
(Exemple : MongoDB 8.0 – assure-toi d’adapter la commande selon la version souhaitée)
1 2 brew tap mongodb/brew brew install mongodb-community@8.0
  • Lancer MongoDB avec Brew Services :
1 brew services start mongodb-community@8.0
  • Vérifie que MongoDB tourne :
1 brew services list
Mongo sera accessible sur mongodb://localhost:27017 (par défaut).

Documentation officielle :

Install MongoDB sur macOS

3. Créer le projet Next.js

Dans ton dossier de travail, exécute :

1 npx create-payload-app

Réponds aux questions :

  • Nom du projet
  • Choix de la base de données (MongoDB)
  • Choix du template (par exemple blank si tu veux un projet minimal)

4. Installer l’éditeur de code

Tu peux utiliser Visual Studio Code, par exemple :

Télécharger VSCode

5. Lancer le projet en local

  • Ouvre le dossier de projet avec VSCode.
  • Ouvre le terminal (raccourci : Cmd + J).
  • Installe les dépendances :
1 npm i
  • Lance le projet :
1 npm run dev

6. Premiers pas sur l’interface payload

  • Clique sur “Go to Admin Panel”.
  • Crée ton compte admin.

Créer son premier type de contenu sur Payload

1. Créer la liste des Todo dans le back

Objectif : Créer un type de contenu “Todo” (une simple liste de tâches) que tu pourras afficher sur ton site et administrer depuis Payload.
  • Dans VSCode, localise le dossier src/collections.
  • Crée un fichier Todo.ts :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import type { CollectionConfig } from 'payload' export const Todo: CollectionConfig = { slug: 'todo', admin: { useAsTitle: 'Tâche', }, fields: [ { name: 'Tâche', type: 'text', required: true, }, ], }
  • Dans le fichier payload.config.ts (dossier src), ajoute la collection Todo :/
1 2 3 4 5 //avant: collections: [Users, Media], //après: collections: [Users, Media, Todo],
  • N’oublie pas d’importer Todo en haut du fichier payload.config.ts :
1 import { Todo } from './collections/Todo'
Une fois le projet relancé, tu verras apparaître ta nouvelle collection “Todo” dans l’admin.

2. Afficher la liste des Todo dans le front

  • Ouvre la page principale de ton site : src/app/(frontend)/page.tsx et modifie son contenu pour récupérer et afficher les tâches :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import { getPayload } from 'payload' import React from 'react' import config from '@/payload.config' import './styles.css' export const dynamic = 'force-dynamic' export default async function HomePage() { const payload = await getPayload({ config }); const Todos = await payload.find({ collection: 'todo', }) return ( <div> { Todos.docs?.map((todo) => ( <div key={todo.id}> <h2>{todo.Tâche}</h2> </div> )) } </div> ) }
Maintenant, chaque tâche créée dans Payload s’affichera sur la page d’accueil.

Initialise le Repo Git pour le versionning

1. Créer un compte sur GitHub

Créer un compte GitHub

2. Créer une clé SSH

1 ssh-keygen -t rsa -b 4096 -C "votre_email@example.com"
  • Lorsque l'invite te demande de spécifier un chemin de fichier pour la clé, appuis simplement sur Entrée pour accepter l'emplacement par défaut (~/.ssh/id_rsa).
  • Ensuite, choisis un mot de passe sécurisé pour la clé SSH ou appuie sur Entrée pour ignorer (optionnel mais recommandé)

3. Démarrer l'agent SSH

Lance l'agent SSH pour gérer la clé :

1 eval "$(ssh-agent -s)"

4. Ajouter la clé SSH à l'agent

Ajoute la clé privée à l'agent pour qu'elle soit utilisée automatiquement :

1 ssh-add ~/.ssh/id_rsa

5. Copier la clé SSH publique

1 cat ~/.ssh/id_rsa.pub

Sélectionnez et copiez le contenu affiché.

6. Ajouter la clé SSH à GitHub (ou GitLab, etc.)

  • Dans GitHub : Settings > SSH and GPG keys > New SSH key.
  • Colle la clé publique, donne-lui un nom explicite (par ex. "VPS" ou "MacBook"), puis valide.

7. Tester la connexion

1 ssh -T git@github.com

Un message de bienvenue devrait s’afficher.

8. Créer un repo

  • Créer un repo : https://github.com/new
    • Choisis le nom du repo, la visibilité (privé ou public)…
    • Une fois créé, suis les instructions pour lier ton projet :
1 2 3 git remote add origin git@github.com:beease/payload-test.git git branch -M main git push -u origin main
  • Commit les changements:
1 2 3 git add . git commit -am "todo" git push
Bravo, tes modifications sont maintenant en ligne, les autres développeurs ayant accès au projet pourront mettre leur version à jour avec tes changements avec la commande git pull

Configuration de Docker

1. Configurer docker compose

  • À la racine du projet tu trouveras le fichier docker-compose.yml, il sert à gérer les conteneurs docker. Le template de base de payload inclut déjà une configuration. on va la remplacer par le code suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 services: payload: build: context: . volumes: - ./media:/app/media ports: - '3000:3000' depends_on: - mongo mongo: container_name: mongo image: mongo:latest restart: always environment: MONGO_INITDB_ROOT_USERNAME: username MONGO_INITDB_ROOT_PASSWORD: password ports: - "27017:27017" volumes: - mongodb_data:/data/db nginx: container_name: webserver restart: always image: nginx:latest ports: - '80:80' volumes: - ./nginx.conf:/etc/nginx/conf.d/nginx.conf:ro depends_on: - payload volumes: mongodb_data:

2. Configuration de l’image docker

  • Change le contenu du fichier Dockerfile à la racine du projet :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 FROM node:22-alpine AS builder WORKDIR /app COPY . . RUN npm install RUN npm run build:compile FROM node:22-alpine AS runner WORKDIR /app COPY . . COPY --from=builder /app/package-lock.json ./ COPY --from=builder /app/.next ./.next COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static RUN npm ci --omit=dev EXPOSE 3000 ENV PORT 3000 CMD ["sh", "-c", "npm run payload migrate && npm run build:generate && node server.js"]
(Ici, j’utilise Node 22 comme exemple. Adapte si besoin.)

3. Configuration du projet NextJs pour la prod

  • Dans le fichier next.config.mjs active le mode standalone :
1 2 3 4 5 6 7 8 import { withPayload } from '@payloadcms/next/withPayload' /** @type {import('next').NextConfig} */ const nextConfig = { output: "standalone", } export default withPayload(nextConfig, { devBundleServerPackages: false })
  • Dans le fichier package.json à la racine, rajoute ces lignes de script :
1 2 3 4 5 6 "scripts": { ... "build:compile": "next build --experimental-build-mode compile", "build:generate": "next build --experimental-build-mode generate", ... },

4. Configuration du serveur Web

  • Toujours à la racine, crée un nginx.conf :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 upstream payload { server payload:3000; } server { listen 80; listen [::]:80; server_name [domain] www.[domain]; server_tokens off; location / { proxy_pass http://payload; 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-Host $host; proxy_set_header X-Forwarded-Proto $scheme; } }
  • Une fois tout configuré, fais un commit et pousse sur ton repo.
1 2 3 git add . git commit -am "setup docker & nginx" git push

Configurer le VPS

Sur le VPS, Docker se chargera d’installer tout ce dont tu as besoin à l’intérieur des conteneurs. Il te suffit d’installer Git et Docker sur la machine hôte.

1. Installer Git

1 2 3 sudo apt update sudo apt install git -y git --version

2. Installer Docker

Suis la doc officielle de Docker :

Install Docker Engine

1 2 3 4 5 6 7 8 9 10 11 12 13 # Add Docker's official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # Add the repository to Apt sources: echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update
  • Installe les packages Docker :
1 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  • Teste l'installation :
1 sudo docker run hello-world

3. Créer une clé SSH Git sur ton VPS

Même principe que sur ta machine locale (voir section C), afin de pouvoir cloner ton repo en SSH.

4. Cloner le projet git

  • Sur GitHub, récupère l’URL de clonage SSH :
github-payload-test.png
  • Sur ton VPS, place-toi dans le dossier où tu veux cloner :
1 git clone git@github.com:MonCompte/mon-projet.git

5. Créer le fichier .env

1 2 cd mon-projet nano .env
  • écrire les variables d’environnements :
1 2 DATABASE_URI=mongodb://username:password@mongo:27017/payload?authSource=admin PAYLOAD_SECRET=[Clef secrète payload]

(Dans l’exemple : mongo correspond au nom du conteneur Mongo, défini dans docker-compose.yml.)

Pour sauvegarder et quitter Nano : Ctrl + O puis Ctrl + X (ou Cmd + S, Cmd + X sur Mac si SSH sous iTerm, etc.).

5. Lancer les conteneurs Docker

  • Crée les images Docker :
1 sudo docker compose build
  • Lance les conteneurs Docker :
1 sudo docker compose up
Le site est presque en ligne ! Manque plus qu’à configurer les DNS pour lier le nom de domaine à l’adresse physique du VPS`

Configurer les DNS

Dans la configuration DNS de ton nom de domaine, ajoute un enregistrement de type A pointant vers l’adresse IP publique de ton VPS :

Par exemple :

  • Type : A
  • Valeur : 123.456.789.000 (IP de ton VPS)
Tu peux alors accéder à ton interface admin via : http://mon-domaine.fr/admin

Créer un certificat SSL pour passer en HTTPS

1. Configuration Nginx de base pour HTTP :

  • Dans ton docker-compose.yml, ajoute (ou modifie) la config pour Nginx et Certbot :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 services: nginx: container_name: webserver restart: always image: nginx:latest ports: - '80:80' - '443:443' volumes: - ./nginx.conf:/etc/nginx/conf.d/nginx.conf:ro - ./certbot/www:/var/www/certbot/:ro - ./certbot/conf/:/etc/nginx/ssl/:ro depends_on: - payload entrypoint: "/bin/sh -c 'while :; do sleep 6h; nginx -s reload; done & nginx -g \"daemon off;\"'" certbot: restart: always image: certbot/certbot:latest volumes: - ./certbot/www/:/var/www/certbot/:rw - ./certbot/conf/:/etc/letsencrypt/:rw #entrypoint: "/bin/sh -c 'while :; do certbot renew; sleep 12h; done'"
  • Configure nginx.conf (version initiale pour la phase HTTP) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 server { listen 80; listen [::]:80; server_name [domain].fr www.[domain].fr; server_tokens off; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://[domain]$request_uri; } }
  • Commit et push.
  • Sur ton VPS git pull et redémarre docker compose :
1 2 git pull sudo docker compose down && sudo docker compose up

2. Générer le certificat avec Certbot

  • Teste d’abord en mode dry-run : (remplace le nom de domaine par le tiens) :
1 2 3 sudo docker compose run --rm certbot certonly \ --webroot --webroot-path /var/www/certbot/ \ --dry-run -d mon-domaine.fr

Le message "The dry run was successful" devrait s’afficher.

  • Si c’est le cas créer les certificats :
1 2 3 sudo docker compose run --rm certbot certonly \ --webroot --webroot-path /var/www/certbot/ \ -d mon-domaine.fr

3. Mettre à jour la configuration Nginx pour HTTPS

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 upstream payload { server payload:3000; } # Redirection automatique HTTP -> HTTPS server { listen 80; listen [::]:80; server_name [domain].fr www.[domain].fr; server_tokens off; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://[domain]$request_uri; } } # Serveur HTTPS server { listen 443 default_server ssl http2; listen [::]:443 ssl http2; server_name [domain].fr www.[domain].fr; ssl_certificate /etc/nginx/ssl/live/[domain.fr]/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/live/[domain.fr]/privkey.pem; location / { proxy_pass http://payload; 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-Host $host; proxy_set_header X-Forwarded-Proto $scheme; } }
  • Dans docker-compose.yml, décommente cette ligne pour renouveler automatiquement le certificat :
1 2 3 4 5 6 7 8 certbot: restart: always image: certbot/certbot:latest volumes: - ./certbot/www/:/var/www/certbot/:rw - ./certbot/conf/:/etc/letsencrypt/:rw ==> entrypoint: "/bin/sh -c 'while :; do certbot renew; sleep 12h; done'"
  • Commit et push.
  • Sur ton VPS git pull et redemarre docker compose :
1 2 git pull sudo docker compose down && sudo docker compose up
Félicitations : ton application Payload est maintenant accessible en HTTPS via : https://[votre-domaine]/admin

Conclusion

Tu as maintenant un environnement complet pour :

  • Développer localement (Payload, MongoDB, Next.js).
  • Versionner tes modifications via Git et GitHub.
  • Déployer sur un VPS avec Docker + Nginx + Certbot pour obtenir un site en HTTPS.

Bonne continuation ! 🐝

Discutons ensemble de votre projet !

Développement web miniature expertise

Développement web

Développement mobile miniature expertise

Développement mobile

Site vitrine miniature expertise

Site vitrine

Design UI/UX miniature expertise

Design UI/UX

join us