English
Environment variables
A Mankomail instance is configured entirely through environment variables, read once when the process starts. This page lists every variable the application reads, grouped by topic, then the variables that only the reference Docker Compose file, the image build and the backup scripts use.
To change a value, edit it and restart the application. For installation steps, see Self-hosting; for how configuration fits into day-to-day operations, see Configuration.
How the application reads its configuration
These rules apply to every variable on this page that the application reads (all sections except the last two).
- No variable is strictly required by the application. Each one has a default or is optional, and the process never refuses to start because of a configuration value. A real installation still needs at least
DATABASE_URL,ENCRYPTION_KEY,PUBLIC_BASE_URLand the object storage variables; the reference Compose file refuses to start without them (see Variables of the reference Compose file). - An invalid value falls back to the default. The process logs a warning such as
configuration: invalid value, falling back to the default (…)with the variable name, then carries on with the default. For an optional variable without a default, the warning isconfiguration: invalid value, ignoredand the variable is treated as absent. Read the boot logs after any change. - An empty value counts as absent.
PUBLIC_BASE_URL=behaves exactly like a missingPUBLIC_BASE_URL. - Every variable has a
<NAME>_FILEform.ENCRYPTION_KEY_FILE=/run/secrets/encryption_keyreads the value from that file (surrounding whitespace removed), which suits Docker and Kubernetes secrets. When both forms are set, the file wins. An unreadable or empty file produces a warning, and the plain variable is used instead, if set. - Booleans accept
true,false,1,0,yesandno, in any case. - Bounds are inclusive. A number outside the documented range is invalid, and therefore replaced by the default.
The one exception to "never stops the boot" is DATABASE_SSL_CA: see Database.
Runtime and HTTP
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
NODE_ENV | development | development, test, production | Production mode. It turns on COOKIE_SECURE by default and the Strict-Transport-Security header. The Docker image sets it to production. |
APP_ROLE | all | all, api, worker | What this process runs. all: HTTP API, web interface and background work. api: HTTP only, no background work. worker: background work; the process still listens on its HTTP port. |
APP_VERSION | 0.0.0 | Non-empty text | Version returned by /healthz and attached to every log line. The Docker image sets it from the APP_VERSION build argument. |
HOST | 0.0.0.0 | Non-empty text | Interface the HTTP server listens on. |
PORT | 3000 | Integer from 1 to 65535 | Port the HTTP server listens on. |
PUBLIC_BASE_URL | http://localhost:3000 | Absolute URL | The address your users reach. See the warning below. |
UI_DIST_DIR | public | Path, or empty | Directory of the web interface files. If it is empty or does not exist, the process serves the API only. |
COOKIE_SECURE | true when NODE_ENV=production, false otherwise | Boolean | Whether the session cookie carries the Secure attribute. |
TRUST_PROXY | true | Boolean, number of hops, or addresses / CIDR ranges separated by commas | Which X-Forwarded-* headers the application believes. |
PUBLIC_BASE_URL
If PUBLIC_BASE_URL is absent, empty or invalid, the instance starts with http://localhost:3000, without an error. Everything built from it is then wrong for your users:
- the OAuth redirect URIs,
<PUBLIC_BASE_URL>/api/v1/oauth/<provider>/callback, so connecting a Google or Microsoft mailbox fails at the provider; - the invitation links that administrators copy for new members, and the links in approval emails;
- the Microsoft Graph push notification URL,
<PUBLIC_BASE_URL>/hooks/push/msgraph, whenMSGRAPH_NOTIFICATION_URLis not set.
When the variable is not set, two more things change: the Content Security Policy keeps a broad connect-src instead of being restricted to your own origin, and no site URL is announced to AI providers that accept one. Set it to the exact public URL, scheme, host and port included, without a trailing /.
COOKIE_SECURE
With COOKIE_SECURE=true, a sign-in request that does not arrive over HTTPS is refused with the error auth.https_required, because the browser would silently drop the cookie. HTTPS terminated by a reverse proxy counts, through the X-Forwarded-Proto header. COOKIE_SECURE=false sends the session cookie in clear text: use it only on a machine or network you control.
TRUST_PROXY
Keep true behind a reverse proxy: without it, every request appears to come from the proxy, so the sign-in rate limit applies to all users at once and HTTPS termination is invisible. Set false if the application port is exposed directly; otherwise a client can forge X-Forwarded-For and bypass the sign-in rate limit. 1 and 0 are read as booleans, not as a number of hops: write 2 or more for a hop count. The resolved value is logged at boot (proxy trust policy resolved).
Branding
The brand of a self-hosted instance. Every variable except BRAND_NAME is optional: left empty, the product default applies (monogram, theme palette). On an instance linked to a control plane, the brand it sends takes precedence field by field. See White label.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
BRAND_NAME | Mankomail | Non-empty text | Name shown in the interface (sidebar, sign-in page, tab title), in emails sent by the instance (approval requests) and on the invitation page; announced to IMAP servers and AI providers. |
BRAND_LOGO_URL | none | Absolute URL (https recommended) | Logo shown in the sidebar and on the sign-in page, in place of the monogram. A logo carries the name: the name text next to it is hidden. |
BRAND_LOGO_DARK_URL | none | Absolute URL | Logo for the dark mode. Without it, BRAND_LOGO_URL is used in both modes. |
BRAND_FAVICON_URL | none | Absolute URL | Browser tab icon. Without it, the monogram is drawn in the primary color. |
BRAND_PRIMARY_COLOR | none | #RRGGBB | Becomes the theme accent (buttons, active navigation item, links, focus ring). Its lightness is recomputed for each theme, in light and dark mode, so that text stays readable (4.5:1). |
BRAND_ACCENT_COLOR | none | #RRGGBB | Secondary brand color (sign-in page panel). |
BRAND_SUPPORT_URL | none | Absolute URL | “Help” link on the sign-in page and in the member menu. |
BRAND_HIDE_POWERED_BY | false | true, false | Hides the “Powered by Mankomail” line shown on the sign-in page and in system emails when the brand name differs from the product name. |
Images are loaded by browsers: the page's content security policy allows https: images, plus the exact origin of an http: URL given here.
Control plane
Set the three variables together, or none. Without them (self-hosting), the instance calls nothing and sends nothing anywhere. With them, it sends a signed heartbeat every minute, reports its usage every five minutes, and reads its configuration (brand, plan, entitlements). If only one or two are set, the link stays off and the boot log says which one is missing. See White label.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
CONTROL_PLANE_URL | none | Absolute URL, http or https | Base of the calls, for example https://api.example.com/api/instances/v1. A trailing slash is removed. |
CONTROL_PLANE_INSTANCE_ID | none | Text (ins_…) | Public identifier of the instance. |
CONTROL_PLANE_SECRET | none | Text | Shared HMAC secret. Treat it as a password; CONTROL_PLANE_SECRET_FILE is accepted. |
Logs
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
LOG_LEVEL | info | fatal, error, warn, info, debug, trace, silent | Minimum level written to standard output. |
LOG_FORMAT | json | json, pretty | Shape of each log line. json for production; pretty for a development terminal. |
With json, logs are JSON lines on standard output, with level, an ISO timestamp, role and version on every line: the format log tools such as jq or Loki read. With pretty, each line reads 10:04:12.345 INFO [mirror] message key=value, coloured in a terminal, with an error's stack trace indented below it; role and version are left out. In both formats, secrets such as the encryption key are redacted before the line is written. See Monitoring.
Database
PostgreSQL is the only mandatory dependency: it holds all the state of the instance, including the job queue.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
DATABASE_URL | postgres://postgres:postgres@localhost:5432/postgres | Non-empty connection string | The PostgreSQL connection. |
DATABASE_POOL_MAX | 10 | Positive integer | Maximum number of connections per process. |
DATABASE_SSL | disable | disable, no-verify, verify; also true/1/yes (= no-verify) and false/0/no (= disable) | TLS mode of the connection. |
DATABASE_SSL_CA | none | Path to a PEM file | Certificate authority used by verify, for a private authority. Without it, the system authorities are used. |
DATABASE_RUN_MIGRATIONS | true | Boolean | Apply pending migrations at boot. With false, the process logs a warning and starts without migrating. |
DATABASE_STATEMENT_TIMEOUT_MS | 30000 | Integer from 0 to 86400000 | Maximum duration of a query, in milliseconds. 0 sends no limit, so the server or role setting applies. |
DATABASE_SSLmodes.disableis right when the database is reached over a private network, as in the reference Compose file.no-verifyencrypts the connection without authenticating the server: it protects against passive eavesdropping only.verifychecks the server certificate chain, and is the mode to use as soon as the database is remote.DATABASE_SSL_CAstops the boot if the file is unreadable. This is the only configuration value that does: withDATABASE_SSL=verifyand an unreadable file, the process stops withDATABASE_SSL_CA: unreadable PEM file. It is ignored in the other modes.- Migrations run under a PostgreSQL advisory lock: several processes can start together, only one migrates. They are never affected by
DATABASE_STATEMENT_TIMEOUT_MS. - The statement timeout applies to the connection pool only. A query that exceeds it is cancelled by PostgreSQL and the request returns an error, instead of holding a connection.
- At boot, the process waits up to 60 seconds for the database to accept connections. A wrong password, an unknown role or a missing database stop it immediately.
Object storage
Email bodies, attachments and files added to runs are stored in an S3-compatible object storage (s3) or in a local directory (fs).
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
STORAGE_DRIVER | s3 | s3, fs | Storage backend: an S3-compatible bucket, or a directory on the server's disk. |
STORAGE_ENDPOINT | none | Absolute URL | Endpoint of the S3-compatible service. Without it, the default AWS endpoint for the region is used. |
STORAGE_REGION | us-east-1 | Non-empty text | Bucket region. |
STORAGE_BUCKET | product | Non-empty text | Bucket name. The application does not create it. |
STORAGE_ACCESS_KEY_ID | none | Non-empty text | Access key. |
STORAGE_SECRET_ACCESS_KEY | none | Non-empty text | Secret key. |
STORAGE_FORCE_PATH_STYLE | true | Boolean | Path-style addressing (endpoint/bucket/key), needed by MinIO and most S3-compatible services. |
STORAGE_FS_ROOT | ./.data/blobs | Non-empty path | Directory of the fs driver, relative to the working directory (/app in the Docker image). Ignored with s3. |
The STORAGE_ENDPOINT to STORAGE_FORCE_PATH_STYLE variables apply to s3 only. Use one bucket per instance: object keys are not prefixed.
STORAGE_DRIVER=fs
The fs driver suits a single-server installation without MinIO. It gives the same guarantees as s3: each file is written to a temporary file then renamed, so a crash never leaves a half-written email; keys cannot escape the directory; deleting a mailbox removes its files. The process logs blob storage is a local directory at boot.
- Put
STORAGE_FS_ROOTon a persistent volume: in a container, a directory outside a volume disappears with the container, and every email body with it. - Every process of the instance must see the same directory. With several servers, use
s3. - The backup scripts copy the MinIO bucket of the reference Compose file, not this directory: include
STORAGE_FS_ROOTin your own backups.
Encryption key and first administrator
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
ENCRYPTION_KEY | none | 32 bytes: 64 hexadecimal characters, or base64 | Instance key (AES-256-GCM) that encrypts stored secrets: mailbox OAuth tokens, IMAP passwords, AI provider keys, other connections. |
BOOTSTRAP_ADMIN_EMAIL | none | Email address (stored in lower case) | Email of the first administrator. |
BOOTSTRAP_ADMIN_PASSWORD | none | At least 12 characters | Password of the first administrator. |
ENCRYPTION_KEY
Generate it with openssl rand -hex 32 or openssl rand -base64 32. It is never generated automatically.
- Absent or invalid: the instance starts, logs
ENCRYPTION_KEY is not setorENCRYPTION_KEY is invalid, and secret storage is disabled: no mailbox, AI provider or connection secret can be saved. - Lost or changed: every stored secret becomes unreadable, and every mailbox has to be reconnected. Keep a copy outside the server. Backups do not contain it.
The first administrator is created at boot only if the instance has no member yet, and only if both variables are set. A password shorter than 12 characters is refused with a warning, and no account is created. Once a member exists, the two variables have no effect: they cannot reset a password or add an account.
Mailbox synchronisation
These variables govern the mirror, the local copy of each connected mailbox. See Mailboxes and the mirror.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
BACKFILL_MONTHS | 12 | Integer from 1 to 240 | Depth of history copied when a mailbox is connected, in months. |
BACKFILL_CHUNK_DAYS | 30 | Integer from 1 to 365 | Width of one slice of that initial copy, in days. An interrupted copy resumes from the last completed slice. |
POLL_INTERVAL_SECONDS | 300 | Integer from 30 to 86400 | Interval of the periodic check of each mailbox. Push notifications speed synchronisation up; polling guarantees it. |
WORKER_CONCURRENCY | 4 | Integer from 1 to 64 | Background jobs processed at the same time by this process. Keep it below DATABASE_POOL_MAX. |
PUSH_SHARED_SECRET | none | At least 16 characters | Secret expected in the token query parameter of the push endpoints /hooks/push/gmail and /hooks/push/msgraph. |
GMAIL_PUBSUB_TOPIC | none | Non-empty text, projects/<project>/topics/<topic> | Google Cloud Pub/Sub topic used for Gmail push notifications. |
MSGRAPH_NOTIFICATION_URL | derived | Absolute URL | URL Microsoft Graph calls for notifications. |
- Without
PUSH_SHARED_SECRET, both push endpoints answer404to every call, and synchronisation relies on polling alone. That is a valid set-up. - Without
GMAIL_PUBSUB_TOPIC, Gmail mailboxes are not registered for push notifications; polling is used. MSGRAPH_NOTIFICATION_URLis derived fromPUBLIC_BASE_URLandPUSH_SHARED_SECRET(<PUBLIC_BASE_URL>/hooks/push/msgraph?token=…). Set it only if Microsoft must reach the instance through a different public address. WithoutPUSH_SHARED_SECRETthere is no Microsoft push at all.
Sending
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
SEND_ENABLED | true | Boolean | Instance-wide kill switch. false stops every real send; drafts are not blocked. |
SEND_MAX_PER_HOUR | 100 | Integer from 1 to 10000 | Sends per hour and per mailbox, used until an administrator sets the organisation's own rate. |
SEND_MAX_BYTES | 26214400 (25 MB) | Integer from 10000 to 67108864 | Maximum size of a composed message, encoded attachments included. |
SEND_ENABLED=falsecannot be reopened from the interface. The organisation's own switch, in Administration › Sending, can only restrict further. While sending is stopped, held sends are kept, not lost, and leave when sending reopens. Drafts are not blocked: saving a draft sends nothing. SetSEND_ENABLED=falseon any copy of a production instance, such as a restored backup, before starting it: otherwise the copy sends real emails.SEND_MAX_PER_HOURis the default of the rate set in Administration › Sending. It is counted per sending mailbox, for every send: webmail, workflow runs and approval requests. A send over the limit is postponed until the mailbox has budget again (workflows, approvals) or refused withwebmail.rate_limitedand the delay to wait (webmail); it is never lost.SEND_MAX_BYTESis also enforced when an attachment is uploaded in the webmail: a file that alone would exceed it is refused right away.
AI models
AI provider keys are not environment variables: an administrator enters them in Connections, and they are stored encrypted with ENCRYPTION_KEY.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
LLM_REQUEST_TIMEOUT_MS | 120000 | Integer from 5000 to 600000 | Time limit of one model call, in milliseconds. |
LLM_MAX_REQUESTS_PER_MINUTE | 60 | Integer from 1 to 10000 | Calls per minute and per provider, shared by every process of the instance. A call over the limit is postponed, not failed. |
LLM_DEFAULT_MAX_OUTPUT_TOKENS | 4096 | Integer from 16 to 128000 | Output token limit of a call that does not set its own. |
A slow local model (for example Ollama on CPU) may need a longer LLM_REQUEST_TIMEOUT_MS. Set LLM_MAX_REQUESTS_PER_MINUTE according to the rate allowed by your own provider account.
Mailbox analyzer
Thresholds of the analyzer, which studies a mailbox and proposes automations.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
ANALYZER_TARGET_MESSAGES | 150 | Integer from 10 to 100000 | The analysis uses the shortest window among 30, 90, 180 and 365 days that holds at least this many received emails; otherwise 365 days. |
ANALYZER_MIN_GROUP_VOLUME | 3 | Integer from 2 to 1000 | Minimum size of a group of similar emails. |
ANALYZER_MIN_GROUP_SHARE | 0.02 | Number from 0 to 0.5 | Proportional threshold. A group must reach the larger of ANALYZER_MIN_GROUP_VOLUME and this share of the window's emails, rounded up. |
ANALYZER_MAX_CLUSTERS | 12 | Integer from 1 to 30 | Groups submitted to the model per analysis. |
ANALYZER_LLM_BATCH_SIZE | 1 | Integer from 1 to 10 | Groups per model call. 1 (one call per group) is the most reliable. |
ANALYZER_LLM_CONCURRENCY | 3 | Integer from 1 to 10 | Model calls running at the same time for one analysis. |
ANALYZER_SAMPLE_SIZE | 5 | Integer from 1 to 20 | Subjects and previews sampled per group. Email bodies are never sent. |
ANALYZER_MAX_OPPORTUNITIES | 6 | Integer from 1 to 20 | Proposals kept per report. |
ANALYZER_MAX_OUTPUT_TOKENS | 16000 | Integer from 1000 to 128000 | Output token limit of each call. |
ANALYZER_SUGGESTION_WINDOW_DAYS | 30 | Integer from 1 to 365 | Window of the scan for emails no workflow handles, in days. |
ANALYZER_SUGGESTION_MIN_VOLUME | 15 | Integer from 1 to 10000 | Unhandled emails from one domain, within that window, before a suggestion is made. |
Approvals and waits
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
APPROVAL_REMINDER_FRACTION | 0.5 | Number from 0 to 0.9 | When a pending approval gets its reminder, as a fraction of its time limit. 0.5 = halfway; 0 disables reminders. |
WAIT_MAX_DAYS | 730 | Integer from 1 to 3650 | Longest wait a workflow can request, in days. |
SIGNAL_RETENTION_HOURS | 24 | Integer from 1 to 720 | How long a signal stays valid for a wait that is not in place yet, in hours. |
The time limit of an approval is set in each workflow, on the approval node; the reminder fraction adapts to it. See Review and approvals.
Assistant
Limits of one conversation with the assistant that builds and fixes workflows. The provider and model are chosen in Connections.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
ASSISTANT_MAX_TURNS | 16 | Integer from 1 to 60 | Model calls at most for one message of the member. |
ASSISTANT_MAX_TOKENS_PER_CONVERSATION | 2000000 | Integer from 10000 to 50000000 | Tokens (input and output) at most for a whole conversation. |
ASSISTANT_MAX_TOOL_RESULT_CHARS | 30000 | Integer from 2000 to 200000 | Characters at most of one tool result given back to the model. |
ASSISTANT_MAX_OUTPUT_TOKENS | 6000 | Integer from 512 to 64000 | Output token limit of one call. |
Loops
Instance limits for loop nodes. A loop node's own settings apply on top and can only be stricter.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
LOOP_MAX_ITERATIONS | 500 | Integer from 1 to 500 | Most iterations a loop may run. A loop over more items fails: it never processes part of the list silently. |
LOOP_MIN_ITERATIONS | 10 | Integer from 1 to 500 | Floor of the previous limit: the effective limit is the larger of the two values, so the instance cannot make loops unusable by mistake. |
LOOP_MAX_CONCURRENCY | 5 | Integer from 1 to 5 | Iterations run in parallel, whatever the node asks. |
LOOP_SIMULATED_MAX_ITERATIONS | 3 | Integer from 1 to 50 | Iterations started by a test run in the editor. The result of the test run says it was cut short. |
LOOP_MAX_COLLECTED_BYTES | 262144 (256 KB) | Integer from 4096 to 8388608 | Size budget of the results gathered when a loop finishes. Beyond it, per-iteration data is left out and the result is marked truncated. |
Integrations and run files
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
INTEGRATION_POLL_MIN_MINUTES | 5 | Integer from 1 to 1440 | Shortest interval of a trigger that polls a third-party service, in minutes. A node can ask for a longer interval, never a shorter one. |
EXECUTION_ATTACHMENT_MAX_BYTES | 26214400 (25 MB) | Integer from 1024 to 67108864 | Maximum size of one file a node adds to a run. |
EXECUTION_ATTACHMENTS_MAX_TOTAL_BYTES | 104857600 (100 MB) | Integer from 1024 to 536870912 | Total size of the files added to one run. |
EXECUTION_ATTACHMENTS_MAX_COUNT | 20 | Integer from 1 to 500 | Number of files added to one run. |
Files added to a run are kept as long as the run itself.
Tables
Limits of Tables. Each one has an absolute maximum that no configuration can exceed.
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
TABLES_MAX_TABLES | 100 | Integer from 1 to 1000 | Tables the organisation can create. |
TABLES_MAX_COLUMNS | 60 | Integer from 1 to 200 | Columns per table. |
TABLES_MAX_ROWS | 50000 | Integer from 1 to 500000 | Rows per table. |
TABLES_MAX_CELL_CHARS | 4000 | Integer from 1 to 20000 | Characters per cell. |
TABLES_OP_RETENTION_DAYS | 30 | Integer from 1 to 365 | Days the record of each table write made by a node is kept. This record lets a retried step recognise a write it already made, so a retry never adds a second row or comment. The hourly maintenance job deletes older records; table rows are never affected. |
Retention
| Variable | Default | Accepted values | Effect |
|---|---|---|---|
SIMULATED_EXECUTIONS_RETENTION_DAYS | 7 | Integer from 1 to 365 | Days test runs from the editor are kept, with their steps. |
AUDIT_LOG_RETENTION_DAYS | 365 | Integer from 30 to 3650 | Days entries of the audit log are kept. |
SCHEDULED_TASKS_RETENTION_DAYS | 7 | Integer from 1 to 90 | Days the trace of completed or abandoned scheduled tasks (polls, renewals, maintenance) is kept. |
The other retention periods are fixed in the current version and applied by an hourly maintenance job:
| Data | Kept for |
|---|---|
| Live runs | 180 days |
| Outbound operations (sends, moves, flags) | 180 days |
| Ingestion journal | 365 days |
| AI usage accounting | 365 days |
| Jobs that exhausted their attempts | 30 days |
Telemetry
The instance sends no telemetry, and no variable configures it.
Variables of the reference Compose file
The reference Compose file, compose.reference.yaml, reads these variables from .env for its own use. The application never reads them directly.
| Variable | Default | Use |
|---|---|---|
POSTGRES_PASSWORD | required | Password of the PostgreSQL database, also used to build DATABASE_URL. It is fixed when the database volume is first created: changing it afterwards in .env does not change it in PostgreSQL. |
POSTGRES_USER | Set in the Compose file | PostgreSQL user. |
POSTGRES_DB | Set in the Compose file | PostgreSQL database name. |
STORAGE_ACCESS_KEY_ID | required | Also the MinIO root user. |
STORAGE_SECRET_ACCESS_KEY | required | Also the MinIO root password. |
ENCRYPTION_KEY | required | Passed to the application. |
PUBLIC_BASE_URL | required | Passed to the application. |
STORAGE_BUCKET | Set in the Compose file | Bucket created by the one-off createbucket job and used by the application. |
COMPOSE_PROJECT_NAME | Set in the Compose file | Prefix of containers and volumes. Change it to run two instances on one machine. |
APP_IMAGE | Set in the Compose file (a locally built image) | Application image. |
APP_BIND | 127.0.0.1 | Interface the application port is published on. 0.0.0.0 exposes plain HTTP on the network. |
APP_PORT | 3000 | Port published on the host. |
APP_CPUS, APP_MEMORY | 2, 2g | Resource limits of the application container. |
POSTGRES_IMAGE | postgres:16 | PostgreSQL image. |
POSTGRES_CPUS, POSTGRES_MEMORY, POSTGRES_SHM_SIZE | 2, 2g, 256m | Resource limits and shared memory of PostgreSQL. |
MINIO_IMAGE, MC_IMAGE | pinned MinIO release, minio/mc:latest | Images of MinIO and of the bucket job. |
MINIO_BROWSER | off | MinIO web console. |
MINIO_CPUS, MINIO_MEMORY | 1, 1g | Resource limits of MinIO. |
The Compose file refuses to start when one of the five required variables is missing. It also sets some application variables itself, whatever .env says: NODE_ENV=production, PORT=3000, STORAGE_DRIVER=s3, STORAGE_ENDPOINT=http://minio:9000, STORAGE_FORCE_PATH_STYLE=true, and DATABASE_URL built from the POSTGRES_* variables.
Only listed variables reach the application
The Compose file passes an explicit list of variables to the application container: identity, runtime, database, storage, encryption, first administrator, synchronisation, sending and two retention settings. Any other variable from this page, such as TRUST_PROXY, COOKIE_SECURE, LLM_*, ANALYZER_*, TABLES_* or LOOP_*, must be added under services.app.environment, for example in an extra Compose file, to take effect.
Image build and backup scripts
Build arguments of the Docker image:
| Argument | Default | Use |
|---|---|---|
APP_VERSION | 0.0.0-dev (0.0.0-selfhost through the reference Compose file) | Becomes the APP_VERSION variable of the image. |
GIT_SHA | unknown | Recorded as an image label and an environment variable; the application does not read it. |
NODE_IMAGE | node:24-slim | Base image. |
The image also sets NODE_ENV=production, APP_ROLE=all, HOST=0.0.0.0 and PORT=3000.
Backup and restore scripts read these variables from their own environment. They also read POSTGRES_USER, POSTGRES_DB, POSTGRES_PASSWORD, STORAGE_*, ENCRYPTION_KEY, APP_PORT and APP_VERSION from the .env file. See Backups.
| Variable | Default | Use |
|---|---|---|
COMPOSE_FILE | compose.reference.yaml at the repository root | Compose file the scripts drive. |
ENV_FILE | .env at the repository root | Environment file the scripts read. |
BACKUP_KEEP | 7 | Number of backups kept in the output directory; older ones are deleted. 0 keeps them all. |
RESTORE_YES | none | 1 skips the confirmation prompts of the restore, which otherwise ask you to type YES. |
The scripts write their messages in English.