The self-host compose path runs withDocumentation Index
Fetch the complete documentation index at: https://docs.3ngram.ai/llms.txt
Use this file to discover all available pages before exploring further.
AUTH_ENABLED=true. It creates one local
admin user and enables MCP OAuth/device-flow authentication for clients.
Seeded user
Default credentials:MCP OAuth
Local issuer:OAUTH_ALLOWED_REDIRECT_URIS when deploying on a
custom domain.
Generate strong secrets
JWT_SECRET, MCP_SECRET_KEY, and CRON_SECRET must each be at least 32
random characters. Generate one per secret:
.env (copied from .env.selfhost.example) before exposing
the stack:
DB_PASSWORD (and the matching
DATABASE_URL / DATABASE_MIGRATION_URL) with a real password.
Production-like self-hosting
Before exposing the stack beyond your local machine:- Replace
JWT_SECRET,MCP_SECRET_KEY, andCRON_SECRET(see above). - Set
APP_BASE_URLandMCP_ISSUER_URLto HTTPS URLs. - Restrict
CORS_ALLOWED_ORIGINSto the dashboard origin. - Use a real database password and update
DATABASE_URL. - Put the services behind a TLS-terminating reverse proxy.
Secret enforcement
The config layer fails closed:production/staging: the app refuses to boot ifJWT_SECRET,MCP_SECRET_KEY, orCRON_SECRETmatches a known weak default (the compose fallbacks or the.env.selfhost.exampleplaceholder), ifJWT_SECRETis shorter than 32 characters, or ifDATABASE_URLstill uses the defaultengram_dev_password.selfhost(default, loopback): the app boots sodocker compose upworks from a fresh clone, but logs a loudWARNINGfor each secret left at a known default. Treat those warnings as a hard blocker before binding to anything beyond loopback.- Auth cannot be disabled in any deployed environment (
AUTH_ENABLED=trueis enforced forproduction,staging, andselfhost).
Network self-host: fail closed with SELFHOST_NETWORK_MODE
When you expose the self-host stack to a network (anything beyond loopback),
set SELFHOST_NETWORK_MODE=true in your .env. This promotes the warnings
above to hard boot failures without forcing ENVIRONMENT=production (which
would also require DB_REQUIRE_TLS over the internal Docker network). With it
on, selfhost refuses to boot if JWT_SECRET, MCP_SECRET_KEY, CRON_SECRET,
or the database password is left at a known compose default — the same
fail-closed posture as production/staging.
| Environment | SELFHOST_NETWORK_MODE | Weak/default secret behavior |
|---|---|---|
selfhost | false (default) | Loud WARNING, boots (loopback bring-up) |
selfhost | true | Boot failure (network-exposed) |
production / staging | n/a | Boot failure (always) |
SELFHOST_NETWORK_MODE=true, or set ENVIRONMENT=production behind
your reverse proxy. Both turn the known-default secrets (and the default DB
password) into a boot-time failure rather than a warning.