Bouée
Get started

Other platforms

What Bouée needs from any platform that runs containers: Kubernetes, Render, Railway and the rest.

bin/install on a server with Docker and Fly.io are the two installs these docs walk through. Anywhere else that runs a container, follow the platform's own guide for a Docker image with PostgreSQL and object storage, and give Bouée the following.

The image

One image, built from the repository's Dockerfile (target runner), both migrates and serves:

  • Serving: node server.js listens on port 3000 (PORT). GET /api/health answers 200 while the database answers, for the platform's health check.
  • Migrating: /app/bin/migrate applies the database migrations and exits. Run it before a new version serves: as a release or pre-deploy command, a Kubernetes init container or Job, or Compose's migrate service.
  • Keep one instance running. Mail comes in and goes out from the running server, and its sweeps (retries, expiry, auto-close) run on timers inside it. Several instances are fine; none is not.

What it connects to

  • PostgreSQL 16 or later. DATABASE_URL is what the app uses. When it goes through a connection pooler, set DIRECT_DATABASE_URL to a direct connection for the migrations.
  • An S3-compatible bucket (Amazon S3, Cloudflare R2, Tigris, Garage or MinIO): S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, and S3_FORCE_PATH_STYLE=true where the store needs path-style addresses. Keep the bucket private.
  • Resend, with RESEND_API_KEY (Email).

The environment

Variable
APP_URLThe https address people open.
DATABASE_URLAs above.
BETTER_AUTH_SECRET, PORTAL_LINK_SECRET, SECRET_ENCRYPTION_KEYGenerated once, each with openssl rand -base64 32. Keep a copy apart from the platform: a restored database needs the same SECRET_ENCRYPTION_KEY.
S3_*As above.
RESEND_API_KEYA Resend key with full access.
BOUEE_CONFIGWhere the platform mounts bouee.yaml, read-only, such as /config/bouee.yaml.
TRUSTED_PROXIESHow many proxies add to X-Forwarded-For in front of Bouée: 1 behind one load balancer.

.env.example explains every variable, the optional ones included.

In front of it

  • TLS for APP_URL's hostname, and for each brand hostname Bouée serves: a wildcard certificate covers brand subdomains under a hosted_domain, and a customer's own hostname needs one of its own.
  • The Host header passed through unchanged. Bouée decides from it what each hostname may reach: a brand's hostname serves only its knowledge base.
  • Request bodies of 64 MB, just above Bouée's own 60 MiB limit, for attachments; and no path prefix: Bouée answers at the root of its hostname.
  • Inbound https from Resend to APP_URL/api/inbound/…, which is how incoming mail arrives.

Asking the running app

bin/bouee's commands run inside any container of the image:

node /app/bin/bouee.mjs status        # also dns-records and provision

With Kubernetes, that is kubectl exec deploy/bouee -- node /app/bin/bouee.mjs status.

On this page