Configuration reference
Configuration reference
Who this is for: the administrator of a self-hosted installation, after .
What it covers: every environment variable you can set, and every setting under System, Config: what it does, what it needs, and how to check it.
Before you begin you need: a running installation and the admin account (or another account with the system rights listed below).
Self-hosted only. Every setting here is installation-wide. Project owners cannot see or change them; they ask you. The list they work from is .
Where configuration lives
Layer | Where | Changed by | Takes effect |
|---|---|---|---|
Environment |
| You, on the server | After |
System settings | System, Config in the browser | A person with the Manage Jobs system right | Immediately, without a restart |
Project settings | Inside each project | Project owners | Immediately |
Two rules decide conflicts:
A value saved in System Config wins over the same value in the environment. The environment value is the starting value, used until a saved value exists. Example: once Public App URL has been saved, editing PUBLIC_APP_URL in .env changes nothing. Edit it in Config.
The bundled docker-compose.yml passes only the variables it lists to the app container. Putting another variable in .env has no effect on its own. See Pass an extra variable to the app.
Who can open System
The gear button on the Projects page opens the administration menu. Each entry needs a system right. Rights are granted per user in Users (select a user, System Permissions).
System right | Opens |
|---|---|
Manage Jobs | Config, Jobs, Health, Traces, Client errors, Index advisor |
Manage Users | Users, Billing |
Manage Projects | Connectors, access to all projects, the demo project flag in the project form, and the Builder panel on the Security tab. A project owner does not have these. |
Manage Traces | Traces, Client errors and the notification journal (Manage Jobs opens them too) |
The admin account created at install has all four. Give other administrators only what they need. Users also lets you block an account (Block User) and set a new password for it (Reset Password).
Environment variables
Set by the installer
The installer writes these into .env (see .env.example in the bundle). You normally never edit the generated secrets.
Variable | Default | What it does |
|---|---|---|
|
| The address people open in the browser, with no trailing slash. Cookies, emailed links and sign-in callbacks are built from it. |
|
| Host port for the app's plain HTTP. |
|
| Interface the app port listens on. |
| empty | Set together by |
| generated | Signs team sessions. At least 32 characters. In production the app does not work with a missing, too short or publicly known value; the log shows an |
| generated | Master key (base64, 32 bytes) for saved connector credentials. Losing it makes them unreadable. Back it up with |
| generated | Password of the |
| generated | Password of the bundled database. |
|
| The plan new accounts start on. |
| set by the installer | The image to run. |
Optional, passed by the bundled compose file
These are empty by default. They are only the starting values or the fallbacks: the pages under System, Config take priority once you use them.
Variable | What it does |
|---|---|
| Outgoing email. Used until you save the Email tab. |
| A fallback AI provider. It is used for a role only when no enabled provider on the AI tab is assigned to that role. |
Optional, not passed unless you add them
Careful:
HEALTH_TOKENand the bundled image. The image's Docker health check andinstall.shcall/api/healthwithout a token. If you setHEALTH_TOKEN, the app answers401to them: the container is reportedunhealthy, and a later./install.shwaits six minutes and reports a failure although the app runs. Leave the token unset, or restrict/api/healthat your proxy instead.
Pass an extra variable to the app
Create docker-compose.override.yml in the release directory. docker compose merges it with docker-compose.yml automatically, and a new release does not overwrite it.
services:
app:
environment:
NEXT_MANUAL_SIG_HANDLE: "true"
CONNECTOR_ALLOW_PRIVATE_HOSTS: "true"
stop_grace_period: 20s
docker compose up -d
Check: docker compose exec app printenv NEXT_MANUAL_SIG_HANDLE prints true. The stop_grace_period matters: Docker waits 10 seconds by default before killing a container, which is less than the app's 12-second shutdown budget.
System, Config tabs
Open System, Config from the gear button. The page says changes apply without a restart. Every secret field shows set once saved and never shows the value again; type a new value to replace it.
General
Setting | Default | What it needs and how to check |
|---|---|---|
Public App URL | from | The public address, no trailing slash, |
Software development feature | off | A switch. When on, project owners can enable Software development in a project: components, source code, code analysis and Git sync. Existing projects that already have it keep working when you turn it off. |
Git Cache Directory |
| Where repositories are cloned for that feature. In the container it is inside the image, not on a volume, so clones are lost when the container is recreated (they are cloned again on demand). |
Max Parallel Jobs |
| The most background jobs that run at the same time. |
Embed File Max Size (MB) |
| The largest file a user can attach to a document. Your reverse proxy must allow uploads at least this large ( |
AI
AI Providers. Press Add. The fields are: Name, Provider (OpenRouter, Z.AI, MiniMax, Alibaba (DashScope), or Custom / Self-hosted (OpenAI-compatible)), a base URL for the custom kind, API key, Model, Priority (a lower number is tried first), Max Parallel Jobs, and the roles it serves under Use for.
The roles are: Analysis, Doc Generation, Agent, Grammar Check, Grammar Background, Image Description, OCR (vision required) and Translation Background. The OCR role needs a model that accepts images. A role with no enabled provider falls back to the AI_PROVIDER environment variables; if those are empty too, the feature fails.
Check: use the provider's test button before saving. The Workers by role summary shows how many parallel workers each role has; a role with none reads No enabled provider is assigned to the "…" role.
A custom endpoint may be local (for example an Ollama or vLLM server), and its key is optional. Give the app container a route to it.
Embedding Model. The endpoint that turns text into vectors for search by meaning.
Field | Notes |
|---|---|
Provider | A preset from |
Endpoint URL | Default |
Model | Default |
API Key | Optional; leave empty for an endpoint without authentication |
Vector Size | Default |
Press Test, then Save. Stats shows how many documents and files are indexed.
Careful: changing the model needs a full reindex; the page asks you to confirm. Without an embedding endpoint, search still works by keywords, and results that match only by meaning are missing.
Email Connector. Outgoing mail for invitations, verification, sign-in links, notifications, automation emails and backup reports.
Field | Notes |
|---|---|
Provider | SMTP or Resend |
From address | Optional for SMTP (the SMTP user name is used if empty). Required for Resend, and its domain must be verified in Resend (SPF and DKIM). |
Host, Port, Username, Password | SMTP only. Port 465 uses implicit TLS; other ports use STARTTLS. |
Resend API Key | Resend only |
Press Test Connection, then Save. Check: the test prints Connection successful, and a real invitation arrives. Symptoms of a missing or wrong setup: a new account shows Account created but failed to send verification email. Please contact support.; a portal invite shows User saved, but the invite email failed to send. Check SMTP configuration. Member invitations are saved even when the mail fails, and the failure is written only to the server log.
Inbound Email Domain and Resend Inbound Signing Secret. These give each project an inbound address of the form project-slug@domain (owners set the route in Inbound Messaging in the project menu).
Receive mail for the domain at Resend and set Inbound Email Domain (no leading @). With no domain set, owners must type a full address for each endpoint.
Set Public App URL. The page then shows the webhook address to register: <Public App URL>/api/webhooks/inbound/resend.
Register that address as the inbound webhook in your Resend dashboard, and paste the signing secret (whsec_…) into Resend Inbound Signing Secret. The app verifies every inbound message with it and rejects mail without it.
Check: send a test message to an inbound address and see it arrive in the project's inbox.
Storage & Logs
Storage. Where uploaded images, files and attachments go.
Choice | Where files live |
|---|---|
Local filesystem | In the app's |
S3-compatible | A bucket. Works with AWS S3, MinIO, Cloudflare R2 and others. Fields: Endpoint (blank means AWS), Region, Bucket, Access Key ID, Secret Access Key, and Force path-style addressing (needed for MinIO and some R2 setups). |
Press Test Connection, then Save. Check: upload an image in a document and open it. Uploads that fail show Upload failed in places such as the Asset Library.
Switching affects new uploads only; existing files keep serving from where they are. To move existing files, use Migrate storage: it copies every tracked file to the other backend, verifies it, and then switches. The old store stays as a rollback. Choose the store before users upload many files. With local storage, the volume is part of your backup and the disk is your capacity limit.
Storage garbage collection frees files that nothing refers to any more. It is off by default and has a Dry run switch that is on by default, so enabling it deletes nothing until you switch the dry run off. A file must lose its last reference and wait out a grace window and a quarantine window (roughly 60 days) before it can be deleted. Leave it off unless disk space forces you to use it, and read the journal in dry-run mode first.
Log DB configuration. Where the data change log is kept. By default it is in the main database, which is fine for most installations. A separate database isolates the log's heavy writes from live traffic, but only when it is a different server: a second database on the same server gains little.
The panel shows Status (Not configured — change log is stored in the main database, or Configured). To set it up:
On the other server, create an empty database and a role that can create roles (CREATEROLE) or a superuser, and allow it to connect from the app.
CREATE ROLE log_admin LOGIN PASSWORD 'CHOOSE_A_LONG_PASSWORD' CREATEROLE;
CREATE DATABASE app_logs OWNER log_admin;
Paste that role's URL into Admin connection URL (used once, not stored), for example postgres://log_admin:CHOOSE_A_LONG_PASSWORD@logs.internal.example:5432/app_logs, and press Bootstrap log database.
The panel creates a dedicated codedocs_logs role with a generated password, builds the partitioned change-log table, hands ownership to that role, and saves the new connection URL (not the one you pasted) in the main database. You may drop the bootstrap role afterwards. Check: Status reads Configured, and Test Connection succeeds. Failure with permission denied to create role means the pasted role lacks CREATEROLE: you must paste an administrator URL, not the URL of a runtime role. Clear switches back to the main database. Change-log rows already written to the log database are not moved back.
Data Providers
FX rate providers are the exchange-rate sources that projects can import from: European Central Bank (ECB), Open Exchange Rates, CurrencyFreaks, Custom endpoint, and Central Bank of Russia. Each has a switch; turning one off hides it from the picker and refuses scheduled imports that still use it. The Central Bank of Russia source is off by default. CurrencyFreaks API Key is needed for the CurrencyFreaks source. Open Exchange Rates needs an App ID that each project enters. Check: the source appears in a project's FX rates settings. The servers need outbound HTTPS to the chosen source.
Billing
Setting | Notes |
|---|---|
Stripe billing (platform subscriptions) | Billing secret key (optional; the storefront payments key is used if empty) and Billing webhook signing secret. Buttons: Sync plans to Stripe, Configure customer portal. The page shows the webhook address to register in Stripe. |
Subscription plans | The plans, their prices and their limits: projects, documents, records, seats, viewers, external users, AI credits, automation runs, storage, and whether backups are included. |
A self-hosted installation does not need Stripe billing: the Self-hosted plan has no limits and is not for sale. Set up billing only if you sell plans to your own users. Without plans or Stripe, the plans page of a user shows no Available plans, and the upgrade button is missing. To put one account on a plan by hand without charging, use System, Billing.
AI Usage
A read-only log of AI calls, tokens and credits by role over the last 30 days. Use it to see which role consumes the most. The Self-hosted plan has no AI credit limit; a plan you define yourself can have one.
Security
Setting | Notes and check |
|---|---|
Blocked email domains | Disposable-mail domains refused at team sign-up and portal login. A built-in list updates with each release. Also block these adds domains; Allow these anyway lets a built-in domain through. One domain per line; subdomains are included. A refused customer sees Disposable or temporary email addresses are not allowed. Please use a permanent email address. Check: sign up with an address on an allowed domain. |
Cloudflare Turnstile | The CAPTCHA for sign-in, sign-up, public forms and public booking. Fields: TURNSTILE_SITE_KEY (public) and TURNSTILE_SECRET. Leave both blank to turn it off everywhere. If the keys are missing, a form that has Require Cloudflare Turnstile ticked accepts submissions without a CAPTCHA. The badge reads Configured when both keys are saved. |
Stripe payments | The platform's Stripe Connect keys: Secret key and Webhook signing secret. Leave blank to disable card payments in shops. Register |
Login with Google | A switch, plus Google OAuth Client ID and Google OAuth Client Secret from a Google Cloud Web application. Register the Authorized redirect URI shown on the page: |
Login with Apple | A switch, plus Apple Services ID, Apple Team ID, Apple Key ID and Apple Private Key (.p8). Register the Return URL shown: |
New users who sign in through Google or Apple are created already verified. An existing password account with the same verified email is linked automatically.
The Security tab also has a Builder panel for platform administrators with Manage Projects; it is not needed for a normal installation.
Public registration is open. There is no setting in Config that closes it; limit who can reach the site at the network level if that is a requirement. Registration refuses blocked domains and uses Turnstile when it is configured.
Deployments
For publishing shops and booking sites to their own host.
Setting | Notes |
|---|---|
Vercel credentials | API token and Team id. Needed to attach custom domains to storefronts hosted on Vercel. Press Test. Without it, a project shows Connect Vercel (System → Config → Deployments) to attach custom domains. |
Storefront templates | One row per storefront deployment: Template id, Label, Type, Vercel project id (blank for a self-hosted deployment), Default host suffix, DNS target (A record) (the address customers point custom domains at), Git branch, Deploy hook URL, Revalidate secret. With no template, Publish to web shows No storefront templates are configured. |
The storefront application itself is a separate deployment and is not part of this installation. The sub-domain and custom-domain notes in apply.
Observability and Analytics
Observability configures OpenTelemetry (traces, metrics and logs to a collector, and a Prometheus endpoint). It is off by default. See .
Analytics loads Google Analytics on the register, login, projects and billing pages only. It never loads inside a project, a document or the customer portal. Fields: Enable Google Analytics, the measurement ID (G-XXXXXXXXXX), and Ask for consent in the EEA, UK and Switzerland. It is off by default.
Other System pages
Page | What it does |
|---|---|
Connectors | Security model for installing connector packages: Signed only (safest), Trusted URLs (only from allow-listed prefixes), or Any (dev) (no verification; do not use in production), with an option to require both a signature and an allow-listed URL. Install a connector from a URL or a |
Users | Accounts, System Permissions, Block User, Reset Password |
Billing | Every billing account, its plan, seats, usage and payment state, and a manual plan change |
Jobs | Background work and its history (imports, AI jobs) |
Health | Whether each background scheduler is running. Stale or Failing means that job is not doing its work |
Traces, Client errors, Index advisor |