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

.env next to docker-compose.yml

You, on the server

After docker compose up -d recreates the container

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

PUBLIC_APP_URL

http://localhost:3000

The address people open in the browser, with no trailing slash. Cookies, emailed links and sign-in callbacks are built from it. ./install.sh --url and --domain set it. Once Public App URL is saved in Config, Config wins.

APP_PORT

3000

Host port for the app's plain HTTP.

APP_BIND

0.0.0.0

Interface the app port listens on. --domain sets 127.0.0.1, so only the HTTPS proxy reaches it. Set it yourself when you use your own proxy.

DOMAIN, COMPOSE_PROFILES

empty

Set together by --domain; COMPOSE_PROFILES=tls starts the bundled Caddy. Leave empty for plain HTTP.

AUTH_SECRET

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 AUTH_SECRET error. Changing it signs everybody out and invalidates sign-in links in flight. Keep it stable.

CONNECTOR_ENCRYPTION_KEY

generated

Master key (base64, 32 bytes) for saved connector credentials. Losing it makes them unreadable. Back it up with .env.

ADMIN_INITIAL_PASSWORD

generated

Password of the admin user at creation, and at repair. If it is empty, the account gets a well-known default, so never blank it.

POSTGRES_PASSWORD

generated

Password of the bundled database.

DEFAULT_PLAN_CODE

self_hosted

The plan new accounts start on. self_hosted has no plan limits and has backups on. Without it a new account lands on Free (2 projects, 20 documents per project, 1,000 rows per table, one editing seat). Only new accounts read it; move existing accounts in Billing. A code that names no plan is ignored with a warning in the log.

CODEDOCS_IMAGE

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

SMTP_HOST, SMTP_PORT (587), SMTP_USER, SMTP_PASSWORD

Outgoing email. Used until you save the Email tab.

AI_PROVIDER (openrouter or zai), OPENROUTER_API_KEY, OPENROUTER_MODEL, ZAI_API_KEY, ZAI_MODEL

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

Variable

Default

What it does

HEALTH_TOKEN

unset

Requires a shared secret on /api/health (header X-Health-Token or Authorization: Bearer). Unset means the health reply is open. See the caution below.

SCHEDULERS

all

Which background schedulers this process runs: all, none, or a comma list of scheduler ids. Use it to keep background work off a web-only process (see ). A wrong id stops the start and the error lists the valid ones.

NEXT_MANUAL_SIG_HANDLE

unset

Set to true so the app can finish its shutdown (save live documents, release jobs) within 12 seconds when stopped. Recommended; see below.

CONNECTOR_ALLOW_PRIVATE_HOSTS

off

true lets connectors reach private, loopback and link-local addresses, for example a database on your internal network. Off by default so connectors cannot be pointed at your internal services.

CONNECTOR_HOST_ALLOWLIST

empty

Comma-separated host names or CIDR ranges that connectors may always reach.

VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT

generated at first start

Web Push keys for browser notifications. Set them only to pin one key pair across servers. Changing them makes every user re-subscribe.

PG_POOL_MAX

20

Size of the database connection pool of one app process. Keep it below the server's max_connections.

PG_CONNECT_TIMEOUT_S

10

Seconds allowed to open a database connection.

PG_IDLE_IN_TXN_TIMEOUT_MS

60000

The database ends a session left idle inside a transaction after this long, so a leaked transaction cannot hold a connection forever.

WATCHDOG_ENABLED

true

The stall detector writes a stack dump to the traces volume when the event loop is blocked for WATCHDOG_THRESHOLD_MS (default 5000). [Watchdog] Disabled in the log means its native module did not load; the app still runs.

CLIENT_ERROR_RETENTION_DAYS

30

How long browser error reports are kept (minimum 1). AGENT_TOOL_ERROR_RETENTION_DAYS does the same for agent tool errors.

FTS_LANGUAGE

english

Language of keyword search: english or russian.

EMBEDDING_PROVIDERS_JSON

unset

A JSON list of presets that appear in the Provider list of Embedding Model.

TURNSTILE_SITE_KEY, TURNSTILE_SECRET

unset

Starting values for Cloudflare Turnstile. Use the Security tab.

NODE_ID

unknown

A name for this server. It appears in the health reply and in database connection names. Set it per server in a multi-server setup.

SKIP_MIGRATIONS

0

Set to 1 in the container to start without applying migrations: for a second app replica, or when you migrate separately.

Careful: HEALTH_TOKEN and the bundled image. The image's Docker health check and install.sh call /api/health without a token. If you set HEALTH_TOKEN, the app answers 401 to them: the container is reported unhealthy, and a later ./install.sh waits six minutes and reports a failure although the app runs. Leave the token unset, or restrict /api/health at 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 PUBLIC_APP_URL

The public address, no trailing slash, https:// in production. It builds every emailed link (sign-in, invitations, verification, digests), the OAuth redirect addresses and the MCP server's issuer address. Check: open any redirect address shown on the Security tab; if the page asks you to set the URL first, it is empty. Emailed links must open your site, not localhost.

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

./git_cache

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

10

The most background jobs that run at the same time.

Embed File Max Size (MB)

100

The largest file a user can attach to a document. Your reverse proxy must allow uploads at least this large (client_max_body_size in nginx).

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 EMBEDDING_PROVIDERS_JSON, or Custom

Endpoint URL

Default https://openrouter.ai/api/v1/embeddings

Model

Default openai/text-embedding-3-small

API Key

Optional; leave empty for an endpoint without authentication

Vector Size

Default 1536; it must match what the model returns

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

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).

1.

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.

2.

Set Public App URL. The page then shows the webhook address to register: <Public App URL>/api/webhooks/inbound/resend.

3.

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 public/uploads/ folder. In the bundle this is the uploads Docker volume (codedocs_uploads), on this server's disk.

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:

1.

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;
2.

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 <Public App URL>/api/webhooks/inbound/stripe as the webhook; the page shows it. Without keys, a shop's payment connector shows Stripe isn't configured on this platform.

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: <Public App URL>/api/auth/oauth/google/callback. The Continue with Google button appears on the login and register pages only when the switch is on and the credentials are filled in.

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: <Public App URL>/api/auth/oauth/apple/callback. Apple works only over HTTPS.

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 .zip upload. Installed connectors lists packages and deletes them (connectors that use a deleted package stop working). OAuth apps: for connectors that sign in to an outside account such as a CRM or a drive, register one app per provider and use the Redirect URI shown (copy it exactly; providers need HTTPS and an exact match). If it shows localhost, set Public App URL. Needs Manage Projects.

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

Diagnostics. See

•

•

•

•