YYayaw

Auto-hébergement

Runtime Docker portable pour exécuter Yayaw sans Vercel ni stockage Supabase.

Périmètre

La première cible auto-hébergée supportée est un déploiement Docker unique:

  • serveur Next.js standalone
  • Postgres
  • MinIO ou autre stockage objet compatible S3
  • worker base de données Page AI
  • Caddy ou autre proxy inverse qui préserve les en-têtes d'hôte d'origine

Ce chemin prouve la portabilité. Il ne remplace pas Stripe, OpenAI, Resend, l'accès au code GitHub, ni toutes les fonctions propres aux plateformes de déploiement. L'analytics peut utiliser Umami auto-hébergé ou un fournisseur externe comme PostHog.

Fichiers

  • Dockerfile
  • docker-compose.self-host.yml
  • .env.self-host.example
  • deploy/self-host/Caddyfile

next.config.ts utilise output: "standalone" afin que l'image de production puisse lancer le serveur Next.js tracé avec node server.js.

Démarrage Rapide

cp .env.self-host.example .env.self-host
perl -0777 -i -pe "s/^BETTER_AUTH_SECRET=$/BETTER_AUTH_SECRET=$(openssl rand -hex 32)/m" .env.self-host
docker compose --env-file .env.self-host -f docker-compose.self-host.yml --profile setup run --rm migrate
docker compose --env-file .env.self-host -f docker-compose.self-host.yml up --build

Définissez BETTER_AUTH_SECRET avant le premier build. Le Dockerfile refuse de construire avec un secret vide parce que les routes Better Auth sont évaluées pendant next build.

Le profil setup lance drizzle-kit push pour synchroniser le schéma Drizzle courant dans la base auto-hébergée, puis exécute le seed idempotent pour les rôles, indicateurs de fonctionnalité, catalogue de facturation, thèmes et contenu CMS de départ.

Ouvrez http://localhost:8080. MinIO est exposé sur http://localhost:9000 pour l'API S3, et sa console sur http://localhost:9001. Les URL publiques de ressources sont servies via Caddy sur l'origine de l'app par défaut.

Environnement Runtime

Valeurs auto-hébergées importantes:

NEXT_PUBLIC_BASE_URL=http://localhost:8080
BETTER_AUTH_SECRET=<generate-a-long-random-secret>
DATABASE_URL=postgresql://yayaw:yayaw@postgres:5432/yayaw
STORAGE_PROVIDER=s3
STORAGE_MEDIA_BUCKET=media
STORAGE_PUBLIC_BASE_URL=http://localhost:8080
S3_ENDPOINT=http://minio:9000
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=yayaw
S3_SECRET_ACCESS_KEY=yayaw-minio-password
S3_FORCE_PATH_STYLE=true
PUBLIC_DOMAIN_PROVIDER=manual-dns
PAGE_AI_QUEUE_DRIVER=db-worker
DEPLOYMENT_PROVIDER=static
DEPLOYMENT_URL=http://localhost:8080
NEXT_PUBLIC_ANALYTICS_PROVIDER=none
NEXT_PUBLIC_ANALYTICS_CAPTURE_MODE=hybrid
NEXT_PUBLIC_UMAMI_HOST_URL=
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
UMAMI_API_URL=
UMAMI_WEBSITE_ID=
UMAMI_API_TOKEN=
UMAMI_API_KEY=
UMAMI_USERNAME=
UMAMI_PASSWORD=
RESEND_API_KEY=
EMAIL_SENDER=team@yayaw.app
EMAIL_SUPPORT=support@yayaw.app
EMAIL_USERNAME=Yayaw Team

Les valeurs EMAIL_* permettent aux e-mails transactionnels de fonctionner avant la connexion d'un admin. Après setup, Admin > Site Settings > Email peut les surcharger au runtime.

Les valeurs NEXT_PUBLIC_* sont intégrées au bundle navigateur au moment du build. Les commandes Compose ci-dessus passent .env.self-host comme fichier d'environnement de build pour que ces valeurs atteignent les arguments Docker. Reconstruisez une image lorsqu'elles changent. BETTER_AUTH_SECRET est aussi fourni au build Docker afin que Next.js puisse évaluer les routes Better Auth pendant next build; gardez-le aussi présent au runtime.

Les autres valeurs uniquement serveur peuvent changer dans le magasin de secrets de l'orchestrateur ou .env.self-host, puis par redémarrage des conteneurs concernés.

Les builds Docker fixent NEXT_BUILD_WORKERS à 1 par défaut pour garder la génération statique Next.js stable sur de petites machines. Augmentez cette valeur comme variable ou argument de build uniquement après vérification de la marge CPU et mémoire.

Les pages de documentation sont rendues dynamiquement dans les builds auto-hébergés au lieu d'être prégénérées pendant la construction d'image. Cela évite aux petits hôtes Coolify ou Docker de consacrer l'essentiel du budget de déploiement aux pages docs, tout en les servant normalement au runtime.

YAYAW_APP_IMAGE et YAYAW_WORKER_IMAGE contrôlent les tags d'image Compose utilisés par l'app et les cibles worker Bun. Le service migrate utilise volontairement le même tag d'image worker que le worker long-lived, afin que Docker et Coolify réutilisent cette cible de build entre services.

docker-compose.coolify.yml est optimisé pour le chemin Coolify managé par Yayaw et attend des images app et worker déjà présentes sur le serveur Coolify. GitHub Actions construit ces images pour linux/arm64, les charge sur la VM Mac mini, définit YAYAW_APP_IMAGE et YAYAW_WORKER_IMAGE via l'API Coolify, puis déclenche le déploiement Compose. Utilisez docker-compose.self-host.yml pour les installations locales ou clients portables qui doivent construire les images directement depuis le code source.

