Self-host docs
Run Flowstace locally with Docker and keep the OSS path intact.
This setup boots PostgreSQL and the Next.js app locally. AI and Stripe are optional. The product works as a self-hosted agency workspace without either integration.
Quick start
1. Prepare env
Copy `.env.example`, set the database URL, Better Auth values, and choose whether AI, email delivery, or Stripe should stay enabled.
2. Start Docker
Bring up Postgres and the Next.js app with `docker compose up --build`. The web container installs deps, pushes the schema, and starts dev mode automatically.
3. Create the first org
Open the app, sign up, and complete onboarding. For self-hosted OSS use, choose the `OSS` plan in onboarding.
4. Optional SaaS config
If you later want hosted billing behavior, add Stripe price IDs and webhook secret, then expose `/api/billing/webhooks/stripe` publicly.
5. Optional automation cron
Set `AGENCYOS_AUTOMATION_SECRET` and call the daily and weekly digest endpoints from cron. This keeps email digests available without adding a separate worker yet.
Commands
cp .env.example .env
docker compose up --build
# optional, outside Docker
npm install
npm run db:push
npm run dev:web
# optional daily digest cron
curl -X POST http://localhost:3000/api/automation/digests/daily \
-H "Authorization: Bearer $AGENCYOS_AUTOMATION_SECRET"
# optional weekly digest cron
curl -X POST http://localhost:3000/api/automation/digests/weekly \
-H "Authorization: Bearer $AGENCYOS_AUTOMATION_SECRET"Environment
DATABASE_URL
PostgreSQL connection string for Prisma and Better Auth.
BETTER_AUTH_SECRET
Required for session signing.
BETTER_AUTH_URL
Public app URL, e.g. http://localhost:3000.
AGENCYOS_DEFAULT_PLAN
Default onboarding plan. Use `OSS` for self-host.
ANTHROPIC_API_KEY
Optional. Enables Claude-backed Szef mode.
AGENCYOS_ENABLE_AI_PREVIEW
Optional. Keeps preview AI mode available without Anthropic.
EMAIL_PROVIDER
Optional. Mail transport selector: `RESEND`, `SMTP`, `SES`, or leave empty to auto-detect / fallback.
RESEND_API_KEY
Optional. Enables live delivery for email 2FA and future notification emails.
EMAIL_FROM_ADDRESS
Optional with a live mail provider. Sender address for security codes and future notifications.
SMTP_HOST
Optional for SMTP delivery. Mail server hostname.
SMTP_PORT
Optional for SMTP delivery. Mail server port.
SMTP_SECURE
Optional for SMTP delivery. Set to true for implicit TLS.
SMTP_USERNAME
Optional for SMTP delivery. Mail server username.
SMTP_PASSWORD
Optional for SMTP delivery. Mail server password.
SES_REGION
Optional for AWS SES. Region used by the SES client.
SES_ACCESS_KEY_ID
Optional for AWS SES. Access key ID for live transactional delivery.
SES_SECRET_ACCESS_KEY
Optional for AWS SES. Secret access key for live transactional delivery.
MAILERLITE_ENABLED
Optional. Enables public newsletter capture on the landing page when set to true.
MAILERLITE_API_KEY
Optional. MailerLite API key for sending landing newsletter leads to your audience.
MAILERLITE_GROUP_ID
Optional. MailerLite group ID that receives new Flowstace landing signups.
AGENCYOS_AUTOMATION_SECRET
Optional but recommended for cron-triggered automation endpoints like daily and weekly digests.
AGENCYOS_STORAGE_ROOT
Optional but recommended for VPS/SaaS. Persistent writable path for uploads, logos, and avatars.
STRIPE_SECRET_KEY
Optional. Only needed if you want live billing and webhooks.
Operational notes
- Every data query is organization-scoped. The first onboarding run creates the first tenant membership.
- Choose `OSS` during onboarding if you want AI features locked by default.
- Stripe billing is optional for self-host. Without it, Billing renders safely but checkout stays unavailable.
- Email 2FA on paid plans works with Resend, or falls back to local capture/logging in development when no mail provider is configured.
- Daily and weekly digests can be triggered by cron through `/api/automation/digests/daily` and `/api/automation/digests/weekly` with the automation bearer secret.
- If Prisma schema changes while Docker is already running, rerun `docker compose exec -T web npm run db:push` and restart `web`.