[{"data":1,"prerenderedAt":206},["ShallowReactive",2],{"seo-verification":3,"blog-deployer-payload-cms-vps-ma-fr":6,"promo-bar-likely":205},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-deployer-payload-cms-vps-ma-fr",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":30,"intro":33,"sections":34,"ctaTitle":145,"ctaBody":146,"ctaButton":147,"ctaUrl":148,"relatedPosts":149},55,"deployer-payload-cms-vps",{"fr":10,"en":12,"ar":13,"es":14},"deploying-a-payload-cms-application-on-a-vps","نشر-تطبيق-payload-cms-على-خادم-vps","desplegar-payload-cms-en-un-vps","Déployer Payload CMS sur VPS : guide complet","Guide complet pour self-héberger Payload CMS 3 sur un VPS : Docker Compose, auth, hooks, migrations, dépannage des erreurs réelles.",10,2,false,"2026-04-26T00:00:00+00:00","2026-11-08T01:13:14+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},4,"Développement","developpement","bg-warning\u002F10 text-warning","dev",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-payload-cms-vps-poster.svg","Payload CMS 3 s'installe directement dans une application Next.js, ce qui en fait l'un des CMS headless les plus proches du code. Ce guide couvre le déploiement complet sur VPS : configuration Docker Compose avec healthchecks, gestion des utilisateurs et des API keys, hooks de collection, workflow de migration, et dépannage des erreurs les plus fréquentes rencontrées en production.",[35,39,50,53,75,78,81,84,87,90,142],{"type":36,"title":37,"body":38},"h2","Pourquoi self-héberger Payload CMS sur un VPS","Payload CMS adopte une approche radicalement code-first : votre schéma de contenu est défini en TypeScript dans des fichiers de configuration, versionnés avec Git, et depuis sa version 3 Payload s'installe directement dans une application Next.js via le App Router. Cela signifie qu'un VPS vous permet d'héberger le CMS et le site front dans un seul et même processus Node, partageant le build et le runtime. Vous obtenez un typage de bout en bout, des migrations de schéma gérées dans le code, et aucune dépendance à une interface graphique pour modéliser vos contenus. Le self-hosting est ici l'option naturelle : Payload est pensé pour être déployé comme n'importe quelle app Next.js, et un VPS vous donne le contrôle de la base (MongoDB ou PostgreSQL), des uploads et des variables d'environnement, sans plateforme intermédiaire.",{"type":40,"title":41,"items":42},"ul","Bénéfices concrets",[43,44,45,46,47,48,49],"Schéma de contenu défini en TypeScript et versionné avec Git : revue de code et historique complets","CMS et front Next.js dans un seul runtime : un seul build, un seul process à déployer","Typage de bout en bout entre la config Payload, l'API et le front, sans génération manuelle","Choix de la base : MongoDB, PostgreSQL ou SQLite via les adaptateurs officiels","Migrations de schéma pilotées par le code (`payload migrate`), reproductibles entre environnements","Local API : accès direct aux données sans appel HTTP depuis le code serveur Next.js","Aucun coût de licence : Payload CMS 3 est open-source (MIT) — vous ne payez que le VPS",{"type":36,"title":51,"body":52},"Prérequis matériels et logiciels","Payload reposant sur Next.js, le build est exigeant : prévoyez un VPS de 2 vCPU et 4 Go de RAM pour builder et faire tourner l'application confortablement, surtout si le front Next.js est conséquent. Installez Node.js 22 ou 24 (Payload 3.93 exige `^22.23.4 || >=24.22.1` ; Node 20 n'est plus accepté), Docker et Docker Compose. Côté base, provisionnez MongoDB 7 ou PostgreSQL 16 selon l'adaptateur choisi (`@payloadcms\u002Fdb-mongodb` ou `@payloadcms\u002Fdb-postgres`). Pointez votre domaine vers l'IP du VPS. Comptez 15 Go de disque pour les `node_modules`, le build `.next`, les uploads et les sauvegardes de base.",{"type":54,"title":55,"steps":56},"steps","Déploiement pas à pas",[57,60,63,66,69,72],{"title":58,"body":59},"Choisir et configurer l'adaptateur de base","Dans `payload.config.ts`, déclarez l'adaptateur : `mongooseAdapter` pour MongoDB ou `postgresAdapter` pour PostgreSQL, en lisant l'URL de connexion depuis `DATABASE_URI`. Ce choix est structurant : PostgreSQL impose des migrations, MongoDB est plus souple sur le schéma.",{"title":61,"body":62},"Préparer les variables d'environnement","Créez un fichier `.env.production` avec au minimum :\n\n```bash\nPAYLOAD_SECRET=votre-secret-32-caracteres-minimum\nDATABASE_URI=postgresql:\u002F\u002Fuser:pass@postgres:5432\u002Fpayload\nNEXT_PUBLIC_SERVER_URL=https:\u002F\u002Fexample.com\nNODE_ENV=production\nPAYLOAD_CONFIG_PATH=src\u002Fpayload.config.ts\n```\n\n`PAYLOAD_SECRET` signe les tokens JWT des sessions et chiffre les API keys — une valeur courte ou prévisible fragilise l'ensemble de l'authentification. Générez-la avec `openssl rand -hex 32`. `NEXT_PUBLIC_SERVER_URL` doit correspondre à l'URL publique finale : Payload l'utilise pour construire les liens des médias et les URLs d'email.",{"title":64,"body":65},"Écrire le Docker Compose avec healthchecks","Un `docker-compose.yml` robuste inclut des healthchecks pour ne démarrer l'app qu'après que la base soit prête :\n\n```bash\nservices:\n  app:\n    build: .\n    ports:\n      - \"127.0.0.1:3000:3000\"\n    env_file: .env.production\n    depends_on:\n      postgres:\n        condition: service_healthy\n    volumes:\n      - uploads:\u002Fapp\u002Fpublic\u002Fmedia\n\n  postgres:\n    image: postgres:16-alpine\n    environment:\n      POSTGRES_USER: payload\n      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}\n      POSTGRES_DB: payload\n    volumes:\n      - pgdata:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U payload\"]\n      interval: 5s\n      timeout: 5s\n      retries: 10\n\nvolumes:\n  pgdata:\n  uploads:\n```\n\nSans le healthcheck et la condition `service_healthy`, l'app démarre avant que PostgreSQL n'accepte les connexions, le pool de connexion échoue et le conteneur redémarre en boucle.",{"title":67,"body":68},"Builder l'image et exécuter les migrations","Lancez le build puis les migrations dans cet ordre :\n\n```bash\ndocker compose build\ndocker compose up -d postgres\ndocker compose run --rm app npx payload migrate\ndocker compose up -d app\n```\n\nPour PostgreSQL, `npx payload migrate` applique les fichiers de migration générés dans `src\u002Fmigrations\u002F`. Si aucun fichier n'existe encore, générez-les d'abord avec `npx payload migrate:create`. Pour MongoDB, le schéma ne demande aucune migration : `migrate` n'exécute que les migrations de données que vous avez écrites vous-même avec `migrate:create`.",{"title":70,"body":71},"Configurer Nginx en reverse proxy","Pointez un vhost vers `http:\u002F\u002F127.0.0.1:3000` (port Next.js par défaut). Augmentez `client_max_body_size` pour les uploads de médias et ajoutez les en-têtes `X-Forwarded-Proto` pour que Payload génère des URLs HTTPS correctes.",{"title":73,"body":74},"Sécuriser avec SSL et fixer l'URL serveur","Exécutez `certbot --nginx -d example.com`, puis vérifiez que `serverURL: 'https:\u002F\u002Fexample.com'` est bien défini dans `payload.config.ts`. Cette URL conditionne les liens des médias, les emails de réinitialisation et le bon fonctionnement du panneau admin derrière le proxy.",{"type":36,"title":76,"body":77},"Authentification et gestion des accès","Payload 3 gère les utilisateurs via la collection `users` définie dans `payload.config.ts`. Activez l'authentification sur la collection avec le champ `auth: true` — cela ajoute automatiquement les endpoints `\u002Fapi\u002Fusers\u002Flogin`, `\u002Fapi\u002Fusers\u002Flogout`, `\u002Fapi\u002Fusers\u002Fme` et `\u002Fapi\u002Fusers\u002Frefresh-token`.\n\nPour les rôles, Payload n'impose pas de modèle : vous définissez un champ `role` (type `select`) sur la collection `users`, puis vous pilotez les accès via les fonctions `access` au niveau de chaque collection et de chaque opération :\n\n```bash\naccess: {\n  read: ({ req: { user } }) => user?.role === 'admin',\n  create: isAdmin,\n  update: isAdminOrSelf,\n  delete: isAdmin,\n}\n```\n\nPour les accès programmatiques (CI, intégrations tierces), utilisez les **API keys** : activez `useAPIKey: true` dans la config d'authentification de la collection. Les utilisateurs disposant de l'accès admin peuvent alors générer, régénérer ou révoquer une clé depuis le panneau admin. Transmettez-la dans l'en-tête `Authorization: users API-Key votre-cle`. La clé n'est affichée qu'une fois : Payload la chiffre en base avec `PAYLOAD_SECRET` et ne la montre plus ensuite — une clé perdue se régénère, et changer `PAYLOAD_SECRET` invalide toutes les clés existantes.",{"type":36,"title":79,"body":80},"Hooks de collection : réagir aux événements de contenu","Les **collection hooks** de Payload 3 permettent d'exécuter du code avant ou après chaque opération CRUD. Ils remplacent avantageusement les webhooks quand la logique vit dans le même runtime :\n\n```bash\nhooks: {\n  afterChange: [\n    async ({ doc, operation }) => {\n      if (operation === 'create') {\n        await notifySubscribers(doc)\n      }\n    },\n  ],\n  beforeDelete: [\n    async ({ id }) => {\n      await cleanupMedia(id)\n    },\n  ],\n}\n```\n\nLes hooks de collection sont `beforeOperation`, `beforeValidate`, `beforeChange`, `afterChange`, `beforeRead`, `afterRead`, `beforeDelete`, `afterDelete`, `afterOperation` et `afterError` ; les collections d'authentification ajoutent notamment `beforeLogin`, `afterLogin` et `afterLogout`. Un hook `afterChange` est idéal pour invalider un cache CDN, envoyer une notification ou synchroniser avec un service externe après publication.\n\nPour les **webhooks HTTP sortants** (notifier un site statique, un Slack, un pipeline de build), Payload ne fournit pas de module dédié mais les hooks `afterChange` suffisent : un simple `fetch` vers votre endpoint cible à l'intérieur du hook remplit ce rôle. Veillez à ne pas bloquer la réponse sur une requête externe — wrappez l'appel dans un `setImmediate` ou un processus séparé si la latence est un critère.",{"type":36,"title":82,"body":83},"Mises à jour et migrations de schéma","Payload 3 suit le versionnement sémantique. Les mises à jour de patch (`3.x.y → 3.x.z`) sont sûres à appliquer sans migration. Les mises à jour mineures (`3.x → 3.y`) peuvent ajouter des colonnes ou des index et nécessitent de rejouer `payload migrate`.\n\nWorkflow recommandé pour chaque mise à jour :\n\n```bash\n# 1. Bumper la version dans package.json\nnpm install payload@3.93.0 @payloadcms\u002Fdb-postgres@3.93.0\n\n# 2. Générer le fichier de migration si le schéma a changé\nnpx payload migrate:create\n\n# 3. Tester en local sur une copie de la base\nnpx payload migrate\n\n# 4. Committer le fichier de migration avec le bump de version\ngit add src\u002Fmigrations\u002F package.json package-lock.json\ngit commit -m \"chore: payload 3.93.0\"\n\n# 5. En production : arrêter l'app, appliquer les migrations, redémarrer\ndocker compose run --rm app npx payload migrate\ndocker compose up -d app\n```\n\nNe modifiez jamais à la main une migration déjà appliquée dans `src\u002Fmigrations\u002F` : Payload enregistre chaque migration exécutée par son nom dans la collection `payload-migrations` et ne la rejoue pas, si bien que la retouche n'atteint jamais la production. Écrivez plutôt une nouvelle migration. Pour revenir en arrière sur une migration : `npx payload migrate:down`.",{"type":36,"title":85,"body":86},"Quand `sharp` refuse de se charger","C'est le premier obstacle du déploiement sur VPS, et il prend trois formes distinctes qu'il vaut mieux savoir distinguer. La plus déroutante est `Unsupported CPU: Prebuilt binaries for Linux x64 require v2 microarchitecture` (« linux-x64 » avant sharp 0.35) : elle ne vient ni de votre code ni de vos dépendances, mais du **processeur de la machine**. Les binaires précompilés visent un jeu d'instructions que les CPU les plus anciens n'exposent pas — c'est donc un critère de choix de VPS, pas un bug à corriger. La deuxième, `Could not load the \"sharp\" module using the linux-x64 runtime`, signale presque toujours un `node_modules` fabriqué sur une autre plateforme, typiquement un macOS de développement copié vers un serveur Linux : réinstallez sur la machine cible plutôt que de transporter le dossier. La troisième est propre à Docker multi-étapes : `sharp` installé dans l'étape de construction seulement, absent de l'étape d'exécution — le conteneur démarre puis échoue au premier traitement d'image. Installez-le explicitement dans l'étape finale. Sur une architecture ARM, la même vigilance s'applique : la bibliothèque doit être résolue pour cette plateforme.",{"type":36,"title":88,"body":89},"Dépannage : erreurs fréquentes en production","**Build OOM — `Killed` ou `JavaScript heap out of memory`.**\nSurvient pendant `npm run build` quand la RAM du VPS est juste et que le tas de Node.js atteint sa limite. Passez `NODE_OPTIONS=--max-old-space-size=3072` dans l'environnement avant de lancer le build, ou buildez l'image sur une machine plus puissante et poussez l'image vers un registry.\n\n**PostgreSQL — `Error: connect ECONNREFUSED 127.0.0.1:5432`.**\nL'app tente de se connecter avant que PostgreSQL soit prêt, ou l'URL de connexion pointe sur `localhost` au lieu du nom du service Docker (`postgres`). Vérifiez que `DATABASE_URI` utilise le nom du service (`postgresql:\u002F\u002Fpayload:pass@postgres:5432\u002Fpayload`) et que le healthcheck est en place (voir étape 3).\n\n**Admin inaccessible en prod — `\u002Fadmin` répond 404 ou redirige en boucle.**\nDeux causes principales : `serverURL` non défini ou non correspondant à l'URL réelle (Payload génère ses redirections internes depuis cette valeur), ou le header `X-Forwarded-Proto: https` absent du reverse proxy Nginx. Ajoutez `proxy_set_header X-Forwarded-Proto $scheme;` dans le vhost et vérifiez que `serverURL` est identique à l'origine publique, sans barre oblique finale.\n\n**CORS — `Access-Control-Allow-Origin` manquant sur l'API.**\nPayload lit `cors` depuis `payload.config.ts`. En production, listez explicitement vos origines autorisées : `cors: { origins: ['https:\u002F\u002Fexample.com'] }`. Laisser `cors: '*'` accepte toutes les origines, ce qui peut être voulu pour une API publique mais expose l'admin aux requêtes cross-origin. `cors: { origins: [serverURL] }` est le réglage minimal sûr.\n\n**Une migration retouchée ne s'applique pas.**\nUn fichier de `src\u002Fmigrations\u002F` a été édité après avoir été appliqué. Payload enregistre chaque migration exécutée par son nom et ne la rejoue jamais : la modification est ignorée sans erreur. Restaurez l'original depuis Git, générez un nouveau fichier de migration si le schéma a changé, et appliquez-le.",{"type":91,"title":92,"headers":93,"rows":97},"comparison","Payload CMS vs Strapi : quel CMS headless self-héberger ?",[94,95,96],"Critère","Payload CMS","Strapi",[98,102,106,110,114,118,122,126,130,134,138],[99,100,101],"Approche de configuration","Code-first en TypeScript, versionné avec Git","GUI-first via le Content-Type Builder",[103,104,105],"Intégration front","Native dans Next.js (un seul runtime)","Découplé, front et CMS séparés",[107,108,109],"Bases supportées","MongoDB, PostgreSQL et SQLite","PostgreSQL, MySQL, MariaDB, SQLite",[111,112,113],"Typage","TypeScript de bout en bout natif","Types générés, intégration moins serrée",[115,116,117],"Accès aux données serveur","Local API sans appel HTTP","API REST\u002FGraphQL via HTTP",[119,120,121],"Modélisation du contenu","Dans le code, par les développeurs","Dans l'interface, accessible aux non-dev",[123,124,125],"RAM nécessaire au build","Élevée (build Next.js)","Élevée (build admin React)",[127,128,129],"Gestion des migrations","Fichiers versionnés, `payload migrate`","Schéma synchronisé au démarrage, migrations dans `database\u002Fmigrations` (sans CLI)",[131,132,133],"API keys natives","Oui, par collection, chiffrées en base","Oui, via les tokens d'API",[135,136,137],"Hooks de collection","Natifs, typés TypeScript","Lifecycle hooks (`lifecycles.js`) et middlewares du Document Service",[139,140,141],"Idéal pour","Équipes dev, projets Next.js typés","Équipes mixtes, modélisation visuelle",{"type":143,"body":144},"tip","Exploitez la Local API de Payload dans vos composants serveur Next.js : au lieu d'appeler votre propre API via `fetch`, importez `getPayload` et interrogez la base directement (`payload.find({ collection: 'posts' })`). Vous supprimez un aller-retour HTTP et gagnez en latence comme en sécurité. Pour les médias, branchez le plugin `@payloadcms\u002Fstorage-s3` afin de stocker les uploads hors du VPS, et automatisez un dump quotidien de votre base via un cron pour garantir des sauvegardes hors-serveur. Enfin, activez le **draft\u002Fpreview** natif de Payload pour offrir un workflow éditorial de prévisualisation avant publication, sans aucun plugin tiers.","Déployez Payload CMS sur une stack unifiée","Le VPS Cloud ServOrbit offre la puissance nécessaire au build Next.js de Payload et un environnement Docker prêt pour MongoDB ou PostgreSQL, afin d'héberger votre CMS code-first et votre front sur la même machine.","Découvrir le VPS Cloud","\u002Fvps-cloud",[150,168,186],{"id":151,"slug":152,"slugs":153,"title":157,"excerpt":158,"readTime":23,"views":159,"isPinned":19,"noindex":19,"publishedAt":160,"updatedAt":161,"category":162,"categories":163,"featuredImage":30,"bgImage":31,"posterImage":165,"relatedSolution":166},5,"deployer-laravel-vps",{"fr":152,"en":154,"ar":155,"es":156},"deploying-laravel-on-a-vps-a-production-guide","نشر-laravel-على-خادم-vps-دليل-الإنتاج","desplegar-laravel-en-un-vps","Déployer Laravel sur un VPS : guide production","Passez Laravel en production sur VPS : PHP, workers, cache, base de données, reverse proxy et HTTPS proprement configurés.",1,"2026-02-09T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[164],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-laravel-vps-poster.svg",{"categorySlug":27,"appSlug":167},"laravel-stack",{"id":169,"slug":170,"slugs":171,"title":175,"excerpt":176,"readTime":177,"views":159,"isPinned":19,"noindex":19,"publishedAt":178,"updatedAt":179,"category":180,"categories":181,"featuredImage":30,"bgImage":31,"posterImage":183,"relatedSolution":184},43,"deployer-nodejs-vps",{"fr":170,"en":172,"ar":173,"es":174},"deploy-a-nodejs-application-on-a-vps","نشر-تطبيق-nodejs-على-vps","desplegar-una-aplicacion-nodejs-en-un-vps","Déployer une application Node.js sur un VPS","Déployez une application Node.js en production sur un VPS : PM2, reverse proxy Nginx, SSL Let's Encrypt et démarrage automatique au boot.",8,"2026-05-08T00:00:00+00:00","2026-11-08T01:13:12+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[182],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-nodejs-vps-poster.svg",{"categorySlug":25,"appSlug":185},"nodejs-stack",{"id":187,"slug":188,"slugs":189,"title":193,"excerpt":194,"readTime":195,"views":196,"isPinned":19,"noindex":19,"publishedAt":197,"updatedAt":198,"category":199,"categories":200,"featuredImage":30,"bgImage":31,"posterImage":202,"relatedSolution":203},44,"deployer-django-vps",{"fr":188,"en":190,"ar":191,"es":192},"deploy-a-django-application-on-a-vps","نشر-تطبيق-django-على-vps","desplegar-una-aplicacion-django-en-un-vps","Déployer une application Django sur un VPS","Déployez Django sur un VPS : Gunicorn, Nginx, PostgreSQL, Docker et SSL. Guide complet pour développeurs Python qui veulent self-héberger.",3,7,"2026-05-07T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[201],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-django-vps-poster.svg",{"categorySlug":25,"appSlug":204},"django",true,1794270698436]