Dans Coolify, ces variables de tags d'image doivent être disponibles au build time comme au runtime, car Compose résout l'interpolation image: avant de démarrer les services.

Proxy Inverse

Le proxy doit préserver:

  • Host
  • X-Forwarded-Host
  • X-Forwarded-Proto
  • en-têtes de transmission de l'IP client

Les pages publiques d'organisation routent par hostname; perdre le Host d'origine casse la résolution des domaines personnalisés. Gardez un buffering compatible avec les réponses streaming et l'optimisation d'images Next.js.

Lorsque STORAGE_PUBLIC_BASE_URL pointe vers l'origine app ou CDN, routez tous les préfixes de buckets publics vers MinIO avant le repli vers l'app. Le fichier Caddy fourni gère les buckets publics intégrés:

handle /media/* {
	reverse_proxy minio:9000
}

handle /organization-logos/* {
	reverse_proxy minio:9000
}

Si STORAGE_PUBLIC_BASE_URL pointe directement vers une origine dédiée de stockage objet ou CDN, configurez cette origine pour servir les mêmes chemins /<bucket>/<key>.

Stockage

La pile Compose démarre MinIO et crée les buckets publics media et organization-logos. Les médias téléversés et les miniatures utilisent des opérations compatibles S3; les pages publiées utilisent les URL publiques stockées.

Les URL média Supabase existantes ne sont pas migrées par la pile auto-hébergée. Gardez l'ancien bucket joignable ou prévoyez une migration média séparée.

Domaines Publics

Les domaines auto-hébergés utilisent une vérification DNS manuelle:

  1. Ajoutez le hostname depuis les réglages d'organisation ou MCP.
  2. Publiez le challenge TXT affiché par le dashboard.
  3. Pointez le domaine vers l'ingress avec les enregistrements CNAME ou A configurés.
  4. Relancez le check ou la vérification du domaine.
  5. Configurez TLS au niveau du proxy.

Utilisez PUBLIC_DOMAIN_CNAME_TARGET et PUBLIC_DOMAIN_IPV4_TARGETS pour afficher les indications de routage à l'opérateur. Utilisez APP_MANAGED_HOSTS et RESERVED_PUBLIC_DOMAIN_SUFFIXES pour empêcher les clients de réclamer des hôtes possédés par l'app ou réservés.

Worker

Lancez un ou plusieurs workers Page AI avec:

bun run worker:page-ai

Le worker interroge Postgres pour les runs Page AI durables. Vercel Queues reste disponible sur Vercel, mais le défaut de production auto-hébergé est db-worker.

Exploitation

  • Lancez le profil setup avant le premier démarrage et après les changements de schéma afin de synchroniser la base et réparer les seeds.
  • Persistez les volumes Postgres, MinIO, Caddy et .next/cache.
  • Sauvegardez Postgres et le stockage objet ensemble pour garder les lignes média et les objets synchronisés.
  • Gardez NEXT_SERVER_ACTIONS_ENCRYPTION_KEY et une stratégie de build ID stable comme suivi avant de passer à plusieurs instances app.
  • Choisissez un fournisseur d'analytics avec NEXT_PUBLIC_ANALYTICS_PROVIDER. Valeurs supportées: posthog, umami, none; Umami requiert NEXT_PUBLIC_UMAMI_* pour le suivi et les variables API UMAMI_* pour les données dashboard.
  • Choisissez un mode de capture analytics avec NEXT_PUBLIC_ANALYTICS_CAPTURE_MODE. Utilisez server pour éviter tout script analytics navigateur; utilisez hybrid pour combiner analytics produit navigateur et conversions facturation côté serveur.
  • Gardez les risques fournisseurs Stripe, OpenAI, Resend et GitHub documentés tant que leurs contrats fournisseurs n'existent pas.

Vérifications Production

Après un déploiement production, vérifiez la configuration depuis le conteneur app en cours d'exécution plutôt que seulement depuis l'UI de l'orchestrateur. Signaux auto-hébergés importants:

  • STORAGE_PROVIDER=s3
  • STORAGE_PUBLIC_BASE_URL pointe vers l'origine app, CDN ou stockage objet qui sert les chemins /<bucket>/<key>
  • S3_ENDPOINT est joignable depuis les conteneurs app et worker
  • NEXT_PUBLIC_ANALYTICS_PROVIDER=umami lorsque vous utilisez Umami auto-hébergé
  • NEXT_PUBLIC_ANALYTICS_CAPTURE_MODE=server lorsqu'aucun script analytics navigateur ne doit être rendu

Pour les médias, téléversez un petit objet avec les mêmes identifiants S3 que l'app, puis récupérez son URL publique. L'URL publique doit utiliser STORAGE_PUBLIC_BASE_URL, par exemple /media/<key> quand Caddy route le préfixe de bucket vers MinIO. Si ce test stockage réussit mais que le téléversement dashboard échoue, inspectez l'organisation active, les permissions média, le quota de plan, le type de fichier et la taille avant de changer de fournisseur de stockage.

Pour une configuration sans analytics navigateur, récupérez une page publique et confirmez que le HTML ne contient pas l'URL du script Umami ni data-website-id. Les analytics dashboard ont encore besoin d'identifiants API Umami via UMAMI_API_TOKEN, UMAMI_API_KEY ou UMAMI_USERNAME/UMAMI_PASSWORD; la capture événementielle côté serveur utilise /api/send et ne requiert pas le script navigateur.

Validation

docker compose --env-file .env.self-host -f docker-compose.self-host.yml config
bun test src/config/storage.config.test.ts src/lib/storage.test.ts
bun test src/lib/server/services/organization-domains/organization-public-domains.test.ts
bun test src/lib/server/services/pages/page-ai-runner.test.ts