Self-hosting

Run Benkyou with Docker Compose and a private Postgres service.

Docker Compose is the recommended self-host path. Node and pnpm remain the development path when you want to work directly in the repo.

Requirements

Recommended
Docker and Docker Compose for the web app plus Postgres.
Development
Node.js 22 and pnpm when running outside Docker.
Network
Port 3000 for the app. Postgres stays on the internal Compose network.

Environment

Use the root environment template for self-hosting. Keep real values in .env, not in docker-compose.yml.

cp .env.example .env
POSTGRES_PASSWORD
Set a long random password. Do not commit it.
BETTER_AUTH_SECRET
Generate a strong session secret and rotate the placeholder.
BETTER_AUTH_URL
Set to the canonical app URL, for example http://localhost:3000.
PUBLIC_SITE_URL
Set to the public canonical URL used by metadata, robots.txt, and sitemap.xml.
AI_API_KEY
Required for real AI generation. Keep it server-side.
YOUTUBE_API_KEY
Optional for YouTube metadata enrichment.
GENERATION_RATE_LIMIT_MAX / WINDOW_HOURS
Optional quota controls. Defaults are 5 attempts per 24 hours.

Docker start

The Compose stack builds the app, starts Postgres, waits for the database healthcheck, runs migrations, then starts the web server.

docker compose up --build

The Compose file publishes only the web app by default. Postgres is reachable to containers as db, not as a public host port.

Health check

curl http://localhost:3000/api/health

Use /api/health for deployment readiness checks. It is simple, unauthenticated, and does not expose application data.

Development path

Use Node and pnpm when contributing locally or running against your own Postgres instance.

pnpm install
pnpm --filter @benkyou/db db:migrate
pnpm --filter @benkyou/web dev

Operations

Migrations
Run automatically before the web server starts in the Docker image.
Backups
Back up the Postgres volume before upgrades or destructive maintenance.
Public deploy
Put Benkyou behind a reverse proxy with TLS before exposing it beyond localhost.

Rotate every placeholder secret in .env. The values in.env.example are a template, not production credentials.